View Javadoc
1 /* 2 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v 1.7 2003/05/26 22:07:22 oglueck Exp $ 3 * $Revision: 1.7 $ 4 * $Date: 2003/05/26 22:07:22 $ 5 * 6 * ==================================================================== 7 * 8 * The Apache Software License, Version 1.1 9 * 10 * Copyright (c) 1999-2003 The Apache Software Foundation. All rights 11 * reserved. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 20 * 2. Redistributions in binary form must reproduce the above copyright 21 * notice, this list of conditions and the following disclaimer in 22 * the documentation and/or other materials provided with the 23 * distribution. 24 * 25 * 3. The end-user documentation included with the redistribution, if 26 * any, must include the following acknowlegement: 27 * "This product includes software developed by the 28 * Apache Software Foundation (http://www.apache.org/)." 29 * Alternately, this acknowlegement may appear in the software itself, 30 * if and wherever such third-party acknowlegements normally appear. 31 * 32 * 4. The names "The Jakarta Project", "Commons", and "Apache Software 33 * Foundation" must not be used to endorse or promote products derived 34 * from this software without prior written permission. For written 35 * permission, please contact apache@apache.org. 36 * 37 * 5. Products derived from this software may not be called "Apache" 38 * nor may "Apache" appear in their names without prior written 39 * permission of the Apache Group. 40 * 41 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 42 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 43 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 44 * DISCLAIMED. IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR 45 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 46 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 47 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 48 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 49 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 50 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 51 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 52 * SUCH DAMAGE. 53 * ==================================================================== 54 * 55 * This software consists of voluntary contributions made by many 56 * individuals on behalf of the Apache Software Foundation. For more 57 * information on the Apache Software Foundation, please see 58 * <http://www.apache.org/>;. 59 * 60 * [Additional notices, if required by prior licensing conditions] 61 * 62 */ 63 64 package org.apache.commons.httpclient.auth; 65 66 import java.util.Map; 67 import java.util.HashMap; 68 import org.apache.commons.httpclient.Header; 69 import org.apache.commons.httpclient.HttpConnection; 70 import org.apache.commons.httpclient.HttpMethod; 71 import org.apache.commons.httpclient.Credentials; 72 import org.apache.commons.httpclient.HttpState; 73 import org.apache.commons.httpclient.UsernamePasswordCredentials; 74 import org.apache.commons.logging.Log; 75 import org.apache.commons.logging.LogFactory; 76 77 /*** 78 * Utility methods for HTTP authorization and authentication. This class 79 * provides utility methods for generating responses to HTTP www and proxy 80 * authentication challenges. 81 * 82 * <blockquote> 83 * A client SHOULD assume that all paths at or deeper than the depth of the 84 * last symbolic element in the path field of the Request-URI also are within 85 * the protection space specified by the basic realm value of the current 86 * challenge. A client MAY preemptively send the corresponding Authorization 87 * header with requests for resources in that space without receipt of another 88 * challenge from the server. Similarly, when a client sends a request to a 89 * proxy, it may reuse a userid and password in the Proxy-Authorization header 90 * field without receiving another challenge from the proxy server. 91 * </blockquote> 92 * </p> 93 * 94 * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> 95 * @author Rodney Waldhoff 96 * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a> 97 * @author Ortwin Gl�ck 98 * @author Sean C. Sullivan 99 * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a> 100 * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> 101 * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> 102 */ 103 public final class HttpAuthenticator { 104 105 /*** Log object for this class. */ 106 private static final Log LOG = LogFactory.getLog(HttpAuthenticator.class); 107 108 /*** 109 * The www authenticate challange header. 110 */ 111 public static final String WWW_AUTH = "WWW-Authenticate"; 112 113 114 /*** 115 * The www authenticate response header. 116 */ 117 public static final String WWW_AUTH_RESP = "Authorization"; 118 119 120 /*** 121 * The proxy authenticate challange header. 122 */ 123 public static final String PROXY_AUTH = "Proxy-Authenticate"; 124 125 126 /*** 127 * The proxy authenticate response header. 128 */ 129 public static final String PROXY_AUTH_RESP = "Proxy-Authorization"; 130 131 /*** Chooses the strongest authentication scheme supported from the 132 * array of authentication challenges. Currently only <code>NTLM</code>, 133 * <code>Digest</code>, <code>Basic</code> schemes are recognized. 134 * The <code>NTLM</code> scheme is considered the strongest and is 135 * preferred to all others. The <code>Digest</code> scheme is preferred to 136 * the <code>Basic</code> one which provides no encryption for credentials. 137 * The <code>Basic</code> scheme is used only if it is the only one 138 * supported. 139 * 140 * @param challenges The array of authentication challenges 141 * 142 * @return The strongest authentication scheme supported 143 * 144 * @throws MalformedChallengeException is thrown if an authentication 145 * challenge is malformed 146 * @throws UnsupportedOperationException when none of challenge types 147 * available is supported. 148 */ 149 public static AuthScheme selectAuthScheme(final Header[] challenges) 150 throws MalformedChallengeException { 151 LOG.trace("enter HttpAuthenticator.selectAuthScheme(Header[])"); 152 if (challenges == null) { 153 throw new IllegalArgumentException("Array of challenges may not be null"); 154 } 155 if (challenges.length == 0) { 156 throw new IllegalArgumentException("Array of challenges may not be empty"); 157 } 158 String challenge = null; 159 Map challengemap = new HashMap(challenges.length); 160 for (int i = 0; i < challenges.length; i++) { 161 challenge = challenges[i].getValue(); 162 String s = AuthChallengeParser.extractScheme(challenge); 163 challengemap.put(s, challenge); 164 } 165 challenge = (String) challengemap.get("ntlm"); 166 if (challenge != null) { 167 return new NTLMScheme(challenge); 168 } 169 challenge = (String) challengemap.get("digest"); 170 if (challenge != null) { 171 return new DigestScheme(challenge); 172 } 173 challenge = (String) challengemap.get("basic"); 174 if (challenge != null) { 175 return new BasicScheme(challenge); 176 } 177 throw new UnsupportedOperationException( 178 "Authentication scheme(s) not supported: " + challengemap.toString()); 179 } 180 181 182 private static boolean doAuthenticateDefault( 183 HttpMethod method, 184 HttpConnection conn, 185 HttpState state, 186 boolean proxy) 187 throws AuthenticationException { 188 if (method == null) { 189 throw new IllegalArgumentException("HTTP method may not be null"); 190 } 191 if (state == null) { 192 throw new IllegalArgumentException("HTTP state may not be null"); 193 } 194 String host = null; 195 if (conn != null) { 196 host = proxy ? conn.getProxyHost() : conn.getHost(); 197 } 198 Credentials credentials = proxy 199 ? state.getProxyCredentials(null, host) : state.getCredentials(null, host); 200 if (credentials == null) { 201 return false; 202 } 203 if (!(credentials instanceof UsernamePasswordCredentials)) { 204 throw new AuthenticationException( 205 "Credentials cannot be used for basic authentication: " 206 + credentials.toString()); 207 } 208 String auth = BasicScheme.authenticate((UsernamePasswordCredentials) credentials); 209 if (auth != null) { 210 String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP; 211 method.setRequestHeader(s, auth); 212 return true; 213 } else { 214 return false; 215 } 216 } 217 218 219 /*** 220 * Attempt to provide default 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>Authenticate</tt> response header 231 * was added 232 * 233 * @throws AuthenticationException when a parsing or other error occurs 234 235 * @see HttpState#setCredentials(String,String,Credentials) 236 */ 237 public static boolean authenticateDefault( 238 HttpMethod method, 239 HttpConnection conn, 240 HttpState state) 241 throws AuthenticationException { 242 LOG.trace( 243 "enter HttpAuthenticator.authenticateDefault(HttpMethod, HttpConnection, HttpState)"); 244 return doAuthenticateDefault(method, conn, state, false); 245 } 246 247 248 /*** 249 * Attempt to provide default proxy authentication credentials 250 * to the given method in the given context using basic 251 * authentication scheme. 252 * 253 * @param method the HttpMethod which requires authentication 254 * @param conn the connection to a specific host. This parameter 255 * may be <tt>null</tt> if default credentials (not specific 256 * to any particular host) are to be used 257 * @param state the HttpState object providing Credentials 258 * 259 * @return true if the <tt>Proxy-Authenticate</tt> response header 260 * was added 261 * 262 * @throws AuthenticationException when a parsing or other error occurs 263 264 * @see HttpState#setCredentials(String,Credentials) 265 */ 266 public static boolean authenticateProxyDefault( 267 HttpMethod method, 268 HttpConnection conn, 269 HttpState state) 270 throws AuthenticationException { 271 LOG.trace("enter HttpAuthenticator.authenticateProxyDefault(HttpMethod, HttpState)"); 272 return doAuthenticateDefault(method, conn, state, true); 273 } 274 275 276 private static boolean doAuthenticate( 277 AuthScheme authscheme, 278 HttpMethod method, 279 HttpConnection conn, 280 HttpState state, 281 boolean proxy) 282 throws AuthenticationException { 283 if (authscheme == null) { 284 throw new IllegalArgumentException("Authentication scheme may not be null"); 285 } 286 if (method == null) { 287 throw new IllegalArgumentException("HTTP method may not be null"); 288 } 289 if (state == null) { 290 throw new IllegalArgumentException("HTTP state may not be null"); 291 } 292 String host = null; 293 if (conn != null) { 294 host = proxy ? conn.getProxyHost() : conn.getHost(); 295 } 296 String realm = authscheme.getRealm(); 297 // TODO: To be removed in the future. Required for backward compatibility 298 if (realm == null) { 299 Header hostheader = method.getRequestHeader("host"); 300 if (hostheader != null) { 301 realm = hostheader.getValue(); 302 } 303 } 304 if (LOG.isDebugEnabled()) { 305 if (realm == null) { 306 LOG.debug("Using default authentication realm"); 307 } else { 308 LOG.debug("Using '" + realm + "' authentication realm"); 309 } 310 } 311 Credentials credentials = proxy 312 ? state.getProxyCredentials(realm, host) 313 : state.getCredentials(realm, host); 314 if (credentials == null) { 315 throw new AuthenticationException( 316 "No credentials available for the " + authscheme.getSchemeName() 317 + "authentication realm '" + realm + "'"); 318 } 319 String auth = authscheme.authenticate(credentials, method.getName(), method.getPath()); 320 if (auth != null) { 321 String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP; 322 method.setRequestHeader(s, auth); 323 return true; 324 } else { 325 return false; 326 } 327 } 328 329 /*** 330 * Attempt to provide requisite authentication credentials to the 331 * given method in the given context using the given 332 * authentication scheme. 333 * 334 * @param authscheme The authentication scheme to be used 335 * @param method The HttpMethod which requires authentication 336 * @param conn the connection to a specific host. This parameter 337 * may be <tt>null</tt> if default credentials (not specific 338 * to any particular host) are to be used 339 * @param state The HttpState object providing Credentials 340 * 341 * @return true if the <tt>Authenticate</tt> response header was added 342 * 343 * @throws AuthenticationException when a parsing or other error occurs 344 345 * @see HttpState#setCredentials(String,Credentials) 346 */ 347 public static boolean authenticate( 348 AuthScheme authscheme, 349 HttpMethod method, 350 HttpConnection conn, 351 HttpState state) 352 throws AuthenticationException { 353 LOG.trace( 354 "enter HttpAuthenticator.authenticate(AuthScheme, HttpMethod, HttpConnection, " 355 + "HttpState)"); 356 return doAuthenticate(authscheme, method, conn, state, false); 357 } 358 359 360 /*** 361 * Attempt to provide requisite proxy authentication credentials 362 * to the given method in the given context using 363 * the given authentication scheme. 364 * 365 * @param authscheme The authentication scheme to be used 366 * @param method the HttpMethod which requires authentication 367 * @param conn the connection to a specific host. This parameter 368 * may be <tt>null</tt> if default credentials (not specific 369 * to any particular host) are to be used 370 * @param state the HttpState object providing Credentials 371 * 372 * @return true if the <tt>Proxy-Authenticate</tt> response header 373 * was added 374 * 375 * @throws AuthenticationException when a parsing or other error occurs 376 377 * @see HttpState#setCredentials(String,Credentials) 378 */ 379 public static boolean authenticateProxy( 380 AuthScheme authscheme, 381 HttpMethod method, 382 HttpConnection conn, 383 HttpState state 384 ) throws AuthenticationException { 385 LOG.trace("enter HttpAuthenticator.authenticateProxy(AuthScheme, HttpMethod, HttpState)"); 386 return doAuthenticate(authscheme, method, conn, state, true); 387 } 388 }

This page was automatically generated by Maven