View Javadoc

    1   /*
    2    * $Header: /home/jerenkrantz/tmp/commons/commons-convert/cvs/home/cvs/jakarta-commons//httpclient/src/java/org/apache/commons/httpclient/auth/NTLMScheme.java,v 1.21 2004/05/13 04:02:00 mbecke 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 org.apache.commons.httpclient.Credentials;
    34  import org.apache.commons.httpclient.HttpMethod;
    35  import org.apache.commons.httpclient.NTCredentials;
    36  import org.apache.commons.logging.Log;
    37  import org.apache.commons.logging.LogFactory;
    38
    39  /** An implementation of the Microsoft proprietary NTLM authentication scheme.  For a detailed
    40   * explanation of the NTLM scheme please see <a href="http://davenport.sourceforge.net/ntlm.html">
    41   * http://davenport.sourceforge.net/ntlm.html</a>.
    42   *
    43   * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
    44   * @author Rodney Waldhoff
    45   * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
    46   * @author Ortwin Gl???ck
    47   * @author Sean C. Sullivan
    48   * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
    49   * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
    50   * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
    51   */
    52  public class NTLMScheme implements AuthScheme {
    53
    54      /** Log object for this class. */
    55      private static final Log LOG = LogFactory.getLog(NTLMScheme.class);
    56
    57      /** NTLM challenge string. */
    58      private String ntlmchallenge = null;
    59
    60      private static final int UNINITIATED         = 0;
    61      private static final int INITIATED           = 1;
    62      private static final int TYPE1_MSG_GENERATED = 2;
    63      private static final int TYPE2_MSG_RECEIVED  = 3;
    64      private static final int TYPE3_MSG_GENERATED = 4;
    65      private static final int FAILED              = Integer.MAX_VALUE;
    66
    67      /** Authentication process state */
    68      private int state;
    69
    70      /**
    71       * Default constructor for the NTLM authentication scheme.
    72       *
    73       * @since 3.0
    74       */
    75      public NTLMScheme() {
    76          super();
    77          this.state = UNINITIATED;
    78      }
    79
    80      /**
    81       * Constructor for the NTLM authentication scheme.
    82       *
    83       * @param challenge The authentication challenge
    84       *
    85       * @throws MalformedChallengeException is thrown if the authentication challenge
    86       * is malformed
    87       */
    88      public NTLMScheme(final String challenge) throws MalformedChallengeException {
    89          super();
    90          processChallenge(challenge);
    91      }
    92
    93      /**
    94       * Processes the NTLM challenge.
    95       *
    96       * @param challenge the challenge string
    97       *
    98       * @throws MalformedChallengeException is thrown if the authentication challenge
    99       * is malformed
    100      *
    101      * @since 3.0
    102      */
    103     public void processChallenge(final String challenge) throws MalformedChallengeException {
    104         String s = AuthChallengeParser.extractScheme(challenge);
    105         if (!s.equalsIgnoreCase(getSchemeName())) {
    106             throw new MalformedChallengeException("Invalid NTLM challenge: " + challenge);
    107         }
    108         int i = challenge.indexOf(' ');
    109         if (i != -1) {
    110             s = challenge.substring(i, challenge.length());
    111             this.ntlmchallenge = s.trim();
    112             this.state = TYPE2_MSG_RECEIVED;
    113         } else {
    114             this.ntlmchallenge = "";
    115             if (this.state == UNINITIATED) {
    116                 this.state = INITIATED;
    117             } else {
    118                 this.state = FAILED;
    119             }
    120         }
    121     }
    122
    123     /**
    124      * Tests if the NTLM authentication process has been completed.
    125      *
    126      * @return <tt>true</tt> if Basic authorization has been processed,
    127      *   <tt>false</tt> otherwise.
    128      *
    129      * @since 3.0
    130      */
    131     public boolean isComplete() {
    132         return this.state == TYPE3_MSG_GENERATED || this.state == FAILED;
    133     }
    134
    135     /**
    136      * Returns textual designation of the NTLM authentication scheme.
    137      *
    138      * @return <code>ntlm</code>
    139      */
    140     public String getSchemeName() {
    141         return "ntlm";
    142     }
    143
    144     /**
    145      * The concept of an authentication realm is not supported by the NTLM
    146      * authentication scheme. Always returns <code>null</code>.
    147      *
    148      * @return <code>null</code>
    149      */
    150     public String getRealm() {
    151         return null;
    152     }
    153
    154     /**
    155      * Returns a String identifying the authentication challenge.  This is
    156      * used, in combination with the host and port to determine if
    157      * authorization has already been attempted or not.  Schemes which
    158      * require multiple requests to complete the authentication should
    159      * return a different value for each stage in the request.
    160      *
    161      * <p>Additionally, the ID should take into account any changes to the
    162      * authentication challenge and return a different value when appropriate.
    163      * For example when the realm changes in basic authentication it should be
    164      * considered a different authentication attempt and a different value should
    165      * be returned.</p>
    166      *
    167      * @return String a String identifying the authentication challenge.  The
    168      * returned value may be null.
    169      *
    170      * @deprecated no longer used
    171      */
    172     public String getID() {
    173         return ntlmchallenge;
    174     }
    175
    176     /**
    177      * Returns the authentication parameter with the given name, if available.
    178      *
    179      * <p>There are no valid parameters for NTLM authentication so this method always returns
    180      * <tt>null</tt>.</p>
    181      *
    182      * @param name The name of the parameter to be returned
    183      *
    184      * @return the parameter with the given name
    185      */
    186     public String getParameter(String name) {
    187         if (name == null) {
    188             throw new IllegalArgumentException("Parameter name may not be null");
    189         }
    190         return null;
    191     }
    192
    193     /**
    194      * Returns <tt>true</tt>. NTLM authentication scheme is connection based.
    195      *
    196      * @return <tt>true</tt>.
    197      *
    198      * @since 3.0
    199      */
    200     public boolean isConnectionBased() {
    201         return true;
    202     }
    203
    204     /**
    205      * Create a NTLM authorization string for the given
    206      * challenge and NT credentials.
    207      *
    208      * @param challenge The challenge.
    209      * @param credentials {@link NTCredentials}
    210      *
    211      * @return a ntlm authorization string
    212      * @throws AuthenticationException is thrown if authentication fails
    213      *
    214      * @deprecated Use non-static {@link #authenticate(Credentials, HttpMethod)}
    215      */
    216     public static String authenticate(
    217      final NTCredentials credentials, final String challenge)
    218       throws AuthenticationException {
    219
    220         LOG.trace("enter NTLMScheme.authenticate(NTCredentials, String)");
    221
    222         if (credentials == null) {
    223             throw new IllegalArgumentException("Credentials may not be null");
    224         }
    225
    226         NTLM ntlm = new NTLM();
    227         String s = ntlm.getResponseFor(challenge,
    228         credentials.getUserName(), credentials.getPassword(),
    229         credentials.getHost(), credentials.getDomain());
    230         return "NTLM " + s;
    231     }
    232
    233     /**
    234      * Create a NTLM authorization string for the given
    235      * challenge and NT credentials.
    236      *
    237      * @param challenge The challenge.
    238      * @param credentials {@link NTCredentials}
    239      * @param charset The charset to use for encoding the credentials
    240      *
    241      * @return a ntlm authorization string
    242      * @throws AuthenticationException is thrown if authentication fails
    243      *
    244      * @deprecated Use non-static {@link #authenticate(Credentials, HttpMethod)}
    245      *
    246      * @since 3.0
    247      */
    248     public static String authenticate(
    249         final NTCredentials credentials,
    250 		final String challenge,
    251 		String charset
    252     ) throws AuthenticationException {
    253
    254         LOG.trace("enter NTLMScheme.authenticate(NTCredentials, String)");
    255
    256         if (credentials == null) {
    257             throw new IllegalArgumentException("Credentials may not be null");
    258         }
    259
    260         NTLM ntlm = new NTLM();
    261         ntlm.setCredentialCharset(charset);
    262         String s = ntlm.getResponseFor(
    263             challenge,
    264             credentials.getUserName(),
    265 			credentials.getPassword(),
    266 			credentials.getHost(),
    267 			credentials.getDomain());
    268         return "NTLM " + s;
    269     }
    270
    271     /**
    272      * Produces NTLM authorization string for the given set of
    273      * {@link Credentials}.
    274      *
    275      * @param credentials The set of credentials to be used for athentication
    276      * @param method Method name is ignored by the NTLM authentication scheme
    277      * @param uri URI is ignored by the NTLM authentication scheme
    278      * @throws InvalidCredentialsException if authentication credentials
    279      *         are not valid or not applicable for this authentication scheme
    280      * @throws AuthenticationException if authorization string cannot
    281      *   be generated due to an authentication failure
    282      *
    283      * @return an NTLM authorization string
    284      *
    285      * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
    286      */
    287     public String authenticate(Credentials credentials, String method, String uri)
    288       throws AuthenticationException {
    289         LOG.trace("enter NTLMScheme.authenticate(Credentials, String, String)");
    290
    291         NTCredentials ntcredentials = null;
    292         try {
    293             ntcredentials = (NTCredentials) credentials;
    294         } catch (ClassCastException e) {
    295             throw new InvalidCredentialsException(
    296              "Credentials cannot be used for NTLM authentication: "
    297               + credentials.getClass().getName());
    298         }
    299         return NTLMScheme.authenticate(ntcredentials, this.ntlmchallenge);
    300     }
    301
    302     /**
    303      * Produces NTLM authorization string for the given set of
    304      * {@link Credentials}.
    305      *
    306      * @param credentials The set of credentials to be used for athentication
    307      * @param method The method being authenticated
    308      *
    309      * @throws InvalidCredentialsException if authentication credentials
    310      *         are not valid or not applicable for this authentication scheme
    311      * @throws AuthenticationException if authorization string cannot
    312      *   be generated due to an authentication failure
    313      *
    314      * @return an NTLM authorization string
    315      *
    316      * @since 3.0
    317      */
    318     public String authenticate(
    319         Credentials credentials,
    320         HttpMethod method
    321     ) throws AuthenticationException {
    322         LOG.trace("enter NTLMScheme.authenticate(Credentials, HttpMethod)");
    323
    324         if (this.state == UNINITIATED) {
    325             throw new IllegalStateException("NTLM authentication process has not been initiated");
    326         }
    327
    328         NTCredentials ntcredentials = null;
    329         try {
    330             ntcredentials = (NTCredentials) credentials;
    331         } catch (ClassCastException e) {
    332             throw new InvalidCredentialsException(
    333                     "Credentials cannot be used for NTLM authentication: "
    334                     + credentials.getClass().getName());
    335         }
    336         NTLM ntlm = new NTLM();
    337         ntlm.setCredentialCharset(method.getParams().getCredentialCharset());
    338         String response = null;
    339         if (this.state == INITIATED || this.state == FAILED) {
    340             response = ntlm.getType1Message(
    341                 ntcredentials.getHost(),
    342                 ntcredentials.getDomain());
    343             this.state = TYPE1_MSG_GENERATED;
    344         } else {
    345             response = ntlm.getType3Message(
    346                 ntcredentials.getUserName(),
    347                 ntcredentials.getPassword(),
    348                 ntcredentials.getHost(),
    349                 ntcredentials.getDomain(),
    350                 ntlm.parseType2Message(this.ntlmchallenge));
    351             this.state = TYPE3_MSG_GENERATED;
    352         }
    353         return "NTLM " + response;
    354     }
    355 }