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]