23 * questions. |
23 * questions. |
24 */ |
24 */ |
25 |
25 |
26 package com.sun.net.httpserver; |
26 package com.sun.net.httpserver; |
27 |
27 |
|
28 import java.nio.charset.Charset; |
28 import java.util.Base64; |
29 import java.util.Base64; |
|
30 import java.util.Objects; |
|
31 |
|
32 import static java.nio.charset.StandardCharsets.UTF_8; |
29 |
33 |
30 /** |
34 /** |
31 * BasicAuthenticator provides an implementation of HTTP Basic |
35 * BasicAuthenticator provides an implementation of HTTP Basic |
32 * authentication. It is an abstract class and must be extended |
36 * authentication. It is an abstract class and must be extended |
33 * to provide an implementation of {@link #checkCredentials(String,String)} |
37 * to provide an implementation of {@link #checkCredentials(String,String)} |
34 * which is called to verify each incoming request. |
38 * which is called to verify each incoming request. |
35 */ |
39 */ |
36 public abstract class BasicAuthenticator extends Authenticator { |
40 public abstract class BasicAuthenticator extends Authenticator { |
37 |
41 |
38 protected String realm; |
42 protected final String realm; |
|
43 protected final Charset charset; |
|
44 private final boolean isUTF8; |
39 |
45 |
40 /** |
46 /** |
41 * Creates a BasicAuthenticator for the given HTTP realm |
47 * Creates a BasicAuthenticator for the given HTTP realm. |
|
48 * The Basic authentication credentials (username and password) are decoded |
|
49 * using the platform's {@link Charset#defaultCharset() default character set}. |
|
50 * |
42 * @param realm The HTTP Basic authentication realm |
51 * @param realm The HTTP Basic authentication realm |
43 * @throws NullPointerException if the realm is an empty string |
52 * @throws NullPointerException if realm is {@code null} |
|
53 * @throws IllegalArgumentException if realm is an empty string |
44 */ |
54 */ |
45 public BasicAuthenticator (String realm) { |
55 public BasicAuthenticator (String realm) { |
|
56 this(realm, Charset.defaultCharset()); |
|
57 } |
|
58 |
|
59 /** |
|
60 * Creates a BasicAuthenticator for the given HTTP realm and using the |
|
61 * given {@link Charset} to decode the Basic authentication credentials |
|
62 * (username and password). |
|
63 * |
|
64 * @apiNote {@code UTF-8} is the recommended charset because its usage is |
|
65 * communicated to the client, and therefore more likely to be used also |
|
66 * by the client. |
|
67 * |
|
68 * @param realm The HTTP Basic authentication realm |
|
69 * @param charset The Charset to decode incoming credentials from the client |
|
70 * @throws NullPointerException if realm or charset are {@code null} |
|
71 * @throws IllegalArgumentException if realm is an empty string |
|
72 */ |
|
73 public BasicAuthenticator (String realm, Charset charset) { |
|
74 Objects.requireNonNull(charset); |
|
75 if (realm.isEmpty()) // implicit NPE check |
|
76 throw new IllegalArgumentException("realm must not be empty"); |
46 this.realm = realm; |
77 this.realm = realm; |
|
78 this.charset = charset; |
|
79 this.isUTF8 = charset.equals(UTF_8); |
47 } |
80 } |
48 |
81 |
49 /** |
82 /** |
50 * returns the realm this BasicAuthenticator was created with |
83 * returns the realm this BasicAuthenticator was created with |
51 * @return the authenticator's realm string. |
84 * @return the authenticator's realm string. |
61 * look for auth token |
94 * look for auth token |
62 */ |
95 */ |
63 String auth = rmap.getFirst ("Authorization"); |
96 String auth = rmap.getFirst ("Authorization"); |
64 if (auth == null) { |
97 if (auth == null) { |
65 Headers map = t.getResponseHeaders(); |
98 Headers map = t.getResponseHeaders(); |
66 map.set ("WWW-Authenticate", "Basic realm=" + "\""+realm+"\""); |
99 var authString = "Basic realm=" + "\"" + realm + "\"" + |
|
100 (isUTF8 ? " charset=\"UTF-8\"" : ""); |
|
101 map.set ("WWW-Authenticate", authString); |
67 return new Authenticator.Retry (401); |
102 return new Authenticator.Retry (401); |
68 } |
103 } |
69 int sp = auth.indexOf (' '); |
104 int sp = auth.indexOf (' '); |
70 if (sp == -1 || !auth.substring(0, sp).equals ("Basic")) { |
105 if (sp == -1 || !auth.substring(0, sp).equals ("Basic")) { |
71 return new Authenticator.Failure (401); |
106 return new Authenticator.Failure (401); |
72 } |
107 } |
73 byte[] b = Base64.getDecoder().decode(auth.substring(sp+1)); |
108 byte[] b = Base64.getDecoder().decode(auth.substring(sp+1)); |
74 String userpass = new String (b); |
109 String userpass = new String (b, charset); |
75 int colon = userpass.indexOf (':'); |
110 int colon = userpass.indexOf (':'); |
76 String uname = userpass.substring (0, colon); |
111 String uname = userpass.substring (0, colon); |
77 String pass = userpass.substring (colon+1); |
112 String pass = userpass.substring (colon+1); |
78 |
113 |
79 if (checkCredentials (uname, pass)) { |
114 if (checkCredentials (uname, pass)) { |