Author: olegk
Date: Fri Feb 10 06:11:06 2006
New Revision: 376695

URL: http://svn.apache.org/viewcvs?rev=376695&view=rev
Log:
SPNEGO contrib for httpclient 3.x
http://devel.it.su.se/pub/jsp/polopoly.jsp?d=1026&a=3329

Contributed by Mikael Wikström <mikael.wikstrom at it.su.se>

Added:
    
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/
    
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
   (with props)
    
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
   (with props)
Modified:
    jakarta/commons/proper/httpclient/trunk/project.xml

Modified: jakarta/commons/proper/httpclient/trunk/project.xml
URL: 
http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/project.xml?rev=376695&r1=376694&r2=376695&view=diff
==============================================================================
--- jakarta/commons/proper/httpclient/trunk/project.xml (original)
+++ jakarta/commons/proper/httpclient/trunk/project.xml Fri Feb 10 06:11:06 2006
@@ -124,6 +124,9 @@
     <branch>
       <tag>HTTPCLIENT_2_0_BRANCH</tag>
     </branch>
+    <branch>
+      <tag>HTTPCLIENT_3_0_BRANCH</tag>
+    </branch>
   </branches>
 
   <mailingLists>
@@ -283,6 +286,10 @@
     <contributor>
       <name>Laura Werner</name>
       <email>laura -at- lwerner.org</email>
+    </contributor>
+    <contributor>
+      <name>Mikael Wilstrom</name>
+      <email>mikael.wikstrom -at- it.su.se</email>
     </contributor>
   </contributors>
 

Added: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
URL: 
http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java?rev=376695&view=auto
==============================================================================
--- 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
 (added)
+++ 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
 Fri Feb 10 06:11:06 2006
@@ -0,0 +1,116 @@
+/*
+ * $Header: $
+ * $Revision: $
+ * $Date: $
+ *
+ * ====================================================================
+ *
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+package org.apache.commons.httpclient.contrib.auth;
+
+import java.util.ArrayList;
+
+import org.apache.commons.httpclient.Credentials;
+import org.apache.commons.httpclient.HttpClient;
+import org.apache.commons.httpclient.auth.AuthPolicy;
+import org.apache.commons.httpclient.auth.AuthScope;
+import org.apache.commons.httpclient.methods.GetMethod;
+import org.apache.commons.httpclient.params.DefaultHttpParams;
+import org.apache.commons.httpclient.params.HttpParams;
+
+/**
+ * A simple custom AuthScheme example.  The included auth scheme is meant 
+ * for demonstration purposes only.  It does not actually implement a usable
+ * authentication method.
+ *
+ * <pre>
+ Login Configuration file bcsLogin.conf for JAAS.
+ -----------------------------------------------
+   com.sun.security.jgss.initiate {
+     com.sun.security.auth.module.Krb5LoginModule 
+         required 
+         client=TRUE 
+         useTicketCache="true" 
+         ticketCache="${user.krb5cc}" 
+         debug=true;
+   };
+
+   com.sun.security.jgss.accept {
+     com.sun.security.auth.module.Krb5LoginModule 
+         required 
+         client=TRUE 
+         useTicketCache="true" 
+         ticketCache="${user.krb5cc}" 
+         debug=true;
+   };
+ -----------------------------------------------
+ 
+   java  -Djava.security.krb5.realm=REALM \
+      -Djava.security.krb5.kdc=kdc.domain \
+      -Djavax.security.auth.useSubjectCredsOnly=false \
+      -Djava.security.auth.login.config=src/conf/bcsLogin.conf \
+      -Duser.krb5cc="$KRB5CCNAME" \
+      -classpath $CP \
+      CustomAuthenticationNegotiateExample "http://localhost/gsstest/";
+   </pre>
+ */
+public class CustomAuthenticationNegotiateExample {
+
+    public static void main(String[] args) {
+        
+        // register the auth scheme
+        AuthPolicy.registerAuthScheme("Negotiate", NegotiateScheme.class);
+
+        // include the scheme in the AuthPolicy.AUTH_SCHEME_PRIORITY preference
+        ArrayList schemes = new ArrayList();
+        schemes.add("Negotiate");
+
+        HttpParams params = DefaultHttpParams.getDefaultParams();        
+        params.setParameter(AuthPolicy.AUTH_SCHEME_PRIORITY, schemes);
+        
+        // now that our scheme has been registered we can execute methods 
against
+        // servers that require "Negotiate" authentication... 
+        HttpClient client = new HttpClient();
+        
+        // The Negotiate scheme uses JAAS as credential provider but the
+        // httpclient api require us to supply cred anyway.
+        // a work around is to provide an empty set of creds.
+        Credentials use_jaas_creds = new Credentials() {};
+        client.getState().setCredentials(
+            new AuthScope(null, -1, null),
+            use_jaas_creds);
+        GetMethod httpget = new GetMethod(args[0]);
+
+        try {
+            client.executeMethod(httpget);
+            //System.out.println(httpget.getStatusLine());
+            //System.out.println(httpget.getResponseBodyAsString());
+        } catch (Exception e) {
+            e.printStackTrace();            
+        } finally {
+            // release any connection resources used by the method
+            httpget.releaseConnection();
+        }            
+        
+    }
+} 

Propchange: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/CustomAuthenticationNegotiateExample.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
URL: 
http://svn.apache.org/viewcvs/jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java?rev=376695&view=auto
==============================================================================
--- 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
 (added)
+++ 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
 Fri Feb 10 06:11:06 2006
@@ -0,0 +1,293 @@
+/*
+ * $Header:$
+ * $Revision$
+ * $Date$
+ *
+ * ====================================================================
+ *
+ *  Copyright 2006 The Apache Software Foundation
+ *
+ *  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.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Software Foundation.  For more
+ * information on the Apache Software Foundation, please see
+ * <http://www.apache.org/>.
+ *
+ */
+
+package org.apache.commons.httpclient.contrib.auth;
+
+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.AuthChallengeException;
+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.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.ietf.jgss.GSSContext;
+import org.ietf.jgss.GSSException;
+import org.ietf.jgss.GSSManager;
+import org.ietf.jgss.GSSName;
+import org.ietf.jgss.Oid;
+
+/** 
+ * 
+ * @author <a href="mailto:[EMAIL PROTECTED]">Mikael Wilstrom</a>
+ * @author Mikael Wikstrom
+ */
+public class NegotiateScheme implements AuthScheme {
+
+    /** Log object for this class. */
+    private static final Log LOG = LogFactory.getLog(NegotiateScheme.class);
+
+    /** challenge string. */
+    private String challenge = null;
+
+    private static final int UNINITIATED         = 0;
+    private static final int INITIATED           = 1;
+    private static final int NEGOTIATING         = 3;
+    private static final int ESTABLISHED         = 4;
+    private static final int FAILED              = Integer.MAX_VALUE;
+
+    private GSSContext context = null;
+
+    /** Authentication process state */
+    private int state;
+
+    /** base64 decoded challenge **/
+    byte[] token = new byte[0];
+
+    /**
+     * Init GSSContext for negotiation.
+     * 
+     * @param server servername only (e.g: radar.it.su.se)
+     */
+    protected void init(String server) throws GSSException {
+         LOG.debug("init " + server);
+         /* Kerberos v5 GSS-API mechanism defined in RFC 1964. */
+         Oid krb5Oid = new Oid("1.2.840.113554.1.2.2");
+         GSSManager manager = GSSManager.getInstance();
+         GSSName serverName = manager.createName("HTTP/"+server, null); 
+         context = manager.createContext(serverName, krb5Oid, null,
+                                    GSSContext.DEFAULT_LIFETIME);
+         context.requestMutualAuth(true); 
+         context.requestCredDeleg(true);
+         state = INITIATED;
+    }
+    
+    /**
+     * Default constructor for the Negotiate authentication scheme.
+     * 
+     * @since 3.0
+     */
+    public NegotiateScheme() {
+        super();
+        state = UNINITIATED;
+    }
+
+    /**
+     * Constructor for the Negotiate authentication scheme.
+     * 
+     * @param challenge The authentication challenge
+     */
+    public NegotiateScheme(final String challenge) {
+        super();
+        LOG.debug("enter NegotiateScheme("+challenge+")");
+        processChallenge(challenge);
+    }
+
+    /**
+     * Processes the Negotiate challenge.
+     *  
+     * @param challenge the challenge string
+     * 
+     * @since 3.0
+     */
+    public void processChallenge(final String challenge){
+        LOG.debug("enter processChallenge(challenge=\""+challenge+"\")");
+        if (challenge.startsWith("Negotiate")) {
+            if(isComplete() == false)
+                state = NEGOTIATING;
+            
+            if (challenge.startsWith("Negotiate "))
+                token = new 
Base64().decode(challenge.substring(10).getBytes());
+            else
+                token = new byte[0];
+        }
+    }
+
+    /**
+     * Tests if the Negotiate authentication process has been completed.
+     * 
+     * @return <tt>true</tt> if authorization has been processed,
+     *   <tt>false</tt> otherwise.
+     * 
+     * @since 3.0
+     */
+    public boolean isComplete() {
+        LOG.debug("enter isComplete()");
+        return this.state == ESTABLISHED || this.state == FAILED;
+    }
+
+    /**
+     * Returns textual designation of the Negotiate authentication scheme.
+     * 
+     * @return <code>Negotiate</code>
+     */
+    public String getSchemeName() {
+        return "Negotiate";
+    }
+
+    /**
+     * The concept of an authentication realm is not supported by the 
Negotiate 
+     * authentication scheme. Always returns <code>null</code>.
+     * 
+     * @return <code>null</code>
+     */
+    public String getRealm() {
+        return null;
+    }
+    
+    /**
+     * 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>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() {
+        LOG.debug("enter getID(): " + challenge);
+        return challenge;
+    }
+    
+    /**
+     * Returns the authentication parameter with the given name, if available.
+     * 
+     * <p>There are no valid parameters for Negotiate authentication so this 
+     * method always returns <tt>null</tt>.</p>
+     * 
+     * @param name The name of the parameter to be returned
+     * 
+     * @return the parameter with the given name
+     */
+    public String getParameter(String name) {
+        LOG.debug("enter getParameter("+name+")");
+        if (name == null) {
+            throw new IllegalArgumentException("Parameter name may not be 
null"); 
+        }
+        return null;
+    }
+
+    /**
+     * Returns <tt>true</tt>. 
+     * Negotiate authentication scheme is connection based.
+     * 
+     * @return <tt>true</tt>.
+     * 
+     * @since 3.0
+     */
+    public boolean isConnectionBased() {
+        LOG.info("enter isConnectionBased()");
+        return true;
+    }
+
+    /**
+     * Method not supported by Negotiate scheme. 
+     * 
+     * @throws AuthenticationException if called.
+     * 
+     * @deprecated Use [EMAIL PROTECTED] #authenticate(Credentials, 
HttpMethod)}
+     */
+    public String authenticate(Credentials credentials, String method, String 
uri) 
+      throws AuthenticationException {
+        throw new AuthenticationException("method not supported by Negotiate 
scheme");
+    }
+    
+    /**
+     * Produces Negotiate authorization string based on token created by 
+     * processChallenge.
+     * 
+     * @param credentials Never used be the Negotiate scheme but must be 
provided to 
+     * satisfy common-httpclient API. Credentials from JAAS will be used 
insted.
+     * @param method The method being authenticated
+     * 
+     * @throws AuthenticationException if authorization string cannot 
+     *   be generated due to an authentication failure
+     * 
+     * @return an Negotiate authorization string
+     * 
+     * @since 3.0
+     */
+    public String authenticate(
+        Credentials credentials, 
+        HttpMethod method
+    ) throws AuthenticationException {
+        LOG.debug("enter NegotiateScheme.authenticate(Credentials, 
HttpMethod)");
+
+        if (state == UNINITIATED) {
+            throw new IllegalStateException(
+               "Negotiation authentication process has not been initiated");
+        }
+
+        try {
+            try {                
+                if(context==null) {
+                    LOG.info("host: " + method.getURI().getHost());
+                    init( method.getURI().getHost() );
+                }
+            } catch (org.apache.commons.httpclient.URIException urie) {
+                LOG.error(urie.getMessage());
+                state = FAILED;
+                throw new AuthenticationException(urie.getMessage());
+            }
+        
+            // HTTP 1.1 issue:
+            // Mutual auth will never complete do to 200 insted of 401 in 
+            // return from server. "state" will never reach ESTABLISHED
+            // but it works anyway
+            token = context.initSecContext(token, 0, token.length);
+            LOG.info("got token, sending " + token.length + " to server");
+        } catch (GSSException gsse) {
+            LOG.fatal(gsse.getMessage());
+            state = FAILED;
+            if( gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL
+                    || gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED )
+                throw new InvalidCredentialsException(gsse.getMessage(),gsse);
+            if( gsse.getMajor() == GSSException.NO_CRED )
+                throw new 
CredentialsNotAvailableException(gsse.getMessage(),gsse);
+            if( gsse.getMajor() == GSSException.DEFECTIVE_TOKEN
+                    || gsse.getMajor() == GSSException.DUPLICATE_TOKEN
+                    || gsse.getMajor() == GSSException.OLD_TOKEN )
+                throw new AuthChallengeException(gsse.getMessage(),gsse);
+            // other error
+            throw new AuthenticationException(gsse.getMessage());
+        }
+        return "Negotiate " + new String(new Base64().encode(token));
+    }
+}

Propchange: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
------------------------------------------------------------------------------
    svn:eol-style = native

Propchange: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
------------------------------------------------------------------------------
    svn:keywords = Date Author Id Revision HeadURL

Propchange: 
jakarta/commons/proper/httpclient/trunk/src/contrib/org/apache/commons/httpclient/contrib/auth/NegotiateScheme.java
------------------------------------------------------------------------------
    svn:mime-type = text/plain



---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]

Reply via email to