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 }