SaslWrapper.java

/*
 * JBoss, Home of Professional Open Source
 *
 * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual
 * contributors as indicated by the @author tags.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.xnio.sasl;

import java.nio.ByteBuffer;

import javax.security.sasl.SaslClient;
import javax.security.sasl.SaslException;
import javax.security.sasl.SaslServer;

/**
 * A wrapper delegation class for SASL that presents the same wrap/unwrap API regardless of whether it is
 * dealing with a SASL client or server.
 *
 * @author <a href="mailto:david.lloyd@redhat.com">David M. Lloyd</a>
 */
public abstract class SaslWrapper {

    /**
     * Wrap a message.
     *
     * @param bytes the incoming message
     * @param off the offset into the byte array
     * @param len the length of the byte array to wrap
     * @return the wrap result
     * @throws SaslException if a problem occurs
     */
    public abstract byte[] wrap(byte[] bytes, int off, int len) throws SaslException;

    /**
     * Wrap a message.
     *
     * @param bytes the incoming message
     * @return the wrap result
     * @throws SaslException if a problem occurs
     */
    public final byte[] wrap(byte[] bytes) throws SaslException {
        return unwrap(bytes, 0, bytes.length);
    }

    /**
     * Wrap a message.
     *
     * @param source the buffer from which bytes should be read
     * @return the wrap result
     * @throws SaslException if a problem occurs
     */
    public abstract byte[] wrap(ByteBuffer source) throws SaslException;

    /**
     * Unwrap a message.
     *
     * @param bytes the incoming message
     * @param off the offset into the byte array
     * @param len the length of the byte array to wrap
     * @return the unwrap result
     * @throws SaslException if a problem occurs
     */
    public abstract byte[] unwrap(byte[] bytes, int off, int len) throws SaslException;

    /**
     * Unwrap a message.
     *
     * @param bytes the incoming message
     * @return the unwrap result
     * @throws SaslException if a problem occurs
     */
    public final byte[] unwrap(byte[] bytes) throws SaslException {
        return unwrap(bytes, 0, bytes.length);
    }

    /**
     * Unwrap a message.
     *
     * @param source the buffer from which bytes should be read
     * @return the unwrap result
     * @throws SaslException if a problem occurs
     */
    public abstract byte[] unwrap(ByteBuffer source) throws SaslException;

    /**
     * Wrap a message.  Wrapping occurs from the source buffer to the destination idea.
     * <p/>
     * The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL message
     * (without the length field).  The SASL message itself does not encode any length information so it is up to the
     * protocol implementer to ensure that the message is properly framed.
     *
     * @param destination the buffer into which bytes should be written
     * @param source the buffers from which bytes should be read
     *
     * @throws SaslException if a SASL error occurs
     * @see SaslClient#wrap(byte[], int, int)
     * @see SaslServer#wrap(byte[], int, int)
     */
    public final void wrap(ByteBuffer destination, ByteBuffer source) throws SaslException {
        destination.put(wrap(source));
    }

    /**
     * Unwrap a message.  Unwrapping occurs from the source buffer to the destination idea.
     * <p>
     * The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL
     * message (without the length field).  The SASL message itself does not encode any length information so it is up
     * to the protocol implementer to ensure that the message is properly framed.
     *
     * @param destination the buffer into which bytes should be written
     * @param source the buffers from which bytes should be read
     * @throws SaslException if a SASL error occurs
     * @see SaslClient#unwrap(byte[], int, int)
     */
    public final void unwrap(ByteBuffer destination, ByteBuffer source) throws SaslException {
        destination.put(wrap(source));
    }

    /**
     * Create a SASL wrapper for a SASL client.
     *
     * @param saslClient the SASL client
     * @return the wrapper
     */
    public static SaslWrapper create(SaslClient saslClient) {
        return new SaslClientWrapper(saslClient);
    }

    /**
     * Create a SASL wrapper for a SASL server.
     *
     * @param saslServer the SASL server
     * @return the wrapper
     */
    public static SaslWrapper create(SaslServer saslServer) {
        return new SaslServerWrapper(saslServer);
    }
}

final class SaslClientWrapper extends SaslWrapper {
    private final SaslClient saslClient;

    SaslClientWrapper(final SaslClient saslClient) {
        this.saslClient = saslClient;
    }

    public byte[] wrap(final byte[] bytes, final int off, final int len) throws SaslException {
        return saslClient.wrap(bytes, off, len);
    }

    public byte[] unwrap(final byte[] bytes, final int off, final int len) throws SaslException {
        return saslClient.unwrap(bytes, off, len);
    }

    public byte[] wrap(final ByteBuffer source) throws SaslException {
        return SaslUtils.wrap(saslClient, source);
    }

    public byte[] unwrap(final ByteBuffer source) throws SaslException {
        return SaslUtils.unwrap(saslClient, source);
    }
}

final class SaslServerWrapper extends SaslWrapper {
    private final SaslServer saslServer;

    SaslServerWrapper(final SaslServer saslServer) {
        this.saslServer = saslServer;
    }

    public byte[] wrap(final byte[] bytes, final int off, final int len) throws SaslException {
        return saslServer.wrap(bytes, off, len);
    }

    public byte[] unwrap(final byte[] bytes, final int off, final int len) throws SaslException {
        return saslServer.unwrap(bytes, off, len);
    }

    public byte[] wrap(final ByteBuffer source) throws SaslException {
        return SaslUtils.wrap(saslServer, source);
    }

    public byte[] unwrap(final ByteBuffer source) throws SaslException {
        return SaslUtils.unwrap(saslServer, source);
    }
}