On Tue, Nov 01, 2005 at 03:56:41PM +0100, Ortwin Gl?ck wrote: > Mikael, > > First of all, thanks for your contribution! > > We may consider your code for the contrib package for 3.0 because > i) it is too late in the release process for 3.0 > ii) JGSS API is only available as of JDK 1.4 while HttpClient 3.0 is > compatible with JDK 1.2 (sigh) > > We may decide to include it in the 4.0 code base though. For this step > some JUnit tests would be nice. > > Personally I have no objections. What do the others think? >
+1 from me to add this code to the contrib package Oleg > Ortwin Gl?ck > > Mikael Wikstr?m wrote: > >this is a followup on my previus mail with the same title sent 08/03/2005 > > > >Hi, > > > >finally... Here's my spnego/Negotiate AuthScheme for httpclient 3.0. > > > >It's more or less complete and rely on JAAS for credentials and jgss for > >mutual auth and credential forwarding. > > > >My next goal will be to se if I can use this scheme with axis (SOAP) > >over ssl to create a secure WS that can use forwarded credentials. > > > >I really hope this patch will become part of the main dist. > > > >references: > >http://www.ietf.org/internet-drafts/draft-jaganathan-kerberos-http-00.txt > >http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dnsecure/html/http-sso-2.asp > > > >http://www11.informatik.tu-muenchen.de/Java/j2sdkse/guide/security/jgss/tutorials/ClientServer.html > > > > > >Regards > >/ Mikael Wikstrom > >[EMAIL PROTECTED] > > > > > > > > > >------------------------------------------------------------------------ > > > >/* > > * $Header: > > /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/examples/CustomAuthenticationExample.java,v > > 1.1 2004/09/06 20:10:02 mbecke Exp $ > > * $Revision: 155418 $ > > * $Date: 2005-02-26 14:01:52 +0100 (Sat, 26 Feb 2005) $ > > * > > * ==================================================================== > > * > > * Copyright 2002-2004 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/>. > > * > > */ > >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.auth.NegotiateScheme; > >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. > > */ > >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(); > > } > > > > } > >} > > > > > >------------------------------------------------------------------------ > > > >/* > > * $Header:$ > > * $Revision:$ > > * $Date:$ > > * > > * ==================================================================== > > * > > * Copyright 2002-2004 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.auth; > > > >import org.apache.commons.codec.binary.Base64; > >import org.apache.commons.httpclient.Credentials; > >import org.apache.commons.httpclient.HttpMethod; > >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)); > > } > >} > > > > > >------------------------------------------------------------------------ > > > >/** > > * Login Configuration 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; > >}; > > > > > >------------------------------------------------------------------------ > > > >--------------------------------------------------------------------- > >To unsubscribe, e-mail: [EMAIL PROTECTED] > >For additional commands, e-mail: [EMAIL PROTECTED] > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: [EMAIL PROTECTED] > For additional commands, e-mail: [EMAIL PROTECTED] > > --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]