View Javadoc
1 /* 2 * $Header: /home/cvs/jakarta-commons/httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v 1.7.2.2 2003/08/09 18:20:34 olegk Exp $ 3 * $Revision: 1.7.2.2 $ 4 * $Date: 2003/08/09 18:20:34 $ 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 if (proxy) { 295 host = conn.getProxyHost(); 296 } else { 297 host = conn.getVirtualHost(); 298 if (host == null) { 299 host = conn.getHost(); 300 } 301 } 302 } 303 String realm = authscheme.getRealm(); 304 if (LOG.isDebugEnabled()) { 305 StringBuffer buffer = new StringBuffer(); 306 buffer.append("Authenticating with the "); 307 if (realm == null) { 308 buffer.append("default"); 309 } else { 310 buffer.append('\''); 311 buffer.append(realm); 312 buffer.append('\''); 313 } 314 buffer.append(" authentication realm at "); 315 buffer.append(host); 316 LOG.debug(buffer.toString()); 317 } 318 // TODO: To be removed in the future. Required for backward compatibility 319 if (realm == null) { 320 realm = host; 321 } 322 Credentials credentials = proxy 323 ? state.getProxyCredentials(realm, host) 324 : state.getCredentials(realm, host); 325 if (credentials == null) { 326 throw new AuthenticationException( 327 "No credentials available for the '" + authscheme.getRealm() 328 + "' authentication realm at " + host); 329 } 330 String auth = authscheme.authenticate(credentials, method.getName(), method.getPath()); 331 if (auth != null) { 332 String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP; 333 method.setRequestHeader(s, auth); 334 return true; 335 } else { 336 return false; 337 } 338 } 339 340 /*** 341 * Attempt to provide requisite authentication credentials to the 342 * given method in the given context using the given 343 * authentication scheme. 344 * 345 * @param authscheme The authentication scheme to be used 346 * @param method The HttpMethod which requires authentication 347 * @param conn the connection to a specific host. This parameter 348 * may be <tt>null</tt> if default credentials (not specific 349 * to any particular host) are to be used 350 * @param state The HttpState object providing Credentials 351 * 352 * @return true if the <tt>Authenticate</tt> response header was added 353 * 354 * @throws AuthenticationException when a parsing or other error occurs 355 356 * @see HttpState#setCredentials(String,Credentials) 357 */ 358 public static boolean authenticate( 359 AuthScheme authscheme, 360 HttpMethod method, 361 HttpConnection conn, 362 HttpState state) 363 throws AuthenticationException { 364 LOG.trace( 365 "enter HttpAuthenticator.authenticate(AuthScheme, HttpMethod, HttpConnection, " 366 + "HttpState)"); 367 return doAuthenticate(authscheme, method, conn, state, false); 368 } 369 370 371 /*** 372 * Attempt to provide requisite proxy authentication credentials 373 * to the given method in the given context using 374 * the given authentication scheme. 375 * 376 * @param authscheme The authentication scheme to be used 377 * @param method the HttpMethod which requires authentication 378 * @param conn the connection to a specific host. This parameter 379 * may be <tt>null</tt> if default credentials (not specific 380 * to any particular host) are to be used 381 * @param state the HttpState object providing Credentials 382 * 383 * @return true if the <tt>Proxy-Authenticate</tt> response header 384 * was added 385 * 386 * @throws AuthenticationException when a parsing or other error occurs 387 388 * @see HttpState#setCredentials(String,Credentials) 389 */ 390 public static boolean authenticateProxy( 391 AuthScheme authscheme, 392 HttpMethod method, 393 HttpConnection conn, 394 HttpState state 395 ) throws AuthenticationException { 396 LOG.trace("enter HttpAuthenticator.authenticateProxy(AuthScheme, HttpMethod, HttpState)"); 397 return doAuthenticate(authscheme, method, conn, state, true); 398 } 399 }

This page was automatically generated by Maven