ASF Bugzilla – Attachment 30435 Details for
Bug 55101
BasicAuthenticator parser and associated unit tests
Home
|
New
|
Browse
|
Search
|
[?]
|
Reports
|
Help
|
New Account
|
Log In
Remember
[x]
|
Forgot Password
Login:
[x]
[patch]
new inner class to parse credentials
BasicAuthenticator.diff (text/plain), 8.44 KB, created by
Brian Burch
on 2013-06-15 15:01:40 UTC
(
hide
)
Description:
new inner class to parse credentials
Filename:
MIME Type:
Creator:
Brian Burch
Created:
2013-06-15 15:01:40 UTC
Size:
8.44 KB
patch
obsolete
>Index: java/org/apache/catalina/authenticator/BasicAuthenticator.java >=================================================================== >--- java/org/apache/catalina/authenticator/BasicAuthenticator.java (revision 1493343) >+++ java/org/apache/catalina/authenticator/BasicAuthenticator.java (working copy) >@@ -44,8 +44,7 @@ > * @version $Id$ > */ > >-public class BasicAuthenticator >- extends AuthenticatorBase { >+public class BasicAuthenticator extends AuthenticatorBase { > private static final Log log = LogFactory.getLog(BasicAuthenticator.class); > > >@@ -98,9 +97,6 @@ > } > > // Validate any credentials already included with this request >- String username = null; >- String password = null; >- > MessageBytes authorization = > request.getCoyoteRequest().getMimeHeaders() > .getValue("authorization"); >@@ -108,44 +104,27 @@ > if (authorization != null) { > authorization.toBytes(); > ByteChunk authorizationBC = authorization.getByteChunk(); >- if (authorizationBC.startsWithIgnoreCase("basic ", 0)) { >- authorizationBC.setOffset(authorizationBC.getOffset() + 6); >+ BasicCredentials credentials = null; >+ try { >+ credentials = new BasicCredentials(authorizationBC); >+ String username = credentials.getUsername(); >+ String password = credentials.getPassword(); > >- byte[] decoded = Base64.decodeBase64( >- authorizationBC.getBuffer(), >- authorizationBC.getOffset(), >- authorizationBC.getLength()); >- >- // Get username and password >- int colon = -1; >- for (int i = 0; i < decoded.length; i++) { >- if (decoded[i] == ':') { >- colon = i; >- break; >- } >+ principal = context.getRealm().authenticate(username, password); >+ if (principal != null) { >+ register(request, response, principal, >+ HttpServletRequest.BASIC_AUTH, username, password); >+ return (true); > } >- >- if (colon < 0) { >- username = new String(decoded, B2CConverter.ISO_8859_1); >- } else { >- username = new String( >- decoded, 0, colon, B2CConverter.ISO_8859_1); >- password = new String( >- decoded, colon + 1, decoded.length - colon - 1, >- B2CConverter.ISO_8859_1); >+ } >+ catch (IllegalArgumentException iae) { >+ if (log.isDebugEnabled()) { >+ log.debug("Invalid Authorization" + iae.getMessage()); > } >- >- authorizationBC.setOffset(authorizationBC.getOffset() - 6); > } >- >- principal = context.getRealm().authenticate(username, password); >- if (principal != null) { >- register(request, response, principal, >- HttpServletRequest.BASIC_AUTH, username, password); >- return (true); >- } > } > >+ // the request could not be authenticated, so reissue the challenge > StringBuilder value = new StringBuilder(16); > value.append("Basic realm=\""); > value.append(getRealmName(context)); >@@ -156,9 +135,139 @@ > > } > >- > @Override > protected String getAuthMethod() { > return HttpServletRequest.BASIC_AUTH; > } >+ >+ >+ /** >+ * Parser for an HTTP Authorization header for BASIC authentication >+ * as per RFC 2617 section 2, and the Base64 encoded credentials as >+ * per RFC 2045 section 6.8. >+ */ >+ protected static class BasicCredentials { >+ >+ // the only authentication method supported by this parser >+ // note: we include single white space as its delimiter >+ private static final String METHOD = "basic "; >+ >+ private ByteChunk authorization; >+ private int initialOffset; >+ private int base64blobOffset; >+ private int base64blobLength; >+ >+ private String username = null; >+ private String password = null; >+ >+ /** >+ * Parse the HTTP Authorization header for BASIC authentication >+ * as per RFC 2617 section 2, and the Base64 encoded credentials >+ * as per RFC 2045 section 6.8. >+ * >+ * @param input The header value to parse in-place >+ * >+ * @throws IllegalArgumentException If the header does not conform >+ * to RFC 2617 >+ */ >+ public BasicCredentials(ByteChunk input) >+ throws IllegalArgumentException { >+ authorization = input; >+ initialOffset = input.getOffset(); >+ parseMethod(); >+ byte[] decoded = parseBase64(); >+ parseCredentials(decoded); >+ } >+ >+ /** >+ * Trivial accessor. >+ * >+ * @return the decoded username token as a String, which is >+ * never be <code>null</code>, but can be empty. >+ */ >+ public String getUsername() { >+ return username; >+ } >+ >+ /** >+ * Trivial accessor. >+ * >+ * @return the decoded password token as a String, or <code>null</code> >+ * if no password was found in the credentials. >+ */ >+ public String getPassword() { >+ return password; >+ } >+ >+ /* >+ * The authorization method string is case-insensitive and must >+ * hae at least one space character as a delimiter. >+ */ >+ private void parseMethod() throws IllegalArgumentException { >+ if (authorization.startsWithIgnoreCase(METHOD, 0)) { >+ // step past the auth method name >+ base64blobOffset = initialOffset + METHOD.length(); >+ base64blobLength = authorization.getLength() - METHOD.length(); >+ } >+ else { >+ // is this possible, or permitted? >+ throw new IllegalArgumentException( >+ "Authorization header method is not \"Basic\""); >+ } >+ } >+ /* >+ * Decode the base64-user-pass token, which RFC 2617 states >+ * can be longer than the 76 characters per line limit defined >+ * in RFC 2045. The base64 decoder will ignore embedded line >+ * break characters as well as surplus surrounding white space. >+ */ >+ private byte[] parseBase64() throws IllegalArgumentException { >+ byte[] decoded = Base64.decodeBase64( >+ authorization.getBuffer(), >+ base64blobOffset, base64blobLength); >+ // restore original offset >+ authorization.setOffset(initialOffset); >+ if (decoded == null) { >+ throw new IllegalArgumentException( >+ "Basic Authorization credentials are not Base64"); >+ } >+ return decoded; >+ } >+ >+ /* >+ * Extract the mandatory username token and separate it from the >+ * optional password token. Tolerate surplus surrounding white space. >+ */ >+ private void parseCredentials(byte[] decoded) >+ throws IllegalArgumentException { >+ >+ int colon = -1; >+ for (int i = 0; i < decoded.length; i++) { >+ if (decoded[i] == ':') { >+ colon = i; >+ break; >+ } >+ } >+ >+ if (colon < 0) { >+ username = new String(decoded, B2CConverter.ISO_8859_1); >+ // password will remain null! >+ } >+ else { >+ username = new String( >+ decoded, 0, colon, B2CConverter.ISO_8859_1); >+ password = new String( >+ decoded, colon + 1, decoded.length - colon - 1, >+ B2CConverter.ISO_8859_1); >+ // tolerate surplus white space around credentials >+ if (password.length() > 1) { >+ password = password.trim(); >+ } >+ } >+ // tolerate surplus white space around credentials >+ if (username.length() > 1) { >+ username = username.trim(); >+ } >+ } >+ } > }
You cannot view the attachment while viewing its details because your browser does not support IFRAMEs.
View the attachment on a separate page
.
View Attachment As Diff
View Attachment As Raw
Actions:
View
|
Diff
Attachments on
bug 55101
: 30435 |
30436
|
30437
|
30636