Package au.net.ocean.httpclient.auth.spnego

Source Code of au.net.ocean.httpclient.auth.spnego.SPNegoAuthScheme

/*******************************************************************************
* Copyright (c) 2007, Dave Whitla
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
*  * Redistributions of source code must retain the above copyright notice,
*    this list of conditions and the following disclaimer.
*
*  * Redistributions in binary form must reproduce the above copyright notice,
*    this list of conditions and the following disclaimer in the documentation
*    and/or other materials provided with the distribution.
*
*  * Neither the name of the copyright holder nor the names of contributors
*    may be used to endorse or promote products derived from this software
*    without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
* OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/

package au.net.ocean.httpclient.auth.spnego;

import org.apache.commons.codec.binary.Base64;
import org.apache.commons.httpclient.Credentials;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.auth.AuthScheme;
import org.apache.commons.httpclient.auth.AuthenticationException;
import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
import org.apache.commons.httpclient.auth.InvalidCredentialsException;
import org.apache.commons.httpclient.auth.MalformedChallengeException;
import org.ietf.jgss.GSSContext;
import org.ietf.jgss.GSSException;

import java.util.logging.Level;
import java.util.logging.Logger;

/**
* Created by dwhitla at Apr 15, 2007 4:20:35 PM
*
* @author <a href="mailto:dave.whitla@ocean.net.au">Dave Whitla</a>
* @version $Id: SPNegoAuthScheme.java 0 Apr 15, 2007 4:20:35 PM dwhitla $
*/
public class SPNegoAuthScheme implements AuthScheme {

    public static final String IDENTIFIER = "Negotiate";

    private static final Logger LOGGER = Logger.getLogger(SPNegoAuthScheme.class.getName());
    private static final String CHALLENGE = "Negotiate";
    private static final String TOKEN_PREFIX = "Negotiate";
    private static final Base64 BASE64_CODEC = new Base64();

    private byte[] serverToken;
    private boolean complete;


    /**
     * Processes the given challenge token. Some authentication schemes
     * may involve multiple challenge-response exchanges. Such schemes must be able
     * to maintain the state information when dealing with sequential challenges
     *
     * @param challenge the challenge string
     * @since 3.0
     */
    public void processChallenge(final String challenge) throws MalformedChallengeException {
        if (challenge == null) {
            throw new MalformedChallengeException("Null challenge");
        }
        String[] tokens = challenge.trim().split("\\s+");
        if (!tokens[0].equalsIgnoreCase(CHALLENGE)) {
            LOGGER.log(Level.WARNING, "Received malformed challenge: \"{0}\"", challenge);
            throw new MalformedChallengeException(challenge);
        }
        switch (tokens.length) {
            case 1:
                LOGGER.log(Level.INFO, "Received initial \"{0}\" challenge", CHALLENGE);
                serverToken = new byte[0];
                break;
            case 2:
                LOGGER.log(Level.INFO, "Received \"{0}\" challenge with token \"{1}\"", new String[]{CHALLENGE, tokens[1]});
                serverToken = BASE64_CODEC.decode(tokens[1].getBytes());
                break;
            default:
                LOGGER.log(Level.WARNING, "Received malformed challenge: \"{0}\"", challenge);
                throw new MalformedChallengeException();
        }
    }

    /**
     * @InheritDoc
     */
    public String getSchemeName() {
        return IDENTIFIER;
    }

    /**
     * Returns authentication parameter with the given name, if available.
     *
     * @param name The name of the parameter to be returned
     * @return the parameter with the given name
     */
    public String getParameter(final String name) {
        throw new UnsupportedOperationException("Not yet implemented");
        // return null;
    }

    /**
     * Returns authentication realm. If the concept of an authentication
     * realm is not applicable to the given authentication scheme, returns
     * <code>null</code>.
     *
     * @return the authentication realm
     */
    public String getRealm() {
        return null;
    }

    /**
     * Tests if the authentication scheme provides authorization on a per
     * connection basis instead of usual per request basis
     *
     * @return <tt>true</tt> if the scheme is connection based, <tt>false</tt> if the scheme is request based.
     * @since 3.0
     */
    public boolean isConnectionBased() {
        return true;
    }

    /**
     * Authentication process may involve a series of challenge-response exchanges.
     * This method tests if the authorization process has been completed, either
     * successfully or unsuccessfully, that is, all the required authorization
     * challenges have been processed in their entirety.
     *
     * @return <tt>true</tt> if the authentication process has been completed,
     *         <tt>false</tt> otherwise.
     * @since 3.0
     */
    public boolean isComplete() {
        return complete;
    }

    /**
     * Produces an authorization string for the given set of {@link org.apache.commons.httpclient.Credentials}.
     *
     * @param credentials The set of credentials to be used for athentication
     * @param method      The method being authenticated
     * @return the authorization string
     * @throws org.apache.commons.httpclient.auth.AuthenticationException
     *          if authorization string cannot
     *          be generated due to an authentication failure
     * @since 3.0
     */
    public String authenticate(Credentials credentials, HttpMethod method) throws AuthenticationException {
        try {
            SPNegoCredentials spnegoCredentials;
            try {
                spnegoCredentials = (SPNegoCredentials) credentials;
            } catch (ClassCastException e) {
                throw new InvalidCredentialsException(
                        "Credentials cannot be used for SPNego authentication: " + credentials.getClass().getName());
            }
            GSSContext gssContext = spnegoCredentials.getGSSContext();
            byte[] clientToken = gssContext.initSecContext(serverToken, 0, serverToken.length);
            if (gssContext.isEstablished()) {
                complete = true;
                LOGGER.log(Level.INFO, "GSS Context established");
                LOGGER.log(Level.INFO, "Caller is " + gssContext.getSrcName());
                LOGGER.log(Level.INFO, "Server is " + gssContext.getTargName());
                if (gssContext.getMutualAuthState()) {
                    LOGGER.log(Level.INFO, "Mutually authenticated");
                }
            }
            String encodedToken = new String(BASE64_CODEC.encode(clientToken));
            return new StringBuffer(TOKEN_PREFIX).append(' ').append(encodedToken).toString();
        } catch (GSSException e) {
            complete = true;
            switch (e.getMajor()) {
                case GSSException.CREDENTIALS_EXPIRED:
                    throw new InvalidCredentialsException(e.getMessage(), e);
                case GSSException.NO_CRED:
                    throw new CredentialsNotAvailableException(e.getMessage(), e);
                default:
                    String errorMessage = "Caught GSSException in GSSContext.initSecContext()";
                    LOGGER.log(Level.SEVERE, errorMessage, e);
                    throw new AuthenticationException(errorMessage, e);
            }
        }
    }

   
    // DEPRECATED METHODS

    /**
     * Returns a String identifying the authentication challenge.  This is
     * used, in combination with the host and port to determine if
     * authorization has already been attempted or not.  Schemes which
     * require multiple requests to complete the authentication should
     * return a different value for each stage in the request.
     * <p/>
     * <p>Additionally, the ID should take into account any changes to the
     * authentication challenge and return a different value when appropriate.
     * For example when the realm changes in basic authentication it should be
     * considered a different authentication attempt and a different value should
     * be returned.</p>
     *
     * @return String a String identifying the authentication challenge.  The
     *         returned value may be null.
     * @deprecated no longer used
     */
    public String getID() {
        throw new UnsupportedOperationException("Deprecated.");
    }

    /**
     * @param credentials The set of credentials to be used for athentication
     * @param method      The name of the method that requires authorization.
     *                    This parameter may be ignored, if it is irrelevant
     *                    or not applicable to the given authentication scheme
     * @param uri         The URI for which authorization is needed.
     *                    This parameter may be ignored, if it is irrelevant or not
     *                    applicable to the given authentication scheme
     * @return the authorization string
     * @throws org.apache.commons.httpclient.auth.AuthenticationException
     *          if authorization string cannot
     *          be generated due to an authentication failure
     * @see org.apache.commons.httpclient.HttpMethod#getName()
     * @see org.apache.commons.httpclient.HttpMethod#getPath()
     * @deprecated Use {@link #authenticate(org.apache.commons.httpclient.Credentials,org.apache.commons.httpclient.HttpMethod)}
     *             <p/>
     *             Produces an authorization string for the given set of {@link org.apache.commons.httpclient.Credentials},
     *             method name and URI using the given authentication scheme in response to
     *             the actual authorization challenge.
     */
    public String authenticate(Credentials credentials, String method, String uri) throws AuthenticationException {
        throw new UnsupportedOperationException(
                "Deprecated. Use authenticate(org.apache.commons.httpclient.Credentials," +
                        " org.apache.commons.httpclient.HttpMethod) instead.");
    }

}
TOP

Related Classes of au.net.ocean.httpclient.auth.spnego.SPNegoAuthScheme

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.