1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27 package org.apache.http.impl.auth;
28
29 import org.apache.http.Header;
30 import org.apache.http.HttpRequest;
31 import org.apache.http.annotation.NotThreadSafe;
32 import org.apache.http.auth.AUTH;
33 import org.apache.http.auth.AuthenticationException;
34 import org.apache.http.auth.Credentials;
35 import org.apache.http.auth.InvalidCredentialsException;
36 import org.apache.http.auth.MalformedChallengeException;
37 import org.apache.http.auth.NTCredentials;
38 import org.apache.http.message.BufferedHeader;
39 import org.apache.http.util.Args;
40 import org.apache.http.util.CharArrayBuffer;
41
42
43
44
45
46
47
48 @NotThreadSafe
49 public class NTLMScheme extends AuthSchemeBase {
50
51 enum State {
52 UNINITIATED,
53 CHALLENGE_RECEIVED,
54 MSG_TYPE1_GENERATED,
55 MSG_TYPE2_RECEVIED,
56 MSG_TYPE3_GENERATED,
57 FAILED,
58 }
59
60 private final NTLMEngine engine;
61
62 private State state;
63 private String challenge;
64
65 public NTLMScheme(final NTLMEngine engine) {
66 super();
67 Args.notNull(engine, "NTLM engine");
68 this.engine = engine;
69 this.state = State.UNINITIATED;
70 this.challenge = null;
71 }
72
73
74
75
76 public NTLMScheme() {
77 this(new NTLMEngineImpl());
78 }
79
80 public String getSchemeName() {
81 return "ntlm";
82 }
83
84 public String getParameter(final String name) {
85
86 return null;
87 }
88
89 public String getRealm() {
90
91 return null;
92 }
93
94 public boolean isConnectionBased() {
95 return true;
96 }
97
98 @Override
99 protected void parseChallenge(
100 final CharArrayBuffer buffer,
101 final int beginIndex, final int endIndex) throws MalformedChallengeException {
102 final String challenge = buffer.substringTrimmed(beginIndex, endIndex);
103 if (challenge.length() == 0) {
104 if (this.state == State.UNINITIATED) {
105 this.state = State.CHALLENGE_RECEIVED;
106 } else {
107 this.state = State.FAILED;
108 }
109 this.challenge = null;
110 } else {
111 this.state = State.MSG_TYPE2_RECEVIED;
112 this.challenge = challenge;
113 }
114 }
115
116 public Header authenticate(
117 final Credentials credentials,
118 final HttpRequest request) throws AuthenticationException {
119 NTCredentials ntcredentials = null;
120 try {
121 ntcredentials = (NTCredentials) credentials;
122 } catch (final ClassCastException e) {
123 throw new InvalidCredentialsException(
124 "Credentials cannot be used for NTLM authentication: "
125 + credentials.getClass().getName());
126 }
127 String response = null;
128 if (this.state == State.CHALLENGE_RECEIVED || this.state == State.FAILED) {
129 response = this.engine.generateType1Msg(
130 ntcredentials.getDomain(),
131 ntcredentials.getWorkstation());
132 this.state = State.MSG_TYPE1_GENERATED;
133 } else if (this.state == State.MSG_TYPE2_RECEVIED) {
134 response = this.engine.generateType3Msg(
135 ntcredentials.getUserName(),
136 ntcredentials.getPassword(),
137 ntcredentials.getDomain(),
138 ntcredentials.getWorkstation(),
139 this.challenge);
140 this.state = State.MSG_TYPE3_GENERATED;
141 } else {
142 throw new AuthenticationException("Unexpected state: " + this.state);
143 }
144 final CharArrayBuffer buffer = new CharArrayBuffer(32);
145 if (isProxy()) {
146 buffer.append(AUTH.PROXY_AUTH_RESP);
147 } else {
148 buffer.append(AUTH.WWW_AUTH_RESP);
149 }
150 buffer.append(": NTLM ");
151 buffer.append(response);
152 return new BufferedHeader(buffer);
153 }
154
155 public boolean isComplete() {
156 return this.state == State.MSG_TYPE3_GENERATED || this.state == State.FAILED;
157 }
158
159 }