001: /*
002: * Copyright 1999,2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.apache.catalina.authenticator;
018:
019: import java.io.IOException;
020: import java.security.Principal;
021: import javax.servlet.http.HttpServletRequest;
022: import javax.servlet.http.HttpServletResponse;
023: import org.apache.catalina.HttpRequest;
024: import org.apache.catalina.HttpResponse;
025: import org.apache.catalina.deploy.LoginConfig;
026: import org.apache.catalina.util.Base64;
027: import org.apache.commons.logging.Log;
028: import org.apache.commons.logging.LogFactory;
029:
030: /**
031: * An <b>Authenticator</b> and <b>Valve</b> implementation of HTTP BASIC
032: * Authentication, as outlined in RFC 2617: "HTTP Authentication: Basic
033: * and Digest Access Authentication."
034: *
035: * @author Craig R. McClanahan
036: * @version $Revision: 1.6 $ $Date: 2004/05/16 14:42:36 $
037: */
038:
039: public class BasicAuthenticator extends AuthenticatorBase {
040: private static Log log = LogFactory
041: .getLog(BasicAuthenticator.class);
042:
043: // ----------------------------------------------------- Instance Variables
044:
045: /**
046: * Descriptive information about this implementation.
047: */
048: protected static final String info = "org.apache.catalina.authenticator.BasicAuthenticator/1.0";
049:
050: // ------------------------------------------------------------- Properties
051:
052: /**
053: * Return descriptive information about this Valve implementation.
054: */
055: public String getInfo() {
056:
057: return (info);
058:
059: }
060:
061: // --------------------------------------------------------- Public Methods
062:
063: /**
064: * Authenticate the user making this request, based on the specified
065: * login configuration. Return <code>true</code> if any specified
066: * constraint has been satisfied, or <code>false</code> if we have
067: * created a response challenge already.
068: *
069: * @param request Request we are processing
070: * @param response Response we are creating
071: * @param config Login configuration describing how authentication
072: * should be performed
073: *
074: * @exception IOException if an input/output error occurs
075: */
076: public boolean authenticate(HttpRequest request,
077: HttpResponse response, LoginConfig config)
078: throws IOException {
079:
080: // Have we already authenticated someone?
081: Principal principal = ((HttpServletRequest) request
082: .getRequest()).getUserPrincipal();
083: String ssoId = (String) request
084: .getNote(Constants.REQ_SSOID_NOTE);
085: if (principal != null) {
086: if (log.isDebugEnabled())
087: log.debug("Already authenticated '"
088: + principal.getName() + "'");
089: // Associate the session with any existing SSO session
090: if (ssoId != null)
091: associate(ssoId, getSession(request, true));
092: return (true);
093: }
094:
095: // Is there an SSO session against which we can try to reauthenticate?
096: if (ssoId != null) {
097: if (log.isDebugEnabled())
098: log.debug("SSO Id " + ssoId + " set; attempting "
099: + "reauthentication");
100: /* Try to reauthenticate using data cached by SSO. If this fails,
101: either the original SSO logon was of DIGEST or SSL (which
102: we can't reauthenticate ourselves because there is no
103: cached username and password), or the realm denied
104: the user's reauthentication for some reason.
105: In either case we have to prompt the user for a logon */
106: if (reauthenticateFromSSO(ssoId, request))
107: return true;
108: }
109:
110: // Validate any credentials already included with this request
111: HttpServletRequest hreq = (HttpServletRequest) request
112: .getRequest();
113: HttpServletResponse hres = (HttpServletResponse) response
114: .getResponse();
115: String authorization = request.getAuthorization();
116: String username = parseUsername(authorization);
117: String password = parsePassword(authorization);
118: principal = context.getRealm().authenticate(username, password);
119: if (principal != null) {
120: register(request, response, principal,
121: Constants.BASIC_METHOD, username, password);
122: return (true);
123: }
124:
125: // Send an "unauthorized" response and an appropriate challenge
126: String realmName = config.getRealmName();
127: if (realmName == null)
128: realmName = hreq.getServerName() + ":"
129: + hreq.getServerPort();
130: // if (log.isDebugEnabled())
131: // log.debug("Challenging for realm '" + realmName + "'");
132: hres.setHeader("WWW-Authenticate", "Basic realm=\"" + realmName
133: + "\"");
134: hres.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
135: // hres.flushBuffer();
136: return (false);
137:
138: }
139:
140: // ------------------------------------------------------ Protected Methods
141:
142: /**
143: * Parse the username from the specified authorization credentials.
144: * If none can be found, return <code>null</code>.
145: *
146: * @param authorization Authorization credentials from this request
147: */
148: protected String parseUsername(String authorization) {
149:
150: if (authorization == null)
151: return (null);
152: if (!authorization.toLowerCase().startsWith("basic "))
153: return (null);
154: authorization = authorization.substring(6).trim();
155:
156: // Decode and parse the authorization credentials
157: String unencoded = new String(Base64.decode(authorization
158: .getBytes()));
159: int colon = unencoded.indexOf(':');
160: if (colon < 0)
161: return (null);
162: String username = unencoded.substring(0, colon);
163: // String password = unencoded.substring(colon + 1).trim();
164: return (username);
165:
166: }
167:
168: /**
169: * Parse the password from the specified authorization credentials.
170: * If none can be found, return <code>null</code>.
171: *
172: * @param authorization Authorization credentials from this request
173: */
174: protected String parsePassword(String authorization) {
175:
176: if (authorization == null)
177: return (null);
178: if (!authorization.startsWith("Basic "))
179: return (null);
180: authorization = authorization.substring(6).trim();
181:
182: // Decode and parse the authorization credentials
183: String unencoded = new String(Base64.decode(authorization
184: .getBytes()));
185: int colon = unencoded.indexOf(':');
186: if (colon < 0)
187: return (null);
188: // String username = unencoded.substring(0, colon).trim();
189: String password = unencoded.substring(colon + 1);
190: return (password);
191:
192: }
193:
194: }
|