Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java
+++ new/src/share/classes/sun/net/www/protocol/http/AuthenticationInfo.java
1 1 /*
2 2 * Copyright 1995-2003 Sun Microsystems, Inc. All Rights Reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Sun designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Sun in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
↓ open down ↓ |
17 lines elided |
↑ open up ↑ |
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 23 * have any questions.
24 24 */
25 25
26 26 package sun.net.www.protocol.http;
27 27
28 -import java.io.*;
29 -import java.net.*;
28 +import java.io.IOException;
29 +import java.io.ObjectInputStream;
30 +import java.net.PasswordAuthentication;
31 +import java.net.URL;
30 32 import java.util.Hashtable;
31 33 import java.util.LinkedList;
32 34 import java.util.ListIterator;
33 35 import java.util.Enumeration;
34 36 import java.util.HashMap;
35 37
36 38 import sun.net.www.HeaderParser;
37 39
38 40
39 41 /**
40 42 * AuthenticationInfo: Encapsulate the information needed to
41 43 * authenticate a user to a server.
42 44 *
43 45 * @author Jon Payne
↓ open down ↓ |
4 lines elided |
↑ open up ↑ |
44 46 * @author Herb Jellinek
45 47 * @author Bill Foote
46 48 */
47 49 // REMIND: It would be nice if this class understood about partial matching.
48 50 // If you're authorized for foo.com, chances are high you're also
49 51 // authorized for baz.foo.com.
50 52 // NB: When this gets implemented, be careful about the uncaching
51 53 // policy in HttpURLConnection. A failure on baz.foo.com shouldn't
52 54 // uncache foo.com!
53 55
54 -abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
56 +public abstract class AuthenticationInfo extends AuthCacheValue implements Cloneable {
55 57
56 58 // Constants saying what kind of authroization this is. This determines
57 59 // the namespace in the hash table lookup.
58 - static final char SERVER_AUTHENTICATION = 's';
59 - static final char PROXY_AUTHENTICATION = 'p';
60 + public static final char SERVER_AUTHENTICATION = 's';
61 + public static final char PROXY_AUTHENTICATION = 'p';
60 62
61 63 /**
62 64 * If true, then simultaneous authentication requests to the same realm/proxy
63 65 * are serialized, in order to avoid a user having to type the same username/passwords
64 66 * repeatedly, via the Authenticator. Default is false, which means that this
65 67 * behavior is switched off.
66 68 */
67 69 static boolean serializeAuth;
68 70
69 71 static {
70 72 serializeAuth = java.security.AccessController.doPrivileged(
71 73 new sun.security.action.GetBooleanAction(
72 74 "http.auth.serializeRequests")).booleanValue();
73 75 }
74 76
75 77 /* AuthCacheValue: */
76 78
77 79 transient protected PasswordAuthentication pw;
78 80
79 81 public PasswordAuthentication credentials() {
80 82 return pw;
81 83 }
82 84
83 85 public AuthCacheValue.Type getAuthType() {
84 86 return type == SERVER_AUTHENTICATION ?
85 87 AuthCacheValue.Type.Server:
86 88 AuthCacheValue.Type.Proxy;
87 89 }
88 90
89 91 AuthScheme getAuthScheme() {
90 92 return authScheme;
91 93 }
92 94
93 95 public String getHost() {
94 96 return host;
95 97 }
96 98 public int getPort() {
97 99 return port;
98 100 }
99 101 public String getRealm() {
100 102 return realm;
101 103 }
102 104 public String getPath() {
103 105 return path;
104 106 }
105 107 public String getProtocolScheme() {
106 108 return protocol;
107 109 }
108 110
109 111 /**
110 112 * requests is used to ensure that interaction with the
111 113 * Authenticator for a particular realm is single threaded.
112 114 * ie. if multiple threads need to get credentials from the user
113 115 * at the same time, then all but the first will block until
114 116 * the first completes its authentication.
115 117 */
116 118 static private HashMap requests = new HashMap ();
117 119
118 120 /* check if a request for this destination is in progress
119 121 * return false immediately if not. Otherwise block until
120 122 * request is finished and return true
121 123 */
122 124 static private boolean requestIsInProgress (String key) {
123 125 if (!serializeAuth) {
124 126 /* behavior is disabled. Revert to concurrent requests */
125 127 return false;
126 128 }
127 129 synchronized (requests) {
128 130 Thread t, c;
129 131 c = Thread.currentThread();
130 132 if ((t=(Thread)requests.get(key))==null) {
131 133 requests.put (key, c);
132 134 return false;
133 135 }
134 136 if (t == c) {
135 137 return false;
136 138 }
137 139 while (requests.containsKey(key)) {
138 140 try {
139 141 requests.wait ();
140 142 } catch (InterruptedException e) {}
141 143 }
142 144 }
143 145 /* entry may be in cache now. */
144 146 return true;
145 147 }
146 148
147 149 /* signal completion of an authentication (whether it succeeded or not)
148 150 * so that other threads can continue.
149 151 */
150 152 static private void requestCompleted (String key) {
151 153 synchronized (requests) {
152 154 boolean waspresent = requests.remove (key) != null;
153 155 assert waspresent;
154 156 requests.notifyAll();
155 157 }
156 158 }
157 159
158 160 //public String toString () {
159 161 //return ("{"+type+":"+authScheme+":"+protocol+":"+host+":"+port+":"+realm+":"+path+"}");
160 162 //}
161 163
162 164 // REMIND: This cache just grows forever. We should put in a bounded
163 165 // cache, or maybe something using WeakRef's.
164 166
165 167 /** The type (server/proxy) of authentication this is. Used for key lookup */
166 168 char type;
167 169
168 170 /** The authentication scheme (basic/digest). Also used for key lookup */
169 171 AuthScheme authScheme;
170 172
171 173 /** The protocol/scheme (i.e. http or https ). Need to keep the caches
172 174 * logically separate for the two protocols. This field is only used
173 175 * when constructed with a URL (the normal case for server authentication)
174 176 * For proxy authentication the protocol is not relevant.
175 177 */
176 178 String protocol;
177 179
178 180 /** The host we're authenticating against. */
179 181 String host;
180 182
↓ open down ↓ |
111 lines elided |
↑ open up ↑ |
181 183 /** The port on the host we're authenticating against. */
182 184 int port;
183 185
184 186 /** The realm we're authenticating against. */
185 187 String realm;
186 188
187 189 /** The shortest path from the URL we authenticated against. */
188 190 String path;
189 191
190 192 /** Use this constructor only for proxy entries */
191 - AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
193 + public AuthenticationInfo(char type, AuthScheme authScheme, String host, int port, String realm) {
192 194 this.type = type;
193 195 this.authScheme = authScheme;
194 196 this.protocol = "";
195 197 this.host = host.toLowerCase();
196 198 this.port = port;
197 199 this.realm = realm;
198 200 this.path = null;
199 201 }
200 202
201 203 public Object clone() {
202 204 try {
203 205 return super.clone ();
↓ open down ↓ |
2 lines elided |
↑ open up ↑ |
204 206 } catch (CloneNotSupportedException e) {
205 207 // Cannot happen because Cloneable implemented by AuthenticationInfo
206 208 return null;
207 209 }
208 210 }
209 211
210 212 /*
211 213 * Constructor used to limit the authorization to the path within
212 214 * the URL. Use this constructor for origin server entries.
213 215 */
214 - AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
216 + public AuthenticationInfo(char type, AuthScheme authScheme, URL url, String realm) {
215 217 this.type = type;
216 218 this.authScheme = authScheme;
217 219 this.protocol = url.getProtocol().toLowerCase();
218 220 this.host = url.getHost().toLowerCase();
219 221 this.port = url.getPort();
220 222 if (this.port == -1) {
221 223 this.port = url.getDefaultPort();
222 224 }
223 225 this.realm = realm;
224 226
225 227 String urlPath = url.getPath();
226 228 if (urlPath.length() == 0)
227 229 this.path = urlPath;
228 230 else {
229 231 this.path = reducePath (urlPath);
230 232 }
231 233
232 234 }
233 235
234 236 /*
235 237 * reduce the path to the root of where we think the
236 238 * authorization begins. This could get shorter as
237 239 * the url is traversed up following a successful challenge.
238 240 */
239 241 static String reducePath (String urlPath) {
240 242 int sepIndex = urlPath.lastIndexOf('/');
241 243 int targetSuffixIndex = urlPath.lastIndexOf('.');
242 244 if (sepIndex != -1)
243 245 if (sepIndex < targetSuffixIndex)
244 246 return urlPath.substring(0, sepIndex+1);
245 247 else
246 248 return urlPath;
247 249 else
248 250 return urlPath;
249 251 }
250 252
251 253 /**
252 254 * Returns info for the URL, for an HTTP server auth. Used when we
253 255 * don't yet know the realm
254 256 * (i.e. when we're preemptively setting the auth).
255 257 */
256 258 static AuthenticationInfo getServerAuth(URL url) {
257 259 int port = url.getPort();
258 260 if (port == -1) {
259 261 port = url.getDefaultPort();
260 262 }
261 263 String key = SERVER_AUTHENTICATION + ":" + url.getProtocol().toLowerCase()
262 264 + ":" + url.getHost().toLowerCase() + ":" + port;
263 265 return getAuth(key, url);
264 266 }
265 267
266 268 /**
267 269 * Returns info for the URL, for an HTTP server auth. Used when we
268 270 * do know the realm (i.e. when we're responding to a challenge).
269 271 * In this case we do not use the path because the protection space
270 272 * is identified by the host:port:realm only
271 273 */
272 274 static AuthenticationInfo getServerAuth(URL url, String realm, AuthScheme scheme) {
273 275 int port = url.getPort();
274 276 if (port == -1) {
275 277 port = url.getDefaultPort();
276 278 }
277 279 String key = SERVER_AUTHENTICATION + ":" + scheme + ":" + url.getProtocol().toLowerCase()
278 280 + ":" + url.getHost().toLowerCase() + ":" + port + ":" + realm;
279 281 AuthenticationInfo cached = getAuth(key, null);
280 282 if ((cached == null) && requestIsInProgress (key)) {
281 283 /* check the cache again, it might contain an entry */
282 284 cached = getAuth(key, null);
283 285 }
284 286 return cached;
285 287 }
286 288
287 289
288 290 /**
289 291 * Return the AuthenticationInfo object from the cache if it's path is
290 292 * a substring of the supplied URLs path.
291 293 */
292 294 static AuthenticationInfo getAuth(String key, URL url) {
293 295 if (url == null) {
294 296 return (AuthenticationInfo)cache.get (key, null);
295 297 } else {
296 298 return (AuthenticationInfo)cache.get (key, url.getPath());
297 299 }
298 300 }
299 301
300 302 /**
301 303 * Returns a firewall authentication, for the given host/port. Used
302 304 * for preemptive header-setting. Note, the protocol field is always
303 305 * blank for proxies.
304 306 */
305 307 static AuthenticationInfo getProxyAuth(String host, int port) {
306 308 String key = PROXY_AUTHENTICATION + "::" + host.toLowerCase() + ":" + port;
307 309 AuthenticationInfo result = (AuthenticationInfo) cache.get(key, null);
308 310 return result;
309 311 }
310 312
311 313 /**
312 314 * Returns a firewall authentication, for the given host/port and realm.
313 315 * Used in response to a challenge. Note, the protocol field is always
314 316 * blank for proxies.
315 317 */
316 318 static AuthenticationInfo getProxyAuth(String host, int port, String realm, AuthScheme scheme) {
317 319 String key = PROXY_AUTHENTICATION + ":" + scheme + "::" + host.toLowerCase()
318 320 + ":" + port + ":" + realm;
319 321 AuthenticationInfo cached = (AuthenticationInfo) cache.get(key, null);
320 322 if ((cached == null) && requestIsInProgress (key)) {
321 323 /* check the cache again, it might contain an entry */
322 324 cached = (AuthenticationInfo) cache.get(key, null);
323 325 }
324 326 return cached;
325 327 }
326 328
327 329
328 330 /**
329 331 * Add this authentication to the cache
330 332 */
331 333 void addToCache() {
332 334 cache.put (cacheKey(true), this);
333 335 if (supportsPreemptiveAuthorization()) {
334 336 cache.put (cacheKey(false), this);
335 337 }
336 338 endAuthRequest();
337 339 }
338 340
339 341 void endAuthRequest () {
340 342 if (!serializeAuth) {
341 343 return;
342 344 }
343 345 synchronized (requests) {
344 346 requestCompleted (cacheKey(true));
345 347 }
346 348 }
347 349
348 350 /**
349 351 * Remove this authentication from the cache
350 352 */
↓ open down ↓ |
126 lines elided |
↑ open up ↑ |
351 353 void removeFromCache() {
352 354 cache.remove(cacheKey(true), this);
353 355 if (supportsPreemptiveAuthorization()) {
354 356 cache.remove(cacheKey(false), this);
355 357 }
356 358 }
357 359
358 360 /**
359 361 * @return true if this authentication supports preemptive authorization
360 362 */
361 - abstract boolean supportsPreemptiveAuthorization();
363 + public abstract boolean supportsPreemptiveAuthorization();
362 364
363 365 /**
364 366 * @return the name of the HTTP header this authentication wants set.
365 367 * This is used for preemptive authorization.
366 368 */
367 - abstract String getHeaderName();
369 + public String getHeaderName() {
370 + if (type == SERVER_AUTHENTICATION) {
371 + return "Authorization";
372 + } else {
373 + return "Proxy-authorization";
374 + }
375 + }
368 376
369 377 /**
370 378 * Calculates and returns the authentication header value based
371 379 * on the stored authentication parameters. If the calculation does not depend
372 380 * on the URL or the request method then these parameters are ignored.
373 381 * @param url The URL
374 382 * @param method The request method
375 383 * @return the value of the HTTP header this authentication wants set.
376 384 * Used for preemptive authorization.
377 385 */
378 - abstract String getHeaderValue(URL url, String method);
386 + public abstract String getHeaderValue(URL url, String method);
379 387
380 388 /**
381 389 * Set header(s) on the given connection. Subclasses must override
382 390 * This will only be called for
383 391 * definitive (i.e. non-preemptive) authorization.
384 392 * @param conn The connection to apply the header(s) to
385 393 * @param p A source of header values for this connection, if needed.
386 394 * @param raw The raw header field (if needed)
387 395 * @return true if all goes well, false if no headers were set.
388 396 */
389 - abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
397 + public abstract boolean setHeaders(HttpURLConnection conn, HeaderParser p, String raw);
390 398
391 399 /**
392 400 * Check if the header indicates that the current auth. parameters are stale.
393 401 * If so, then replace the relevant field with the new value
394 402 * and return true. Otherwise return false.
395 403 * returning true means the request can be retried with the same userid/password
396 404 * returning false means we have to go back to the user to ask for a new
397 405 * username password.
398 406 */
399 - abstract boolean isAuthorizationStale (String header);
407 + public abstract boolean isAuthorizationStale (String header);
400 408
401 409 /**
402 410 * Give a key for hash table lookups.
403 411 * @param includeRealm if you want the realm considered. Preemptively
404 412 * setting an authorization is done before the realm is known.
405 413 */
406 414 String cacheKey(boolean includeRealm) {
407 415 // This must be kept in sync with the getXXXAuth() methods in this
408 416 // class.
409 417 if (includeRealm) {
410 418 return type + ":" + authScheme + ":" + protocol + ":"
411 419 + host + ":" + port + ":" + realm;
412 420 } else {
413 421 return type + ":" + protocol + ":" + host + ":" + port;
414 422 }
415 423 }
416 424
417 425 String s1, s2; /* used for serialization of pw */
418 426
419 427 private void readObject(ObjectInputStream s)
420 428 throws IOException, ClassNotFoundException
421 429 {
422 430 s.defaultReadObject ();
423 431 pw = new PasswordAuthentication (s1, s2.toCharArray());
424 432 s1 = null; s2= null;
425 433 }
426 434
427 435 private synchronized void writeObject(java.io.ObjectOutputStream s)
428 436 throws IOException
429 437 {
430 438 s1 = pw.getUserName();
431 439 s2 = new String (pw.getPassword());
432 440 s.defaultWriteObject ();
433 441 }
434 442 }
↓ open down ↓ |
25 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX