View Javadoc

    1   /*
    2    * $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 $
    3    * $Revision: 480424 $
    4    * $Date: 2006-11-29 06:56:49 +0100 (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.auth;
    32
    33  import java.util.HashMap;
    34  import java.util.Map;
    35
    36  import org.apache.commons.httpclient.Credentials;
    37  import org.apache.commons.httpclient.Header;
    38  import org.apache.commons.httpclient.HttpConnection;
    39  import org.apache.commons.httpclient.HttpMethod;
    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   * @deprecated no longer used
    72   */
    73  public final class HttpAuthenticator {
    74
    75      /** Log object for this class. */
    76      private static final Log LOG = LogFactory.getLog(HttpAuthenticator.class);
    77
    78      /**
    79       * The www authenticate challange header.
    80       */
    81      public static final String WWW_AUTH = "WWW-Authenticate";
    82
    83      /**
    84       * The www authenticate response header.
    85       */
    86      public static final String WWW_AUTH_RESP = "Authorization";
    87
    88      /**
    89       * The proxy authenticate challange header.
    90       */
    91      public static final String PROXY_AUTH = "Proxy-Authenticate";
    92
    93      /**
    94       * The proxy authenticate response header.
    95       */
    96      public static final String PROXY_AUTH_RESP = "Proxy-Authorization";
    97
    98      /** Chooses the strongest authentication scheme supported from the
    99       * array of authentication challenges. Currently only <code>NTLM</code>,
    100      * <code>Digest</code>, <code>Basic</code> schemes are recognized.
    101      * The <code>NTLM</code> scheme is considered the strongest and is
    102      * preferred to all others. The <code>Digest</code> scheme is preferred to
    103      * the <code>Basic</code> one which provides no encryption for credentials.
    104      * The <code>Basic</code> scheme is used only if it is the only one
    105      * supported.
    106      *
    107      * @param challenges The array of authentication challenges
    108      *
    109      * @return The strongest authentication scheme supported
    110      *
    111      * @throws MalformedChallengeException is thrown if an authentication
    112      *  challenge is malformed
    113      * @throws UnsupportedOperationException when none of challenge types
    114      *  available is supported.
    115      *
    116      * @deprecated Use {@link AuthChallengeParser#parseChallenges(Header[])} and
    117      *      {@link AuthPolicy#getAuthScheme(String)}
    118      */
    119     public static AuthScheme selectAuthScheme(final Header[] challenges)
    120       throws MalformedChallengeException {
    121         LOG.trace("enter HttpAuthenticator.selectAuthScheme(Header[])");
    122         if (challenges == null) {
    123             throw new IllegalArgumentException("Array of challenges may not be null");
    124         }
    125         if (challenges.length == 0) {
    126             throw new IllegalArgumentException("Array of challenges may not be empty");
    127         }
    128         String challenge = null;
    129         Map challengemap = new HashMap(challenges.length);
    130         for (int i = 0; i < challenges.length; i++) {
    131             challenge = challenges[i].getValue();
    132             String s = AuthChallengeParser.extractScheme(challenge);
    133             challengemap.put(s, challenge);
    134         }
    135         challenge = (String) challengemap.get("ntlm");
    136         if (challenge != null) {
    137             return new NTLMScheme(challenge);
    138         }
    139         challenge = (String) challengemap.get("digest");
    140         if (challenge != null) {
    141             return new DigestScheme(challenge);
    142         }
    143         challenge = (String) challengemap.get("basic");
    144         if (challenge != null) {
    145             return new BasicScheme(challenge);
    146         }
    147         throw new UnsupportedOperationException(
    148           "Authentication scheme(s) not supported: " + challengemap.toString());
    149     }
    150
    151     private static boolean doAuthenticateDefault(
    152         HttpMethod method,
    153         HttpConnection conn,
    154         HttpState state,
    155         boolean proxy)
    156       throws AuthenticationException {
    157         if (method == null) {
    158             throw new IllegalArgumentException("HTTP method may not be null");
    159         }
    160         if (state == null) {
    161             throw new IllegalArgumentException("HTTP state may not be null");
    162         }
    163         String host = null;
    164         if (conn != null) {
    165             host = proxy ? conn.getProxyHost() : conn.getHost();
    166         }
    167         Credentials credentials = proxy
    168             ? state.getProxyCredentials(null, host) : state.getCredentials(null, host);
    169         if (credentials == null) {
    170             return false;
    171         }
    172         if (!(credentials instanceof UsernamePasswordCredentials)) {
    173             throw new InvalidCredentialsException(
    174              "Credentials cannot be used for basic authentication: "
    175               + credentials.toString());
    176         }
    177         String auth = BasicScheme.authenticate(
    178             (UsernamePasswordCredentials) credentials,
    179             method.getParams().getCredentialCharset());
    180         if (auth != null) {
    181             String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP;
    182             Header header = new Header(s, auth, true);
    183             method.addRequestHeader(header);
    184             return true;
    185         } else {
    186             return false;
    187         }
    188     }
    189
    190
    191     /**
    192      * Attempt to provide default authentication credentials
    193      * to the given method in the given context using basic
    194      * authentication scheme.
    195      *
    196      * @param method the HttpMethod which requires authentication
    197      * @param conn the connection to a specific host. This parameter
    198      *   may be <tt>null</tt> if default credentials (not specific
    199      *   to any particular host) are to be used
    200      * @param state the HttpState object providing Credentials
    201      *
    202      * @return true if the <tt>Authenticate</tt> response header
    203      *   was added
    204      *
    205      * @throws InvalidCredentialsException if authentication credentials
    206      *         are not valid or not applicable for basic scheme
    207      * @throws AuthenticationException when a parsing or other error occurs
    208      *
    209      * @see HttpState#setCredentials(String,String,Credentials)
    210      *
    211      * @deprecated use AuthScheme
    212      */
    213     public static boolean authenticateDefault(
    214         HttpMethod method,
    215         HttpConnection conn,
    216         HttpState state)
    217       throws AuthenticationException {
    218         LOG.trace(
    219             "enter HttpAuthenticator.authenticateDefault(HttpMethod, HttpConnection, HttpState)");
    220         return doAuthenticateDefault(method, conn, state, false);
    221     }
    222
    223
    224     /**
    225      * Attempt to provide default proxy authentication credentials
    226      * to the given method in the given context using basic
    227      * authentication scheme.
    228      *
    229      * @param method the HttpMethod which requires authentication
    230      * @param conn the connection to a specific host. This parameter
    231      *   may be <tt>null</tt> if default credentials (not specific
    232      *   to any particular host) are to be used
    233      * @param state the HttpState object providing Credentials
    234      *
    235      * @return true if the <tt>Proxy-Authenticate</tt> response header
    236      *   was added
    237      *
    238      * @throws InvalidCredentialsException if authentication credentials
    239      *         are not valid or not applicable for basic scheme
    240      * @throws AuthenticationException when a parsing or other error occurs
    241
    242      * @see HttpState#setCredentials(String,String,Credentials)
    243      *
    244      * @deprecated use AuthScheme
    245      */
    246     public static boolean authenticateProxyDefault(
    247         HttpMethod method,
    248         HttpConnection conn,
    249         HttpState state)
    250       throws AuthenticationException {
    251         LOG.trace("enter HttpAuthenticator.authenticateProxyDefault(HttpMethod, HttpState)");
    252         return doAuthenticateDefault(method, conn, state, true);
    253     }
    254
    255
    256     private static boolean doAuthenticate(
    257         AuthScheme authscheme,
    258         HttpMethod method,
    259         HttpConnection conn,
    260         HttpState state,
    261         boolean proxy)
    262        throws AuthenticationException {
    263         if (authscheme == null) {
    264             throw new IllegalArgumentException("Authentication scheme may not be null");
    265         }
    266         if (method == null) {
    267             throw new IllegalArgumentException("HTTP method may not be null");
    268         }
    269         if (state == null) {
    270             throw new IllegalArgumentException("HTTP state may not be null");
    271         }
    272         String host = null;
    273         if (conn != null) {
    274             if (proxy) {
    275                 host = conn.getProxyHost();
    276             } else {
    277                 host = method.getParams().getVirtualHost();
    278                 if (host == null) {
    279                     host = conn.getHost();
    280                 }
    281             }
    282         }
    283         String realm = authscheme.getRealm();
    284         if (LOG.isDebugEnabled()) {
    285             StringBuffer buffer = new StringBuffer();
    286             buffer.append("Using credentials for ");
    287             if (realm == null) {
    288                 buffer.append("default");
    289             } else {
    290                 buffer.append('\'');
    291                 buffer.append(realm);
    292                 buffer.append('\'');
    293             }
    294             buffer.append(" authentication realm at ");
    295             buffer.append(host);
    296             LOG.debug(buffer.toString());
    297         }
    298         Credentials credentials = proxy
    299             ? state.getProxyCredentials(realm, host)
    300             : state.getCredentials(realm, host);
    301         if (credentials == null) {
    302             StringBuffer buffer = new StringBuffer();
    303             buffer.append("No credentials available for the ");
    304             if (realm == null) {
    305                 buffer.append("default");
    306             } else {
    307                 buffer.append('\'');
    308                 buffer.append(realm);
    309                 buffer.append('\'');
    310             }
    311             buffer.append(" authentication realm at ");
    312             buffer.append(host);
    313             throw new CredentialsNotAvailableException(buffer.toString());
    314         }
    315         String auth = authscheme.authenticate(credentials, method);
    316         if (auth != null) {
    317             String s = proxy ? PROXY_AUTH_RESP : WWW_AUTH_RESP;
    318             Header header = new Header(s, auth, true);
    319             method.addRequestHeader(header);
    320             return true;
    321         } else {
    322             return false;
    323         }
    324     }
    325
    326     /**
    327      * Attempt to provide requisite authentication credentials to the
    328      * given method in the given context using the given
    329      * authentication scheme.
    330      *
    331      * @param authscheme The authentication scheme to be used
    332      * @param method The HttpMethod which requires authentication
    333      * @param conn the connection to a specific host. This parameter
    334      *   may be <tt>null</tt> if default credentials (not specific
    335      *   to any particular host) are to be used
    336      * @param state The HttpState object providing Credentials
    337      *
    338      * @return true if the <tt>Authenticate</tt> response header was added
    339      *
    340      * @throws CredentialsNotAvailableException if authentication credentials
    341      *         required to respond to the authentication challenge are not available
    342      * @throws AuthenticationException when a parsing or other error occurs
    343
    344      * @see HttpState#setCredentials(String,String,Credentials)
    345      *
    346      * @deprecated use AuthScheme
    347      */
    348     public static boolean authenticate(
    349         AuthScheme authscheme,
    350         HttpMethod method,
    351         HttpConnection conn,
    352         HttpState state)
    353         throws AuthenticationException {
    354        LOG.trace(
    355             "enter HttpAuthenticator.authenticate(AuthScheme, HttpMethod, HttpConnection, "
    356             + "HttpState)");
    357         return doAuthenticate(authscheme, method, conn, state, false);
    358     }
    359
    360
    361     /**
    362      * Attempt to provide requisite proxy authentication credentials
    363      * to the given method in the given context using
    364      * the given authentication scheme.
    365      *
    366      * @param authscheme The authentication scheme to be used
    367      * @param method the HttpMethod which requires authentication
    368      * @param conn the connection to a specific host. This parameter
    369      *   may be <tt>null</tt> if default credentials (not specific
    370      *   to any particular host) are to be used
    371      * @param state the HttpState object providing Credentials
    372      *
    373      * @return true if the <tt>Proxy-Authenticate</tt> response header
    374      *  was added
    375      *
    376      * @throws CredentialsNotAvailableException if authentication credentials
    377      *         required to respond to the authentication challenge are not available
    378      * @throws AuthenticationException when a parsing or other error occurs
    379
    380      * @see HttpState#setCredentials(String,String,Credentials)
    381      *
    382      * @deprecated use AuthScheme
    383      */
    384     public static boolean authenticateProxy(
    385         AuthScheme authscheme,
    386         HttpMethod method,
    387         HttpConnection conn,
    388         HttpState state
    389     ) throws AuthenticationException {
    390        LOG.trace("enter HttpAuthenticator.authenticateProxy(AuthScheme, HttpMethod, HttpState)");
    391        return doAuthenticate(authscheme, method, conn, state, true);
    392     }
    393 }