/* * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/auth/HttpAuthenticator.java,v 1.19 2004/10/06 17:32:04 olegk Exp $ * $Revision: 480424 $ * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $ * * ==================================================================== * * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You 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 java.util.HashMap; import java.util.Map; import org.apache.commons.httpclient.Credentials; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.HttpConnection; import org.apache.commons.httpclient.HttpMethod; import org.apache.commons.httpclient.HttpState; import org.apache.commons.httpclient.UsernamePasswordCredentials; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Utility methods for HTTP authorization and authentication. This class * provides utility methods for generating responses to HTTP www and proxy * authentication challenges. * * <blockquote> * A client SHOULD assume that all paths at or deeper than the depth of the * last symbolic element in the path field of the Request-URI also are within * the protection space specified by the basic realm value of the current * challenge. A client MAY preemptively send the corresponding Authorization * header with requests for resources in that space without receipt of another * challenge from the server. Similarly, when a client sends a request to a * proxy, it may reuse a userid and password in the Proxy-Authorization header * field without receiving another challenge from the proxy server. * </blockquote> * </p> * * @author <a href="mailto:remm@apache.org">Remy Maucherat</a> * @author Rodney Waldhoff * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a> * @author Ortwin Gl�ck * @author Sean C. Sullivan * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a> * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a> * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a> * * @deprecated no longer used */ public final class HttpAuthenticator { /** Log object for this class. */ private static final Log LOG = LogFactory.getLog(HttpAuthenticator.class); /** * The www authenticate challange header. */ public static final String WWW_AUTH = "WWW-Authenticate"; /** * The www authenticate response header. */ public static final String WWW_AUTH_RESP = "Authorization"; /** * The proxy authenticate challange header. */ public static final String PROXY_AUTH = "Proxy-Authenticate"; /** * The proxy authenticate response header. */ public static final String PROXY_AUTH_RESP = "Proxy-Authorization"; /** Chooses the strongest authentication scheme supported from the * array of authentication challenges. Currently only <code>NTLM</code>, * <code>Digest</code>, <code>Basic</code> schemes are recognized. * The <code>NTLM</code> scheme is considered the strongest and is * preferred to all others. The <code>Digest</code> scheme is preferred to * the <code>Basic</code> one which provides no encryption for credentials. * The <code>Basic</code> scheme is used only if it is the only one * supported. * * @param challenges The array of authentication challenges * * @return The strongest authentication scheme supported * * @throws MalformedChallengeException is thrown if an authentication * challenge is malformed * @throws UnsupportedOperationException when none of challenge types * available is supported. * * @deprecated Use {@link AuthChallengeParser#parseChallenges(Header[])} and * {@link AuthPolicy#getAuthScheme(String)} */ public static AuthScheme selectAuthScheme(final Header[] challenges) throws MalformedChallengeException { LOG.trace("enter HttpAuthenticator.selectAuthScheme(Header[])"); if (challenges == null) { throw new IllegalArgumentException("Array of challenges may not be null"); } if (challenges.length == 0) { throw new IllegalArgumentException("Array of challenges may not be empty"); } String challenge = null; Map challengemap = new HashMap(challenges.length); for (int i = 0; i < challenges.length; i++) { challenge = challenges[i].getValue(); String s = AuthChallengeParser.extractScheme(challenge); challengemap.put(s, challenge); } challenge = (String) challengemap.get("ntlm"); if (challenge != null) { return new NTLMScheme(challenge); } challenge = (String) challengemap.get("digest"); if (challenge != null) { return new DigestScheme(challenge); } challenge = (String) challengemap.get("basic"); if (challenge != null) { return new BasicScheme(challenge); } throw new UnsupportedOperationException( "Authentication scheme(s) not supported: " + challengemap.toString()); } private static boolean doAuthenticateDefault( HttpMethod method, HttpConnection conn, HttpState state, boolean proxy) throws AuthenticationException { if (method == null) { throw new IllegalArgumentException("HTTP method may not be null"); } if (state == null) { throw new IllegalArgumentException("HTTP state may not be null"); } String host = null; if (conn != null) { host = proxy ? conn.getProxyHost() : conn.getHost(); } Credentials credentials = proxy ? state.getProxyCredentials(null, host) : state.getCredentials(null, host); if (credentials == null) { return false; } if (!(credentials instanceof UsernamePasswordCredentials)) { throw new InvalidCredentialsException( "Credentials cannot be used for basic authentication: " + credentials.toString()); } String auth = BasicScheme.authenticate( (UsernamePasswordCredentials) credentials, method.getParams().getCredentialCharset()); if (auth != null) { String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP; Header header = new Header(s, auth, true); method.addRequestHeader(header); return true; } else { return false; } } /** * Attempt to provide default authentication credentials * to the given method in the given context using basic * authentication scheme. * * @param method the HttpMethod which requires authentication * @param conn the connection to a specific host. This parameter * may be <tt>null</tt> if default credentials (not specific * to any particular host) are to be used * @param state the HttpState object providing Credentials * * @return true if the <tt>Authenticate</tt> response header * was added * * @throws InvalidCredentialsException if authentication credentials * are not valid or not applicable for basic scheme * @throws AuthenticationException when a parsing or other error occurs * * @see HttpState#setCredentials(String,String,Credentials) * * @deprecated use AuthScheme */ public static boolean authenticateDefault( HttpMethod method, HttpConnection conn, HttpState state) throws AuthenticationException { LOG.trace( "enter HttpAuthenticator.authenticateDefault(HttpMethod, HttpConnection, HttpState)"); return doAuthenticateDefault(method, conn, state, false); } /** * Attempt to provide default proxy authentication credentials * to the given method in the given context using basic * authentication scheme. * * @param method the HttpMethod which requires authentication * @param conn the connection to a specific host. This parameter * may be <tt>null</tt> if default credentials (not specific * to any particular host) are to be used * @param state the HttpState object providing Credentials * * @return true if the <tt>Proxy-Authenticate</tt> response header * was added * * @throws InvalidCredentialsException if authentication credentials * are not valid or not applicable for basic scheme * @throws AuthenticationException when a parsing or other error occurs * @see HttpState#setCredentials(String,String,Credentials) * * @deprecated use AuthScheme */ public static boolean authenticateProxyDefault( HttpMethod method, HttpConnection conn, HttpState state) throws AuthenticationException { LOG.trace("enter HttpAuthenticator.authenticateProxyDefault(HttpMethod, HttpState)"); return doAuthenticateDefault(method, conn, state, true); } private static boolean doAuthenticate( AuthScheme authscheme, HttpMethod method, HttpConnection conn, HttpState state, boolean proxy) throws AuthenticationException { if (authscheme == null) { throw new IllegalArgumentException("Authentication scheme may not be null"); } if (method == null) { throw new IllegalArgumentException("HTTP method may not be null"); } if (state == null) { throw new IllegalArgumentException("HTTP state may not be null"); } String host = null; if (conn != null) { if (proxy) { host = conn.getProxyHost(); } else { host = method.getParams().getVirtualHost(); if (host == null) { host = conn.getHost(); } } } String realm = authscheme.getRealm(); if (LOG.isDebugEnabled()) { StringBuffer buffer = new StringBuffer(); buffer.append("Using credentials for "); if (realm == null) { buffer.append("default"); } else { buffer.append('\''); buffer.append(realm); buffer.append('\''); } buffer.append(" authentication realm at "); buffer.append(host); LOG.debug(buffer.toString()); } Credentials credentials = proxy ? state.getProxyCredentials(realm, host) : state.getCredentials(realm, host); if (credentials == null) { StringBuffer buffer = new StringBuffer(); buffer.append("No credentials available for the "); if (realm == null) { buffer.append("default"); } else { buffer.append('\''); buffer.append(realm); buffer.append('\''); } buffer.append(" authentication realm at "); buffer.append(host); throw new CredentialsNotAvailableException(buffer.toString()); } String auth = authscheme.authenticate(credentials, method); if (auth != null) { String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP; Header header = new Header(s, auth, true); method.addRequestHeader(header); return true; } else { return false; } } /** * Attempt to provide requisite authentication credentials to the * given method in the given context using the given * authentication scheme. * * @param authscheme The authentication scheme to be used * @param method The HttpMethod which requires authentication * @param conn the connection to a specific host. This parameter * may be <tt>null</tt> if default credentials (not specific * to any particular host) are to be used * @param state The HttpState object providing Credentials * * @return true if the <tt>Authenticate</tt> response header was added * * @throws CredentialsNotAvailableException if authentication credentials * required to respond to the authentication challenge are not available * @throws AuthenticationException when a parsing or other error occurs * @see HttpState#setCredentials(String,String,Credentials) * * @deprecated use AuthScheme */ public static boolean authenticate( AuthScheme authscheme, HttpMethod method, HttpConnection conn, HttpState state) throws AuthenticationException { LOG.trace( "enter HttpAuthenticator.authenticate(AuthScheme, HttpMethod, HttpConnection, " + "HttpState)"); return doAuthenticate(authscheme, method, conn, state, false); } /** * Attempt to provide requisite proxy authentication credentials * to the given method in the given context using * the given authentication scheme. * * @param authscheme The authentication scheme to be used * @param method the HttpMethod which requires authentication * @param conn the connection to a specific host. This parameter * may be <tt>null</tt> if default credentials (not specific * to any particular host) are to be used * @param state the HttpState object providing Credentials * * @return true if the <tt>Proxy-Authenticate</tt> response header * was added * * @throws CredentialsNotAvailableException if authentication credentials * required to respond to the authentication challenge are not available * @throws AuthenticationException when a parsing or other error occurs * @see HttpState#setCredentials(String,String,Credentials) * * @deprecated use AuthScheme */ public static boolean authenticateProxy( AuthScheme authscheme, HttpMethod method, HttpConnection conn, HttpState state ) throws AuthenticationException { LOG.trace("enter HttpAuthenticator.authenticateProxy(AuthScheme, HttpMethod, HttpState)"); return doAuthenticate(authscheme, method, conn, state, true); } }