View Javadoc

1   /*
2    * ====================================================================
3    *
4    *  Licensed to the Apache Software Foundation (ASF) under one or more
5    *  contributor license agreements.  See the NOTICE file distributed with
6    *  this work for additional information regarding copyright ownership.
7    *  The ASF licenses this file to You under the Apache License, Version 2.0
8    *  (the "License"); you may not use this file except in compliance with
9    *  the License.  You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   *  Unless required by applicable law or agreed to in writing, software
14   *  distributed under the License is distributed on an "AS IS" BASIS,
15   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   *  See the License for the specific language governing permissions and
17   *  limitations under the License.
18   * ====================================================================
19   *
20   * This software consists of voluntary contributions made by many
21   * individuals on behalf of the Apache Software Foundation.  For more
22   * information on the Apache Software Foundation, please see
23   * <http://www.apache.org/>.
24   *
25   */
26  
27  package org.apache.http.impl.auth;
28  
29  import org.apache.http.annotation.NotThreadSafe;
30  
31  import org.apache.http.Header;
32  import org.apache.http.HttpRequest;
33  import org.apache.http.auth.AUTH;
34  import org.apache.http.auth.AuthenticationException;
35  import org.apache.http.auth.Credentials;
36  import org.apache.http.auth.InvalidCredentialsException;
37  import org.apache.http.auth.MalformedChallengeException;
38  import org.apache.http.auth.NTCredentials;
39  import org.apache.http.impl.auth.AuthSchemeBase;
40  import org.apache.http.message.BufferedHeader;
41  import org.apache.http.util.CharArrayBuffer;
42  
43  /**
44   * NTLM is a proprietary authentication scheme developed by Microsoft
45   * and optimized for Windows platforms.
46   *
47   * @since 4.0
48   */
49  @NotThreadSafe
50  public class NTLMScheme extends AuthSchemeBase {
51  
52      enum State {
53          UNINITIATED,
54          CHALLENGE_RECEIVED,
55          MSG_TYPE1_GENERATED,
56          MSG_TYPE2_RECEVIED,
57          MSG_TYPE3_GENERATED,
58          FAILED,
59      }
60  
61      private final NTLMEngine engine;
62  
63      private State state;
64      private String challenge;
65  
66      public NTLMScheme(final NTLMEngine engine) {
67          super();
68          if (engine == null) {
69              throw new IllegalArgumentException("NTLM engine may not be null");
70          }
71          this.engine = engine;
72          this.state = State.UNINITIATED;
73          this.challenge = null;
74      }
75  
76      public String getSchemeName() {
77          return "ntlm";
78      }
79  
80      public String getParameter(String name) {
81          // String parameters not supported
82          return null;
83      }
84  
85      public String getRealm() {
86          // NTLM does not support the concept of an authentication realm
87          return null;
88      }
89  
90      public boolean isConnectionBased() {
91          return true;
92      }
93  
94      @Override
95      protected void parseChallenge(
96              final CharArrayBuffer buffer,
97              int beginIndex, int endIndex) throws MalformedChallengeException {
98          String challenge = buffer.substringTrimmed(beginIndex, endIndex);
99          if (challenge.length() == 0) {
100             if (this.state == State.UNINITIATED) {
101                 this.state = State.CHALLENGE_RECEIVED;
102             } else {
103                 this.state = State.FAILED;
104             }
105             this.challenge = null;
106         } else {
107             this.state = State.MSG_TYPE2_RECEVIED;
108             this.challenge = challenge;
109         }
110     }
111 
112     public Header authenticate(
113             final Credentials credentials,
114             final HttpRequest request) throws AuthenticationException {
115         NTCredentials ntcredentials = null;
116         try {
117             ntcredentials = (NTCredentials) credentials;
118         } catch (ClassCastException e) {
119             throw new InvalidCredentialsException(
120              "Credentials cannot be used for NTLM authentication: "
121               + credentials.getClass().getName());
122         }
123         String response = null;
124         if (this.state == State.CHALLENGE_RECEIVED || this.state == State.FAILED) {
125             response = this.engine.generateType1Msg(
126                     ntcredentials.getDomain(),
127                     ntcredentials.getWorkstation());
128             this.state = State.MSG_TYPE1_GENERATED;
129         } else if (this.state == State.MSG_TYPE2_RECEVIED) {
130             response = this.engine.generateType3Msg(
131                     ntcredentials.getUserName(),
132                     ntcredentials.getPassword(),
133                     ntcredentials.getDomain(),
134                     ntcredentials.getWorkstation(),
135                     this.challenge);
136             this.state = State.MSG_TYPE3_GENERATED;
137         } else {
138             throw new AuthenticationException("Unexpected state: " + this.state);
139         }
140         CharArrayBuffer buffer = new CharArrayBuffer(32);
141         if (isProxy()) {
142             buffer.append(AUTH.PROXY_AUTH_RESP);
143         } else {
144             buffer.append(AUTH.WWW_AUTH_RESP);
145         }
146         buffer.append(": NTLM ");
147         buffer.append(response);
148         return new BufferedHeader(buffer);
149     }
150 
151     public boolean isComplete() {
152         return this.state == State.MSG_TYPE3_GENERATED || this.state == State.FAILED;
153     }
154 
155 }