KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > httpclient > contrib > auth > NegotiateScheme


1 /*
2  * $Header:$
3  * $Revision: 480424 $
4  * $Date: 2006-11-29 05:56:49 +0000 (Wed, 29 Nov 2006) $
5  *
6  * ====================================================================
7  *
8  * Licensed to the Apache Software Foundation (ASF) under one or more
9  * contributor license agreements. See the NOTICE file distributed with
10  * this work for additional information regarding copyright ownership.
11  * The ASF licenses this file to You under the Apache License, Version 2.0
12  * (the "License"); you may not use this file except in compliance with
13  * the License. You may obtain a copy of the License at
14  *
15  * http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  * ====================================================================
23  *
24  * This software consists of voluntary contributions made by many
25  * individuals on behalf of the Apache Software Foundation. For more
26  * information on the Apache Software Foundation, please see
27  * <http://www.apache.org/>.
28  *
29  */

30
31 package org.apache.commons.httpclient.contrib.auth;
32
33 import org.apache.commons.codec.binary.Base64;
34 import org.apache.commons.httpclient.Credentials;
35 import org.apache.commons.httpclient.HttpMethod;
36 import org.apache.commons.httpclient.auth.AuthChallengeException;
37 import org.apache.commons.httpclient.auth.AuthScheme;
38 import org.apache.commons.httpclient.auth.AuthenticationException;
39 import org.apache.commons.httpclient.auth.CredentialsNotAvailableException;
40 import org.apache.commons.httpclient.auth.InvalidCredentialsException;
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.ietf.jgss.GSSContext JavaDoc;
44 import org.ietf.jgss.GSSException JavaDoc;
45 import org.ietf.jgss.GSSManager JavaDoc;
46 import org.ietf.jgss.GSSName JavaDoc;
47 import org.ietf.jgss.Oid JavaDoc;
48
49 /**
50  *
51  * @author <a HREF="mailto:mikael.wikstrom@it.su.se">Mikael Wilstrom</a>
52  * @author Mikael Wikstrom
53  */

54 public class NegotiateScheme implements AuthScheme {
55
56     /** Log object for this class. */
57     private static final Log LOG = LogFactory.getLog(NegotiateScheme.class);
58
59     /** challenge string. */
60     private String JavaDoc challenge = null;
61
62     private static final int UNINITIATED = 0;
63     private static final int INITIATED = 1;
64     private static final int NEGOTIATING = 3;
65     private static final int ESTABLISHED = 4;
66     private static final int FAILED = Integer.MAX_VALUE;
67
68     private GSSContext JavaDoc context = null;
69
70     /** Authentication process state */
71     private int state;
72
73     /** base64 decoded challenge **/
74     byte[] token = new byte[0];
75
76     /**
77      * Init GSSContext for negotiation.
78      *
79      * @param server servername only (e.g: radar.it.su.se)
80      */

81     protected void init(String JavaDoc server) throws GSSException JavaDoc {
82          LOG.debug("init " + server);
83          /* Kerberos v5 GSS-API mechanism defined in RFC 1964. */
84          Oid JavaDoc krb5Oid = new Oid JavaDoc("1.2.840.113554.1.2.2");
85          GSSManager JavaDoc manager = GSSManager.getInstance();
86          GSSName JavaDoc serverName = manager.createName("HTTP/"+server, null);
87          context = manager.createContext(serverName, krb5Oid, null,
88                                     GSSContext.DEFAULT_LIFETIME);
89          context.requestMutualAuth(true);
90          context.requestCredDeleg(true);
91          state = INITIATED;
92     }
93     
94     /**
95      * Default constructor for the Negotiate authentication scheme.
96      *
97      * @since 3.0
98      */

99     public NegotiateScheme() {
100         super();
101         state = UNINITIATED;
102     }
103
104     /**
105      * Constructor for the Negotiate authentication scheme.
106      *
107      * @param challenge The authentication challenge
108      */

109     public NegotiateScheme(final String JavaDoc challenge) {
110         super();
111         LOG.debug("enter NegotiateScheme("+challenge+")");
112         processChallenge(challenge);
113     }
114
115     /**
116      * Processes the Negotiate challenge.
117      *
118      * @param challenge the challenge string
119      *
120      * @since 3.0
121      */

122     public void processChallenge(final String JavaDoc challenge){
123         LOG.debug("enter processChallenge(challenge=\""+challenge+"\")");
124         if (challenge.startsWith("Negotiate")) {
125             if(isComplete() == false)
126                 state = NEGOTIATING;
127             
128             if (challenge.startsWith("Negotiate "))
129                 token = new Base64().decode(challenge.substring(10).getBytes());
130             else
131                 token = new byte[0];
132         }
133     }
134
135     /**
136      * Tests if the Negotiate authentication process has been completed.
137      *
138      * @return <tt>true</tt> if authorization has been processed,
139      * <tt>false</tt> otherwise.
140      *
141      * @since 3.0
142      */

143     public boolean isComplete() {
144         LOG.debug("enter isComplete()");
145         return this.state == ESTABLISHED || this.state == FAILED;
146     }
147
148     /**
149      * Returns textual designation of the Negotiate authentication scheme.
150      *
151      * @return <code>Negotiate</code>
152      */

153     public String JavaDoc getSchemeName() {
154         return "Negotiate";
155     }
156
157     /**
158      * The concept of an authentication realm is not supported by the Negotiate
159      * authentication scheme. Always returns <code>null</code>.
160      *
161      * @return <code>null</code>
162      */

163     public String JavaDoc getRealm() {
164         return null;
165     }
166     
167     /**
168      * Returns a String identifying the authentication challenge. This is
169      * used, in combination with the host and port to determine if
170      * authorization has already been attempted or not. Schemes which
171      * require multiple requests to complete the authentication should
172      * return a different value for each stage in the request.
173      *
174      * <p>Additionally, the ID should take into account any changes to the
175      * authentication challenge and return a different value when appropriate.
176      * For example when the realm changes in basic authentication it should be
177      * considered a different authentication attempt and a different value should
178      * be returned.</p>
179      *
180      * @return String a String identifying the authentication challenge. The
181      * returned value may be null.
182      *
183      * @deprecated no longer used
184      */

185     public String JavaDoc getID() {
186         LOG.debug("enter getID(): " + challenge);
187         return challenge;
188     }
189     
190     /**
191      * Returns the authentication parameter with the given name, if available.
192      *
193      * <p>There are no valid parameters for Negotiate authentication so this
194      * method always returns <tt>null</tt>.</p>
195      *
196      * @param name The name of the parameter to be returned
197      *
198      * @return the parameter with the given name
199      */

200     public String JavaDoc getParameter(String JavaDoc name) {
201         LOG.debug("enter getParameter("+name+")");
202         if (name == null) {
203             throw new IllegalArgumentException JavaDoc("Parameter name may not be null");
204         }
205         return null;
206     }
207
208     /**
209      * Returns <tt>true</tt>.
210      * Negotiate authentication scheme is connection based.
211      *
212      * @return <tt>true</tt>.
213      *
214      * @since 3.0
215      */

216     public boolean isConnectionBased() {
217         LOG.info("enter isConnectionBased()");
218         return true;
219     }
220
221     /**
222      * Method not supported by Negotiate scheme.
223      *
224      * @throws AuthenticationException if called.
225      *
226      * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
227      */

228     public String JavaDoc authenticate(Credentials credentials, String JavaDoc method, String JavaDoc uri)
229       throws AuthenticationException {
230         throw new AuthenticationException("method not supported by Negotiate scheme");
231     }
232     
233     /**
234      * Produces Negotiate authorization string based on token created by
235      * processChallenge.
236      *
237      * @param credentials Never used be the Negotiate scheme but must be provided to
238      * satisfy common-httpclient API. Credentials from JAAS will be used insted.
239      * @param method The method being authenticated
240      *
241      * @throws AuthenticationException if authorization string cannot
242      * be generated due to an authentication failure
243      *
244      * @return an Negotiate authorization string
245      *
246      * @since 3.0
247      */

248     public String JavaDoc authenticate(
249         Credentials credentials,
250         HttpMethod method
251     ) throws AuthenticationException {
252         LOG.debug("enter NegotiateScheme.authenticate(Credentials, HttpMethod)");
253
254         if (state == UNINITIATED) {
255             throw new IllegalStateException JavaDoc(
256                "Negotiation authentication process has not been initiated");
257         }
258
259         try {
260             try {
261                 if(context==null) {
262                     LOG.info("host: " + method.getURI().getHost());
263                     init( method.getURI().getHost() );
264                 }
265             } catch (org.apache.commons.httpclient.URIException urie) {
266                 LOG.error(urie.getMessage());
267                 state = FAILED;
268                 throw new AuthenticationException(urie.getMessage());
269             }
270         
271             // HTTP 1.1 issue:
272
// Mutual auth will never complete do to 200 insted of 401 in
273
// return from server. "state" will never reach ESTABLISHED
274
// but it works anyway
275
token = context.initSecContext(token, 0, token.length);
276             LOG.info("got token, sending " + token.length + " to server");
277         } catch (GSSException JavaDoc gsse) {
278             LOG.fatal(gsse.getMessage());
279             state = FAILED;
280             if( gsse.getMajor() == GSSException.DEFECTIVE_CREDENTIAL
281                     || gsse.getMajor() == GSSException.CREDENTIALS_EXPIRED )
282                 throw new InvalidCredentialsException(gsse.getMessage(),gsse);
283             if( gsse.getMajor() == GSSException.NO_CRED )
284                 throw new CredentialsNotAvailableException(gsse.getMessage(),gsse);
285             if( gsse.getMajor() == GSSException.DEFECTIVE_TOKEN
286                     || gsse.getMajor() == GSSException.DUPLICATE_TOKEN
287                     || gsse.getMajor() == GSSException.OLD_TOKEN )
288                 throw new AuthChallengeException(gsse.getMessage(),gsse);
289             // other error
290
throw new AuthenticationException(gsse.getMessage());
291         }
292         return "Negotiate " + new String JavaDoc(new Base64().encode(token));
293     }
294 }
295
Popular Tags