001: /*
002: * $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 $
003: * $Revision: 480424 $
004: * $Date: 2006-11-29 06:56:49 +0100 (Wed, 29 Nov 2006) $
005: *
006: * ====================================================================
007: *
008: * Licensed to the Apache Software Foundation (ASF) under one or more
009: * contributor license agreements. See the NOTICE file distributed with
010: * this work for additional information regarding copyright ownership.
011: * The ASF licenses this file to You under the Apache License, Version 2.0
012: * (the "License"); you may not use this file except in compliance with
013: * the License. You may obtain a copy of the License at
014: *
015: * http://www.apache.org/licenses/LICENSE-2.0
016: *
017: * Unless required by applicable law or agreed to in writing, software
018: * distributed under the License is distributed on an "AS IS" BASIS,
019: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
020: * See the License for the specific language governing permissions and
021: * limitations under the License.
022: * ====================================================================
023: *
024: * This software consists of voluntary contributions made by many
025: * individuals on behalf of the Apache Software Foundation. For more
026: * information on the Apache Software Foundation, please see
027: * <http://www.apache.org/>.
028: *
029: */
030:
031: package org.apache.commons.httpclient.auth;
032:
033: import org.apache.commons.httpclient.Credentials;
034: import org.apache.commons.httpclient.HttpMethod;
035: import org.apache.commons.httpclient.NTCredentials;
036: import org.apache.commons.logging.Log;
037: import org.apache.commons.logging.LogFactory;
038:
039: /** An implementation of the Microsoft proprietary NTLM authentication scheme. For a detailed
040: * explanation of the NTLM scheme please see <a href="http://davenport.sourceforge.net/ntlm.html">
041: * http://davenport.sourceforge.net/ntlm.html</a>.
042: *
043: * @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
044: * @author Rodney Waldhoff
045: * @author <a href="mailto:jsdever@apache.org">Jeff Dever</a>
046: * @author Ortwin Gl???ck
047: * @author Sean C. Sullivan
048: * @author <a href="mailto:adrian@ephox.com">Adrian Sutton</a>
049: * @author <a href="mailto:mbowler@GargoyleSoftware.com">Mike Bowler</a>
050: * @author <a href="mailto:oleg@ural.ru">Oleg Kalnichevski</a>
051: */
052: public class NTLMScheme implements AuthScheme {
053:
054: /** Log object for this class. */
055: private static final Log LOG = LogFactory.getLog(NTLMScheme.class);
056:
057: /** NTLM challenge string. */
058: private String ntlmchallenge = null;
059:
060: private static final int UNINITIATED = 0;
061: private static final int INITIATED = 1;
062: private static final int TYPE1_MSG_GENERATED = 2;
063: private static final int TYPE2_MSG_RECEIVED = 3;
064: private static final int TYPE3_MSG_GENERATED = 4;
065: private static final int FAILED = Integer.MAX_VALUE;
066:
067: /** Authentication process state */
068: private int state;
069:
070: /**
071: * Default constructor for the NTLM authentication scheme.
072: *
073: * @since 3.0
074: */
075: public NTLMScheme() {
076: super ();
077: this .state = UNINITIATED;
078: }
079:
080: /**
081: * Constructor for the NTLM authentication scheme.
082: *
083: * @param challenge The authentication challenge
084: *
085: * @throws MalformedChallengeException is thrown if the authentication challenge
086: * is malformed
087: */
088: public NTLMScheme(final String challenge)
089: throws MalformedChallengeException {
090: super ();
091: processChallenge(challenge);
092: }
093:
094: /**
095: * Processes the NTLM challenge.
096: *
097: * @param challenge the challenge string
098: *
099: * @throws MalformedChallengeException is thrown if the authentication challenge
100: * is malformed
101: *
102: * @since 3.0
103: */
104: public void processChallenge(final String challenge)
105: throws MalformedChallengeException {
106: String s = AuthChallengeParser.extractScheme(challenge);
107: if (!s.equalsIgnoreCase(getSchemeName())) {
108: throw new MalformedChallengeException(
109: "Invalid NTLM challenge: " + challenge);
110: }
111: int i = challenge.indexOf(' ');
112: if (i != -1) {
113: s = challenge.substring(i, challenge.length());
114: this .ntlmchallenge = s.trim();
115: this .state = TYPE2_MSG_RECEIVED;
116: } else {
117: this .ntlmchallenge = "";
118: if (this .state == UNINITIATED) {
119: this .state = INITIATED;
120: } else {
121: this .state = FAILED;
122: }
123: }
124: }
125:
126: /**
127: * Tests if the NTLM authentication process has been completed.
128: *
129: * @return <tt>true</tt> if Basic authorization has been processed,
130: * <tt>false</tt> otherwise.
131: *
132: * @since 3.0
133: */
134: public boolean isComplete() {
135: return this .state == TYPE3_MSG_GENERATED
136: || this .state == FAILED;
137: }
138:
139: /**
140: * Returns textual designation of the NTLM authentication scheme.
141: *
142: * @return <code>ntlm</code>
143: */
144: public String getSchemeName() {
145: return "ntlm";
146: }
147:
148: /**
149: * The concept of an authentication realm is not supported by the NTLM
150: * authentication scheme. Always returns <code>null</code>.
151: *
152: * @return <code>null</code>
153: */
154: public String getRealm() {
155: return null;
156: }
157:
158: /**
159: * Returns a String identifying the authentication challenge. This is
160: * used, in combination with the host and port to determine if
161: * authorization has already been attempted or not. Schemes which
162: * require multiple requests to complete the authentication should
163: * return a different value for each stage in the request.
164: *
165: * <p>Additionally, the ID should take into account any changes to the
166: * authentication challenge and return a different value when appropriate.
167: * For example when the realm changes in basic authentication it should be
168: * considered a different authentication attempt and a different value should
169: * be returned.</p>
170: *
171: * @return String a String identifying the authentication challenge. The
172: * returned value may be null.
173: *
174: * @deprecated no longer used
175: */
176: public String getID() {
177: return ntlmchallenge;
178: }
179:
180: /**
181: * Returns the authentication parameter with the given name, if available.
182: *
183: * <p>There are no valid parameters for NTLM authentication so this method always returns
184: * <tt>null</tt>.</p>
185: *
186: * @param name The name of the parameter to be returned
187: *
188: * @return the parameter with the given name
189: */
190: public String getParameter(String name) {
191: if (name == null) {
192: throw new IllegalArgumentException(
193: "Parameter name may not be null");
194: }
195: return null;
196: }
197:
198: /**
199: * Returns <tt>true</tt>. NTLM authentication scheme is connection based.
200: *
201: * @return <tt>true</tt>.
202: *
203: * @since 3.0
204: */
205: public boolean isConnectionBased() {
206: return true;
207: }
208:
209: /**
210: * Create a NTLM authorization string for the given
211: * challenge and NT credentials.
212: *
213: * @param challenge The challenge.
214: * @param credentials {@link NTCredentials}
215: *
216: * @return a ntlm authorization string
217: * @throws AuthenticationException is thrown if authentication fails
218: *
219: * @deprecated Use non-static {@link #authenticate(Credentials, HttpMethod)}
220: */
221: public static String authenticate(final NTCredentials credentials,
222: final String challenge) throws AuthenticationException {
223:
224: LOG
225: .trace("enter NTLMScheme.authenticate(NTCredentials, String)");
226:
227: if (credentials == null) {
228: throw new IllegalArgumentException(
229: "Credentials may not be null");
230: }
231:
232: NTLM ntlm = new NTLM();
233: String s = ntlm.getResponseFor(challenge, credentials
234: .getUserName(), credentials.getPassword(), credentials
235: .getHost(), credentials.getDomain());
236: return "NTLM " + s;
237: }
238:
239: /**
240: * Create a NTLM authorization string for the given
241: * challenge and NT credentials.
242: *
243: * @param challenge The challenge.
244: * @param credentials {@link NTCredentials}
245: * @param charset The charset to use for encoding the credentials
246: *
247: * @return a ntlm authorization string
248: * @throws AuthenticationException is thrown if authentication fails
249: *
250: * @deprecated Use non-static {@link #authenticate(Credentials, HttpMethod)}
251: *
252: * @since 3.0
253: */
254: public static String authenticate(final NTCredentials credentials,
255: final String challenge, String charset)
256: throws AuthenticationException {
257:
258: LOG
259: .trace("enter NTLMScheme.authenticate(NTCredentials, String)");
260:
261: if (credentials == null) {
262: throw new IllegalArgumentException(
263: "Credentials may not be null");
264: }
265:
266: NTLM ntlm = new NTLM();
267: ntlm.setCredentialCharset(charset);
268: String s = ntlm.getResponseFor(challenge, credentials
269: .getUserName(), credentials.getPassword(), credentials
270: .getHost(), credentials.getDomain());
271: return "NTLM " + s;
272: }
273:
274: /**
275: * Produces NTLM authorization string for the given set of
276: * {@link Credentials}.
277: *
278: * @param credentials The set of credentials to be used for athentication
279: * @param method Method name is ignored by the NTLM authentication scheme
280: * @param uri URI is ignored by the NTLM authentication scheme
281: * @throws InvalidCredentialsException if authentication credentials
282: * are not valid or not applicable for this authentication scheme
283: * @throws AuthenticationException if authorization string cannot
284: * be generated due to an authentication failure
285: *
286: * @return an NTLM authorization string
287: *
288: * @deprecated Use {@link #authenticate(Credentials, HttpMethod)}
289: */
290: public String authenticate(Credentials credentials, String method,
291: String uri) throws AuthenticationException {
292: LOG
293: .trace("enter NTLMScheme.authenticate(Credentials, String, String)");
294:
295: NTCredentials ntcredentials = null;
296: try {
297: ntcredentials = (NTCredentials) credentials;
298: } catch (ClassCastException e) {
299: throw new InvalidCredentialsException(
300: "Credentials cannot be used for NTLM authentication: "
301: + credentials.getClass().getName());
302: }
303: return NTLMScheme.authenticate(ntcredentials,
304: this .ntlmchallenge);
305: }
306:
307: /**
308: * Produces NTLM authorization string for the given set of
309: * {@link Credentials}.
310: *
311: * @param credentials The set of credentials to be used for athentication
312: * @param method The method being authenticated
313: *
314: * @throws InvalidCredentialsException if authentication credentials
315: * are not valid or not applicable for this authentication scheme
316: * @throws AuthenticationException if authorization string cannot
317: * be generated due to an authentication failure
318: *
319: * @return an NTLM authorization string
320: *
321: * @since 3.0
322: */
323: public String authenticate(Credentials credentials,
324: HttpMethod method) throws AuthenticationException {
325: LOG
326: .trace("enter NTLMScheme.authenticate(Credentials, HttpMethod)");
327:
328: if (this .state == UNINITIATED) {
329: throw new IllegalStateException(
330: "NTLM authentication process has not been initiated");
331: }
332:
333: NTCredentials ntcredentials = null;
334: try {
335: ntcredentials = (NTCredentials) credentials;
336: } catch (ClassCastException e) {
337: throw new InvalidCredentialsException(
338: "Credentials cannot be used for NTLM authentication: "
339: + credentials.getClass().getName());
340: }
341: NTLM ntlm = new NTLM();
342: ntlm.setCredentialCharset(method.getParams()
343: .getCredentialCharset());
344: String response = null;
345: if (this .state == INITIATED || this .state == FAILED) {
346: response = ntlm.getType1Message(ntcredentials.getHost(),
347: ntcredentials.getDomain());
348: this .state = TYPE1_MSG_GENERATED;
349: } else {
350: response = ntlm.getType3Message(
351: ntcredentials.getUserName(), ntcredentials
352: .getPassword(), ntcredentials.getHost(),
353: ntcredentials.getDomain(), ntlm
354: .parseType2Message(this .ntlmchallenge));
355: this .state = TYPE3_MSG_GENERATED;
356: }
357: return "NTLM " + response;
358: }
359: }
|