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 java.security.cert.X509Certificate;
022:
023: import javax.servlet.http.HttpServletRequest;
024: import javax.servlet.http.HttpServletResponse;
025:
026: import org.apache.catalina.Globals;
027: import org.apache.catalina.HttpRequest;
028: import org.apache.catalina.HttpResponse;
029: import org.apache.catalina.LifecycleException;
030: import org.apache.catalina.deploy.LoginConfig;
031:
032: /**
033: * An <b>Authenticator</b> and <b>Valve</b> implementation of authentication
034: * that utilizes SSL certificates to identify client users.
035: *
036: * @author Craig R. McClanahan
037: * @version $Revision: 1.12 $ $Date: 2004/02/27 14:58:41 $
038: */
039:
040: public class SSLAuthenticator extends AuthenticatorBase {
041:
042: // ------------------------------------------------------------- Properties
043:
044: /**
045: * Descriptive information about this implementation.
046: */
047: protected static final String info = "org.apache.catalina.authenticator.SSLAuthenticator/1.0";
048:
049: /**
050: * Return descriptive information about this Valve implementation.
051: */
052: public String getInfo() {
053:
054: return (info);
055:
056: }
057:
058: // --------------------------------------------------------- Public Methods
059:
060: /**
061: * Authenticate the user by checking for the existence of a certificate
062: * chain, and optionally asking a trust manager to validate that we trust
063: * this user.
064: *
065: * @param request Request we are processing
066: * @param response Response we are creating
067: * @param config Login configuration describing how authentication
068: * should be performed
069: *
070: * @exception IOException if an input/output error occurs
071: */
072: public boolean authenticate(HttpRequest request,
073: HttpResponse response, LoginConfig config)
074: throws IOException {
075:
076: // Have we already authenticated someone?
077: Principal principal = ((HttpServletRequest) request
078: .getRequest()).getUserPrincipal();
079: //String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE);
080: if (principal != null) {
081: if (debug >= 1)
082: log("Already authenticated '" + principal.getName()
083: + "'");
084: // Associate the session with any existing SSO session in order
085: // to get coordinated session invalidation at logout
086: String ssoId = (String) request
087: .getNote(Constants.REQ_SSOID_NOTE);
088: if (ssoId != null)
089: associate(ssoId, getSession(request, true));
090: return (true);
091: }
092:
093: // NOTE: We don't try to reauthenticate using any existing SSO session,
094: // because that will only work if the original authentication was
095: // BASIC or FORM, which are less secure than the CLIENT-CERT auth-type
096: // specified for this webapp
097: //
098: // Uncomment below to allow previous FORM or BASIC authentications
099: // to authenticate users for this webapp
100: // TODO make this a configurable attribute (in SingleSignOn??)
101: /*
102: // Is there an SSO session against which we can try to reauthenticate?
103: if (ssoId != null) {
104: if (log.isDebugEnabled())
105: log.debug("SSO Id " + ssoId + " set; attempting " +
106: "reauthentication");
107: // Try to reauthenticate using data cached by SSO. If this fails,
108: // either the original SSO logon was of DIGEST or SSL (which
109: // we can't reauthenticate ourselves because there is no
110: // cached username and password), or the realm denied
111: // the user's reauthentication for some reason.
112: // In either case we have to prompt the user for a logon
113: if (reauthenticateFromSSO(ssoId, request))
114: return true;
115: }
116: */
117:
118: // Retrieve the certificate chain for this client
119: HttpServletResponse hres = (HttpServletResponse) response
120: .getResponse();
121: if (debug >= 1)
122: log(" Looking up certificates");
123:
124: X509Certificate certs[] = (X509Certificate[]) request
125: .getRequest().getAttribute(Globals.CERTIFICATES_ATTR);
126: if ((certs == null) || (certs.length < 1)) {
127: certs = (X509Certificate[]) request.getRequest()
128: .getAttribute(Globals.SSL_CERTIFICATE_ATTR);
129: }
130: if ((certs == null) || (certs.length < 1)) {
131: if (debug >= 1)
132: log(" No certificates included with this request");
133: hres.sendError(HttpServletResponse.SC_BAD_REQUEST, sm
134: .getString("authenticator.certificates"));
135: return (false);
136: }
137:
138: // Authenticate the specified certificate chain
139: principal = context.getRealm().authenticate(certs);
140: if (principal == null) {
141: if (debug >= 1)
142: log(" Realm.authenticate() returned false");
143: hres.sendError(HttpServletResponse.SC_UNAUTHORIZED, sm
144: .getString("authenticator.unauthorized"));
145: return (false);
146: }
147:
148: // Cache the principal (if requested) and record this authentication
149: register(request, response, principal, Constants.CERT_METHOD,
150: null, null);
151: return (true);
152:
153: }
154:
155: // ------------------------------------------------------ Lifecycle Methods
156:
157: /**
158: * Initialize the database we will be using for client verification
159: * and certificate validation (if any).
160: *
161: * @exception LifecycleException if this component detects a fatal error
162: * that prevents this component from being used
163: */
164: public void start() throws LifecycleException {
165:
166: super .start();
167:
168: }
169:
170: /**
171: * Finalize the database we used for client verification and
172: * certificate validation (if any).
173: *
174: * @exception LifecycleException if this component detects a fatal error
175: * that prevents this component from being used
176: */
177: public void stop() throws LifecycleException {
178:
179: super.stop();
180:
181: }
182:
183: }
|