1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit;
16
17 import java.io.IOException;
18 import java.io.ObjectInputStream;
19 import java.io.ObjectOutputStream;
20 import java.io.Serializable;
21 import java.net.Authenticator;
22 import java.net.PasswordAuthentication;
23 import java.util.HashMap;
24 import java.util.Map;
25
26 import org.apache.http.auth.AuthScope;
27 import org.apache.http.auth.Credentials;
28 import org.apache.http.auth.NTCredentials;
29 import org.apache.http.auth.UsernamePasswordCredentials;
30 import org.apache.http.client.CredentialsProvider;
31 import org.htmlunit.httpclient.HtmlUnitUsernamePasswordCredentials;
32
33
34
35
36
37
38
39
40
41
42
43
44
45 public class DefaultCredentialsProvider implements CredentialsProvider, Serializable {
46
47
48 public static final String ANY_HOST = null;
49
50
51 public static final int ANY_PORT = -1;
52
53
54 public static final String ANY_REALM = null;
55
56
57 public static final String ANY_SCHEME = null;
58
59 private static SocksProxyAuthenticator SocksAuthenticator_;
60 private final Map<AuthScopeProxy, Credentials> credentialsMap_ = new HashMap<>();
61
62
63
64 private static final class SocksProxyAuthenticator extends Authenticator {
65 private CredentialsProvider credentialsProvider_;
66
67 @Override
68 protected PasswordAuthentication getPasswordAuthentication() {
69
70
71 final boolean isProxy = Authenticator.RequestorType.PROXY.equals(getRequestorType())
72 || "SOCKS authentication".equals(getRequestingPrompt());
73 if (!isProxy) {
74 return null;
75 }
76
77 final AuthScope authScope = new AuthScope(getRequestingHost(), getRequestingPort(), getRequestingScheme());
78 final Credentials credentials = credentialsProvider_.getCredentials(authScope);
79 if (credentials == null) {
80 return null;
81 }
82
83 return new PasswordAuthentication(credentials.getUserPrincipal().getName(),
84 credentials.getPassword().toCharArray());
85 }
86 }
87
88
89
90
91
92
93
94
95
96
97 public void addCredentials(final String username, final char[] password) {
98 addCredentials(username, password, ANY_HOST, ANY_PORT, ANY_REALM);
99 }
100
101
102
103
104
105
106
107
108
109
110
111 public void addCredentials(final String username, final char[] password, final String host,
112 final int port, final String realm) {
113 final AuthScope authscope = new AuthScope(host, port, realm, ANY_SCHEME);
114 final HtmlUnitUsernamePasswordCredentials credentials =
115 new HtmlUnitUsernamePasswordCredentials(username, password);
116 setCredentials(authscope, credentials);
117 }
118
119
120
121
122
123
124
125
126
127
128
129
130 public void addNTLMCredentials(final String username, final char[] password, final String host,
131 final int port, final String workstation, final String domain) {
132 final AuthScope authscope = new AuthScope(host, port, ANY_REALM, ANY_SCHEME);
133 final NTCredentials credentials = new NTCredentials(username, String.valueOf(password), workstation, domain);
134 setCredentials(authscope, credentials);
135 }
136
137
138
139
140
141
142
143
144 public void addSocksCredentials(final String username, final char[] password, final String host,
145 final int port) {
146 final AuthScope authscope = new AuthScope(host, port, ANY_REALM, ANY_SCHEME);
147 final HtmlUnitUsernamePasswordCredentials credentials =
148 new HtmlUnitUsernamePasswordCredentials(username, password);
149 setCredentials(authscope, credentials);
150
151 initSocksAuthenticatorIfNeeded(this);
152 }
153
154 private static synchronized void initSocksAuthenticatorIfNeeded(final CredentialsProvider provider) {
155 if (SocksAuthenticator_ == null) {
156 SocksAuthenticator_ = new SocksProxyAuthenticator();
157 SocksAuthenticator_.credentialsProvider_ = provider;
158
159 Authenticator.setDefault(SocksAuthenticator_);
160 }
161 }
162
163
164
165
166 @Override
167 public synchronized void setCredentials(final AuthScope authscope, final Credentials credentials) {
168 if (authscope == null) {
169 throw new IllegalArgumentException("Authentication scope may not be null");
170 }
171
172 if (credentials instanceof UsernamePasswordCredentials
173 || credentials instanceof HtmlUnitUsernamePasswordCredentials
174 || credentials instanceof NTCredentials) {
175 credentialsMap_.put(new AuthScopeProxy(authscope), credentials);
176 return;
177 }
178
179 throw new IllegalArgumentException("Unsupported Credential type: " + credentials.getClass().getName());
180 }
181
182
183
184
185
186
187
188
189 private static Credentials matchCredentials(final Map<AuthScopeProxy, Credentials> map, final AuthScope authscope) {
190 Credentials creds = map.get(new AuthScopeProxy(authscope));
191 if (creds == null) {
192 int bestMatchFactor = -1;
193 AuthScopeProxy bestMatch = null;
194 for (final AuthScopeProxy proxy : map.keySet()) {
195 final AuthScope current = proxy.getAuthScope();
196 final int factor = authscope.match(current);
197 if (factor > bestMatchFactor) {
198 bestMatchFactor = factor;
199 bestMatch = proxy;
200 }
201 }
202 if (bestMatch != null) {
203 creds = map.get(bestMatch);
204 }
205 }
206 return creds;
207 }
208
209
210
211
212 @Override
213 public synchronized Credentials getCredentials(final AuthScope authscope) {
214 if (authscope == null) {
215 throw new IllegalArgumentException("Authentication scope may not be null");
216 }
217 return matchCredentials(credentialsMap_, authscope);
218 }
219
220
221
222
223
224
225 public synchronized boolean removeCredentials(final AuthScope authscope) {
226 if (authscope == null) {
227 throw new IllegalArgumentException("Authentication scope may not be null");
228 }
229 int bestMatchFactor = -1;
230 AuthScopeProxy bestMatch = null;
231 for (final AuthScopeProxy proxy : credentialsMap_.keySet()) {
232 final AuthScope current = proxy.getAuthScope();
233 final int factor = authscope.match(current);
234 if (factor > bestMatchFactor) {
235 bestMatchFactor = factor;
236 bestMatch = proxy;
237 }
238 }
239 return credentialsMap_.remove(bestMatch) != null;
240 }
241
242
243
244
245 @Override
246 public String toString() {
247 return credentialsMap_.toString();
248 }
249
250
251
252
253 @Override
254 public synchronized void clear() {
255 credentialsMap_.clear();
256 }
257
258
259
260
261
262 private static class AuthScopeProxy implements Serializable {
263 private AuthScope authScope_;
264
265 AuthScopeProxy(final AuthScope authScope) {
266 authScope_ = authScope;
267 }
268
269 public AuthScope getAuthScope() {
270 return authScope_;
271 }
272
273 private void writeObject(final ObjectOutputStream stream) throws IOException {
274 stream.writeObject(authScope_.getHost());
275 stream.writeInt(authScope_.getPort());
276 stream.writeObject(authScope_.getRealm());
277 stream.writeObject(authScope_.getScheme());
278 }
279
280 private void readObject(final ObjectInputStream stream) throws IOException, ClassNotFoundException {
281 final String host = (String) stream.readObject();
282 final int port = stream.readInt();
283 final String realm = (String) stream.readObject();
284 final String scheme = (String) stream.readObject();
285 authScope_ = new AuthScope(host, port, realm, scheme);
286 }
287
288 @Override
289 public int hashCode() {
290 return authScope_.hashCode();
291 }
292
293 @Override
294 public boolean equals(final Object obj) {
295 return obj instanceof AuthScopeProxy && authScope_.equals(((AuthScopeProxy) obj).getAuthScope());
296 }
297 }
298 }