001: /*
002: * Copyright 2003-2006 Rick Knowles <winstone-devel at lists sourceforge net>
003: * Distributed under the terms of either:
004: * - the common development and distribution license (CDDL), v1.0; or
005: * - the GNU Lesser General Public License, v2.1 or later
006: */
007: package winstone.auth;
008:
009: import java.io.IOException;
010: import java.util.List;
011: import java.util.Set;
012:
013: import javax.servlet.http.HttpServletRequest;
014: import javax.servlet.http.HttpServletRequestWrapper;
015: import javax.servlet.http.HttpServletResponse;
016:
017: import org.w3c.dom.Node;
018:
019: import winstone.AuthenticationPrincipal;
020: import winstone.AuthenticationRealm;
021: import winstone.Logger;
022: import winstone.WinstoneRequest;
023:
024: /**
025: * Handles HTTP basic authentication.
026: *
027: * @author mailto: <a href="rick_knowles@hotmail.com">Rick Knowles</a>
028: * @version $Id: BasicAuthenticationHandler.java,v 1.5 2007/04/11 13:14:26 rickknowles Exp $
029: */
030: public class BasicAuthenticationHandler extends
031: BaseAuthenticationHandler {
032: public BasicAuthenticationHandler(Node loginConfigNode,
033: List constraintNodes, Set rolesAllowed,
034: AuthenticationRealm realm) {
035: super (loginConfigNode, constraintNodes, rolesAllowed, realm);
036: Logger.log(Logger.DEBUG, AUTH_RESOURCES,
037: "BasicAuthenticationHandler.Initialised", realmName);
038: }
039:
040: /**
041: * Call this once we know that we need to authenticate
042: */
043: protected void requestAuthentication(HttpServletRequest request,
044: HttpServletResponse response, String pathRequested)
045: throws IOException {
046: // Return unauthorized, and set the realm name
047: response.setHeader("WWW-Authenticate", "Basic Realm=\""
048: + this .realmName + "\"");
049: response
050: .sendError(
051: HttpServletResponse.SC_UNAUTHORIZED,
052: AUTH_RESOURCES
053: .getString("BasicAuthenticationHandler.UnauthorizedMessage"));
054: }
055:
056: /**
057: * Handling the (possible) response
058: */
059: protected boolean validatePossibleAuthenticationResponse(
060: HttpServletRequest request, HttpServletResponse response,
061: String pathRequested) throws IOException {
062: String authorization = request.getHeader("Authorization");
063: if ((authorization != null)
064: && authorization.toLowerCase().startsWith("basic")) {
065:
066: char[] inBytes = authorization.substring(5).trim()
067: .toCharArray();
068: byte[] outBytes = new byte[(int) (inBytes.length * 0.75f)]; // always mod 4 = 0
069: int length = decodeBase64(inBytes, outBytes, 0,
070: inBytes.length, 0);
071:
072: String decoded = new String(outBytes, 0, length);
073: int delimPos = decoded.indexOf(':');
074: if (delimPos != -1) {
075: AuthenticationPrincipal principal = this .realm
076: .authenticateByUsernamePassword(decoded
077: .substring(0, delimPos).trim(), decoded
078: .substring(delimPos + 1).trim());
079: if (principal != null) {
080: principal
081: .setAuthType(HttpServletRequest.BASIC_AUTH);
082: if (request instanceof WinstoneRequest)
083: ((WinstoneRequest) request)
084: .setRemoteUser(principal);
085: else if (request instanceof HttpServletRequestWrapper) {
086: HttpServletRequestWrapper wrapper = (HttpServletRequestWrapper) request;
087: if (wrapper.getRequest() instanceof WinstoneRequest)
088: ((WinstoneRequest) wrapper.getRequest())
089: .setRemoteUser(principal);
090: else
091: Logger
092: .log(
093: Logger.WARNING,
094: AUTH_RESOURCES,
095: "BasicAuthenticationHandler.CantSetUser",
096: wrapper.getRequest()
097: .getClass()
098: .getName());
099: } else
100: Logger
101: .log(
102: Logger.WARNING,
103: AUTH_RESOURCES,
104: "BasicAuthenticationHandler.CantSetUser",
105: request.getClass().getName());
106: }
107: }
108: }
109: return true;
110: }
111:
112: /**
113: * Decodes a byte array from base64
114: */
115: public static int decodeBase64(char[] input, byte[] output,
116: int inOffset, int inLength, int outOffset) {
117: if (inLength == 0) {
118: return 0;
119: }
120:
121: int outIndex = outOffset;
122: for (int inIndex = inOffset; inIndex < inLength;) {
123: // Decode four bytes
124: int this PassInBytes = Math.min(inLength - inIndex, 4);
125: while ((this PassInBytes > 1)
126: && (input[inIndex + this PassInBytes - 1] == '=')) {
127: this PassInBytes--;
128: }
129:
130: if (this PassInBytes == 2) {
131: int outBuffer = ((B64_DECODE_ARRAY[input[inIndex]] & 0xFF) << 18)
132: | ((B64_DECODE_ARRAY[input[inIndex + 1]] & 0xFF) << 12);
133: output[outIndex] = (byte) ((outBuffer >> 16) & 0xFF);
134: outIndex += 1;
135: } else if (this PassInBytes == 3) {
136: int outBuffer = ((B64_DECODE_ARRAY[input[inIndex]] & 0xFF) << 18)
137: | ((B64_DECODE_ARRAY[input[inIndex + 1]] & 0xFF) << 12)
138: | ((B64_DECODE_ARRAY[input[inIndex + 2]] & 0xFF) << 6);
139: output[outIndex] = (byte) ((outBuffer >> 16) & 0xFF);
140: output[outIndex + 1] = (byte) ((outBuffer >> 8) & 0xFF);
141: outIndex += 2;
142: } else if (this PassInBytes == 4) {
143: int outBuffer = ((B64_DECODE_ARRAY[input[inIndex]] & 0xFF) << 18)
144: | ((B64_DECODE_ARRAY[input[inIndex + 1]] & 0xFF) << 12)
145: | ((B64_DECODE_ARRAY[input[inIndex + 2]] & 0xFF) << 6)
146: | (B64_DECODE_ARRAY[input[inIndex + 3]] & 0xFF);
147: output[outIndex] = (byte) ((outBuffer >> 16) & 0xFF);
148: output[outIndex + 1] = (byte) ((outBuffer >> 8) & 0xFF);
149: output[outIndex + 2] = (byte) (outBuffer & 0xFF);
150: outIndex += 3;
151: }
152: inIndex += this PassInBytes;
153: }
154: return outIndex;
155: }
156:
157: private static byte B64_DECODE_ARRAY[] = new byte[] { -1, -1, -1,
158: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
159: -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
160: -1, -1, -1, -1, -1, -1, -1,
161: -1,
162: -1,
163: -1,
164: 62, // Plus sign
165: -1,
166: -1,
167: -1,
168: 63, // Slash
169: 52, 53, 54, 55, 56, 57,
170: 58,
171: 59,
172: 60,
173: 61, // Numbers
174: -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
175: 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
176: 23,
177: 24,
178: 25, // Large letters
179: -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34,
180: 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
181: 50, 51, // Small letters
182: -1, -1, -1, -1 };
183: }
|