KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > httpclient > auth > HttpAuthenticator


1 /*
2  * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v 1.7.2.4 2004/06/11 18:55:32 olegk Exp $
3  * $Revision: 1.7.2.4 $
4  * $Date: 2004/06/11 18:55:32 $
5  *
6  * ====================================================================
7  *
8  * Copyright 1999-2004 The Apache Software Foundation
9  *
10  * Licensed under the Apache License, Version 2.0 (the "License");
11  * you may not use this file except in compliance with the License.
12  * You may obtain a copy of the License at
13  *
14  * http://www.apache.org/licenses/LICENSE-2.0
15  *
16  * Unless required by applicable law or agreed to in writing, software
17  * distributed under the License is distributed on an "AS IS" BASIS,
18  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
19  * See the License for the specific language governing permissions and
20  * limitations under the License.
21  * ====================================================================
22  *
23  * This software consists of voluntary contributions made by many
24  * individuals on behalf of the Apache Software Foundation. For more
25  * information on the Apache Software Foundation, please see
26  * <http://www.apache.org/>.
27  *
28  * [Additional notices, if required by prior licensing conditions]
29  *
30  */

31
32 package org.apache.commons.httpclient.auth;
33
34 import java.util.Map JavaDoc;
35 import java.util.HashMap JavaDoc;
36 import org.apache.commons.httpclient.Header;
37 import org.apache.commons.httpclient.HttpConnection;
38 import org.apache.commons.httpclient.HttpMethod;
39 import org.apache.commons.httpclient.Credentials;
40 import org.apache.commons.httpclient.HttpState;
41 import org.apache.commons.httpclient.UsernamePasswordCredentials;
42 import org.apache.commons.logging.Log;
43 import org.apache.commons.logging.LogFactory;
44
45 /**
46  * Utility methods for HTTP authorization and authentication. This class
47  * provides utility methods for generating responses to HTTP www and proxy
48  * authentication challenges.
49  *
50  * <blockquote>
51  * A client SHOULD assume that all paths at or deeper than the depth of the
52  * last symbolic element in the path field of the Request-URI also are within
53  * the protection space specified by the basic realm value of the current
54  * challenge. A client MAY preemptively send the corresponding Authorization
55  * header with requests for resources in that space without receipt of another
56  * challenge from the server. Similarly, when a client sends a request to a
57  * proxy, it may reuse a userid and password in the Proxy-Authorization header
58  * field without receiving another challenge from the proxy server.
59  * </blockquote>
60  * </p>
61  *
62  * @author <a HREF="mailto:remm@apache.org">Remy Maucherat</a>
63  * @author Rodney Waldhoff
64  * @author <a HREF="mailto:jsdever@apache.org">Jeff Dever</a>
65  * @author Ortwin Glück
66  * @author Sean C. Sullivan
67  * @author <a HREF="mailto:adrian@ephox.com">Adrian Sutton</a>
68  * @author <a HREF="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
69  * @author <a HREF="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
70  */

71 public final class HttpAuthenticator {
72
73     /** Log object for this class. */
74     private static final Log LOG = LogFactory.getLog(HttpAuthenticator.class);
75
76     /**
77      * The www authenticate challange header.
78      */

79     public static final String JavaDoc WWW_AUTH = "WWW-Authenticate";
80
81
82     /**
83      * The www authenticate response header.
84      */

85     public static final String JavaDoc WWW_AUTH_RESP = "Authorization";
86
87
88     /**
89      * The proxy authenticate challange header.
90      */

91     public static final String JavaDoc PROXY_AUTH = "Proxy-Authenticate";
92
93
94     /**
95      * The proxy authenticate response header.
96      */

97     public static final String JavaDoc PROXY_AUTH_RESP = "Proxy-Authorization";
98
99     /** Chooses the strongest authentication scheme supported from the
100      * array of authentication challenges. Currently only <code>NTLM</code>,
101      * <code>Digest</code>, <code>Basic</code> schemes are recognized.
102      * The <code>NTLM</code> scheme is considered the strongest and is
103      * preferred to all others. The <code>Digest</code> scheme is preferred to
104      * the <code>Basic</code> one which provides no encryption for credentials.
105      * The <code>Basic</code> scheme is used only if it is the only one
106      * supported.
107      *
108      * @param challenges The array of authentication challenges
109      *
110      * @return The strongest authentication scheme supported
111      *
112      * @throws MalformedChallengeException is thrown if an authentication
113      * challenge is malformed
114      * @throws UnsupportedOperationException when none of challenge types
115      * available is supported.
116      */

117     public static AuthScheme selectAuthScheme(final Header[] challenges)
118       throws MalformedChallengeException {
119         LOG.trace("enter HttpAuthenticator.selectAuthScheme(Header[])");
120         if (challenges == null) {
121             throw new IllegalArgumentException JavaDoc("Array of challenges may not be null");
122         }
123         if (challenges.length == 0) {
124             throw new IllegalArgumentException JavaDoc("Array of challenges may not be empty");
125         }
126         String JavaDoc challenge = null;
127         Map JavaDoc challengemap = new HashMap JavaDoc(challenges.length);
128         for (int i = 0; i < challenges.length; i++) {
129             challenge = challenges[i].getValue();
130             String JavaDoc s = AuthChallengeParser.extractScheme(challenge);
131             challengemap.put(s, challenge);
132         }
133         challenge = (String JavaDoc) challengemap.get("ntlm");
134         if (challenge != null) {
135             return new NTLMScheme(challenge);
136         }
137         challenge = (String JavaDoc) challengemap.get("digest");
138         if (challenge != null) {
139             return new DigestScheme(challenge);
140         }
141         challenge = (String JavaDoc) challengemap.get("basic");
142         if (challenge != null) {
143             return new BasicScheme(challenge);
144         }
145         throw new UnsupportedOperationException JavaDoc(
146           "Authentication scheme(s) not supported: " + challengemap.toString());
147     }
148     
149
150     private static boolean doAuthenticateDefault(
151         HttpMethod method,
152         HttpConnection conn,
153         HttpState state,
154         boolean proxy)
155       throws AuthenticationException {
156         if (method == null) {
157             throw new IllegalArgumentException JavaDoc("HTTP method may not be null");
158         }
159         if (state == null) {
160             throw new IllegalArgumentException JavaDoc("HTTP state may not be null");
161         }
162         String JavaDoc host = null;
163         if (conn != null) {
164             host = proxy ? conn.getProxyHost() : conn.getHost();
165         }
166         Credentials credentials = proxy
167             ? state.getProxyCredentials(null, host) : state.getCredentials(null, host);
168         if (credentials == null) {
169             if (LOG.isWarnEnabled()) {
170                 LOG.warn("Default credentials for " + host + " not available");
171             }
172             return false;
173         }
174         if (!(credentials instanceof UsernamePasswordCredentials)) {
175             throw new AuthenticationException(
176              "Credentials cannot be used for basic authentication: "
177               + credentials.toString());
178         }
179         String JavaDoc auth = BasicScheme.authenticate((UsernamePasswordCredentials) credentials);
180         if (auth != null) {
181             String JavaDoc s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP;
182             method.setRequestHeader(s, auth);
183             return true;
184         } else {
185             return false;
186         }
187     }
188     
189     
190     /**
191      * Attempt to provide default authentication credentials
192      * to the given method in the given context using basic
193      * authentication scheme.
194      *
195      * @param method the HttpMethod which requires authentication
196      * @param conn the connection to a specific host. This parameter
197      * may be <tt>null</tt> if default credentials (not specific
198      * to any particular host) are to be used
199      * @param state the HttpState object providing Credentials
200      *
201      * @return true if the <tt>Authenticate</tt> response header
202      * was added
203      *
204      * @throws AuthenticationException when a parsing or other error occurs
205
206      * @see HttpState#setCredentials(String,String,Credentials)
207      */

208     public static boolean authenticateDefault(
209         HttpMethod method,
210         HttpConnection conn,
211         HttpState state)
212       throws AuthenticationException {
213         LOG.trace(
214             "enter HttpAuthenticator.authenticateDefault(HttpMethod, HttpConnection, HttpState)");
215         return doAuthenticateDefault(method, conn, state, false);
216     }
217
218
219     /**
220      * Attempt to provide default proxy authentication credentials
221      * to the given method in the given context using basic
222      * authentication scheme.
223      *
224      * @param method the HttpMethod which requires authentication
225      * @param conn the connection to a specific host. This parameter
226      * may be <tt>null</tt> if default credentials (not specific
227      * to any particular host) are to be used
228      * @param state the HttpState object providing Credentials
229      *
230      * @return true if the <tt>Proxy-Authenticate</tt> response header
231      * was added
232      *
233      * @throws AuthenticationException when a parsing or other error occurs
234
235      * @see HttpState#setCredentials(String,Credentials)
236      */

237     public static boolean authenticateProxyDefault(
238         HttpMethod method,
239         HttpConnection conn,
240         HttpState state)
241       throws AuthenticationException {
242         LOG.trace("enter HttpAuthenticator.authenticateProxyDefault(HttpMethod, HttpState)");
243         return doAuthenticateDefault(method, conn, state, true);
244     }
245
246
247     private static boolean doAuthenticate(
248         AuthScheme authscheme,
249         HttpMethod method,
250         HttpConnection conn,
251         HttpState state,
252         boolean proxy)
253        throws AuthenticationException {
254         if (authscheme == null) {
255             throw new IllegalArgumentException JavaDoc("Authentication scheme may not be null");
256         }
257         if (method == null) {
258             throw new IllegalArgumentException JavaDoc("HTTP method may not be null");
259         }
260         if (state == null) {
261             throw new IllegalArgumentException JavaDoc("HTTP state may not be null");
262         }
263         String JavaDoc host = null;
264         if (conn != null) {
265             if (proxy) {
266                 host = conn.getProxyHost();
267             } else {
268                 host = conn.getVirtualHost();
269                 if (host == null) {
270                     host = conn.getHost();
271                 }
272             }
273         }
274         String JavaDoc realm = authscheme.getRealm();
275         if (LOG.isDebugEnabled()) {
276             StringBuffer JavaDoc buffer = new StringBuffer JavaDoc();
277             buffer.append("Authenticating with the ");
278             if (realm == null) {
279                 buffer.append("default");
280             } else {
281                 buffer.append('\'');
282                 buffer.append(realm);
283                 buffer.append('\'');
284             }
285             buffer.append(" authentication realm at ");
286             buffer.append(host);
287             LOG.debug(buffer.toString());
288         }
289         // TODO: To be removed in the future. Required for backward compatibility
290
if (realm == null) {
291             realm = host;
292         }
293         Credentials credentials = proxy
294             ? state.getProxyCredentials(realm, host)
295             : state.getCredentials(realm, host);
296         if (credentials == null) {
297             throw new AuthenticationException(
298                 "No credentials available for the '" + authscheme.getRealm()
299                 + "' authentication realm at " + host);
300         }
301         String JavaDoc auth = authscheme.authenticate(credentials, method.getName(), method.getPath());
302         if (auth != null) {
303             String JavaDoc s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP;
304             method.setRequestHeader(s, auth);
305             return true;
306         } else {
307             return false;
308         }
309     }
310
311     /**
312      * Attempt to provide requisite authentication credentials to the
313      * given method in the given context using the given
314      * authentication scheme.
315      *
316      * @param authscheme The authentication scheme to be used
317      * @param method The HttpMethod which requires authentication
318      * @param conn the connection to a specific host. This parameter
319      * may be <tt>null</tt> if default credentials (not specific
320      * to any particular host) are to be used
321      * @param state The HttpState object providing Credentials
322      *
323      * @return true if the <tt>Authenticate</tt> response header was added
324      *
325      * @throws AuthenticationException when a parsing or other error occurs
326
327      * @see HttpState#setCredentials(String,Credentials)
328      */

329     public static boolean authenticate(
330         AuthScheme authscheme,
331         HttpMethod method,
332         HttpConnection conn,
333         HttpState state)
334         throws AuthenticationException {
335        LOG.trace(
336             "enter HttpAuthenticator.authenticate(AuthScheme, HttpMethod, HttpConnection, "
337             + "HttpState)");
338         return doAuthenticate(authscheme, method, conn, state, false);
339     }
340
341
342     /**
343      * Attempt to provide requisite proxy authentication credentials
344      * to the given method in the given context using
345      * the given authentication scheme.
346      *
347      * @param authscheme The authentication scheme to be used
348      * @param method the HttpMethod which requires authentication
349      * @param conn the connection to a specific host. This parameter
350      * may be <tt>null</tt> if default credentials (not specific
351      * to any particular host) are to be used
352      * @param state the HttpState object providing Credentials
353      *
354      * @return true if the <tt>Proxy-Authenticate</tt> response header
355      * was added
356      *
357      * @throws AuthenticationException when a parsing or other error occurs
358
359      * @see HttpState#setCredentials(String,Credentials)
360      */

361     public static boolean authenticateProxy(
362         AuthScheme authscheme,
363         HttpMethod method,
364         HttpConnection conn,
365         HttpState state
366     ) throws AuthenticationException {
367        LOG.trace("enter HttpAuthenticator.authenticateProxy(AuthScheme, HttpMethod, HttpState)");
368        return doAuthenticate(authscheme, method, conn, state, true);
369     }
370 }
371
Popular Tags