Lines 44-51
Link Here
|
44 |
* @version $Id$ |
44 |
* @version $Id$ |
45 |
*/ |
45 |
*/ |
46 |
|
46 |
|
47 |
public class BasicAuthenticator |
47 |
public class BasicAuthenticator extends AuthenticatorBase { |
48 |
extends AuthenticatorBase { |
|
|
49 |
private static final Log log = LogFactory.getLog(BasicAuthenticator.class); |
48 |
private static final Log log = LogFactory.getLog(BasicAuthenticator.class); |
50 |
|
49 |
|
51 |
|
50 |
|
Lines 98-106
Link Here
|
98 |
} |
97 |
} |
99 |
|
98 |
|
100 |
// Validate any credentials already included with this request |
99 |
// Validate any credentials already included with this request |
101 |
String username = null; |
|
|
102 |
String password = null; |
103 |
|
104 |
MessageBytes authorization = |
100 |
MessageBytes authorization = |
105 |
request.getCoyoteRequest().getMimeHeaders() |
101 |
request.getCoyoteRequest().getMimeHeaders() |
106 |
.getValue("authorization"); |
102 |
.getValue("authorization"); |
Lines 108-151
Link Here
|
108 |
if (authorization != null) { |
104 |
if (authorization != null) { |
109 |
authorization.toBytes(); |
105 |
authorization.toBytes(); |
110 |
ByteChunk authorizationBC = authorization.getByteChunk(); |
106 |
ByteChunk authorizationBC = authorization.getByteChunk(); |
111 |
if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { |
107 |
BasicCredentials credentials = null; |
112 |
authorizationBC.setOffset(authorizationBC.getOffset() + 6); |
108 |
try { |
|
|
109 |
credentials = new BasicCredentials(authorizationBC); |
110 |
String username = credentials.getUsername(); |
111 |
String password = credentials.getPassword(); |
113 |
|
112 |
|
114 |
byte[] decoded = Base64.decodeBase64( |
113 |
principal = context.getRealm().authenticate(username, password); |
115 |
authorizationBC.getBuffer(), |
114 |
if (principal != null) { |
116 |
authorizationBC.getOffset(), |
115 |
register(request, response, principal, |
117 |
authorizationBC.getLength()); |
116 |
HttpServletRequest.BASIC_AUTH, username, password); |
118 |
|
117 |
return (true); |
119 |
// Get username and password |
|
|
120 |
int colon = -1; |
121 |
for (int i = 0; i < decoded.length; i++) { |
122 |
if (decoded[i] == ':') { |
123 |
colon = i; |
124 |
break; |
125 |
} |
126 |
} |
118 |
} |
127 |
|
119 |
} |
128 |
if (colon < 0) { |
120 |
catch (IllegalArgumentException iae) { |
129 |
username = new String(decoded, B2CConverter.ISO_8859_1); |
121 |
if (log.isDebugEnabled()) { |
130 |
} else { |
122 |
log.debug("Invalid Authorization" + iae.getMessage()); |
131 |
username = new String( |
|
|
132 |
decoded, 0, colon, B2CConverter.ISO_8859_1); |
133 |
password = new String( |
134 |
decoded, colon + 1, decoded.length - colon - 1, |
135 |
B2CConverter.ISO_8859_1); |
136 |
} |
123 |
} |
137 |
|
|
|
138 |
authorizationBC.setOffset(authorizationBC.getOffset() - 6); |
139 |
} |
124 |
} |
140 |
|
|
|
141 |
principal = context.getRealm().authenticate(username, password); |
142 |
if (principal != null) { |
143 |
register(request, response, principal, |
144 |
HttpServletRequest.BASIC_AUTH, username, password); |
145 |
return (true); |
146 |
} |
147 |
} |
125 |
} |
148 |
|
126 |
|
|
|
127 |
// the request could not be authenticated, so reissue the challenge |
149 |
StringBuilder value = new StringBuilder(16); |
128 |
StringBuilder value = new StringBuilder(16); |
150 |
value.append("Basic realm=\""); |
129 |
value.append("Basic realm=\""); |
151 |
value.append(getRealmName(context)); |
130 |
value.append(getRealmName(context)); |
Lines 156-164
Link Here
|
156 |
|
135 |
|
157 |
} |
136 |
} |
158 |
|
137 |
|
159 |
|
|
|
160 |
@Override |
138 |
@Override |
161 |
protected String getAuthMethod() { |
139 |
protected String getAuthMethod() { |
162 |
return HttpServletRequest.BASIC_AUTH; |
140 |
return HttpServletRequest.BASIC_AUTH; |
163 |
} |
141 |
} |
|
|
142 |
|
143 |
|
144 |
/** |
145 |
* Parser for an HTTP Authorization header for BASIC authentication |
146 |
* as per RFC 2617 section 2, and the Base64 encoded credentials as |
147 |
* per RFC 2045 section 6.8. |
148 |
*/ |
149 |
protected static class BasicCredentials { |
150 |
|
151 |
// the only authentication method supported by this parser |
152 |
// note: we include single white space as its delimiter |
153 |
private static final String METHOD = "basic "; |
154 |
|
155 |
private ByteChunk authorization; |
156 |
private int initialOffset; |
157 |
private int base64blobOffset; |
158 |
private int base64blobLength; |
159 |
|
160 |
private String username = null; |
161 |
private String password = null; |
162 |
|
163 |
/** |
164 |
* Parse the HTTP Authorization header for BASIC authentication |
165 |
* as per RFC 2617 section 2, and the Base64 encoded credentials |
166 |
* as per RFC 2045 section 6.8. |
167 |
* |
168 |
* @param input The header value to parse in-place |
169 |
* |
170 |
* @throws IllegalArgumentException If the header does not conform |
171 |
* to RFC 2617 |
172 |
*/ |
173 |
public BasicCredentials(ByteChunk input) |
174 |
throws IllegalArgumentException { |
175 |
authorization = input; |
176 |
initialOffset = input.getOffset(); |
177 |
parseMethod(); |
178 |
byte[] decoded = parseBase64(); |
179 |
parseCredentials(decoded); |
180 |
} |
181 |
|
182 |
/** |
183 |
* Trivial accessor. |
184 |
* |
185 |
* @return the decoded username token as a String, which is |
186 |
* never be <code>null</code>, but can be empty. |
187 |
*/ |
188 |
public String getUsername() { |
189 |
return username; |
190 |
} |
191 |
|
192 |
/** |
193 |
* Trivial accessor. |
194 |
* |
195 |
* @return the decoded password token as a String, or <code>null</code> |
196 |
* if no password was found in the credentials. |
197 |
*/ |
198 |
public String getPassword() { |
199 |
return password; |
200 |
} |
201 |
|
202 |
/* |
203 |
* The authorization method string is case-insensitive and must |
204 |
* hae at least one space character as a delimiter. |
205 |
*/ |
206 |
private void parseMethod() throws IllegalArgumentException { |
207 |
if (authorization.startsWithIgnoreCase(METHOD, 0)) { |
208 |
// step past the auth method name |
209 |
base64blobOffset = initialOffset + METHOD.length(); |
210 |
base64blobLength = authorization.getLength() - METHOD.length(); |
211 |
} |
212 |
else { |
213 |
// is this possible, or permitted? |
214 |
throw new IllegalArgumentException( |
215 |
"Authorization header method is not \"Basic\""); |
216 |
} |
217 |
} |
218 |
/* |
219 |
* Decode the base64-user-pass token, which RFC 2617 states |
220 |
* can be longer than the 76 characters per line limit defined |
221 |
* in RFC 2045. The base64 decoder will ignore embedded line |
222 |
* break characters as well as surplus surrounding white space. |
223 |
*/ |
224 |
private byte[] parseBase64() throws IllegalArgumentException { |
225 |
byte[] decoded = Base64.decodeBase64( |
226 |
authorization.getBuffer(), |
227 |
base64blobOffset, base64blobLength); |
228 |
// restore original offset |
229 |
authorization.setOffset(initialOffset); |
230 |
if (decoded == null) { |
231 |
throw new IllegalArgumentException( |
232 |
"Basic Authorization credentials are not Base64"); |
233 |
} |
234 |
return decoded; |
235 |
} |
236 |
|
237 |
/* |
238 |
* Extract the mandatory username token and separate it from the |
239 |
* optional password token. Tolerate surplus surrounding white space. |
240 |
*/ |
241 |
private void parseCredentials(byte[] decoded) |
242 |
throws IllegalArgumentException { |
243 |
|
244 |
int colon = -1; |
245 |
for (int i = 0; i < decoded.length; i++) { |
246 |
if (decoded[i] == ':') { |
247 |
colon = i; |
248 |
break; |
249 |
} |
250 |
} |
251 |
|
252 |
if (colon < 0) { |
253 |
username = new String(decoded, B2CConverter.ISO_8859_1); |
254 |
// password will remain null! |
255 |
} |
256 |
else { |
257 |
username = new String( |
258 |
decoded, 0, colon, B2CConverter.ISO_8859_1); |
259 |
password = new String( |
260 |
decoded, colon + 1, decoded.length - colon - 1, |
261 |
B2CConverter.ISO_8859_1); |
262 |
// tolerate surplus white space around credentials |
263 |
if (password.length() > 1) { |
264 |
password = password.trim(); |
265 |
} |
266 |
} |
267 |
// tolerate surplus white space around credentials |
268 |
if (username.length() > 1) { |
269 |
username = username.trim(); |
270 |
} |
271 |
} |
272 |
} |
164 |
} |
273 |
} |