001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.server.security;
031:
032: import com.caucho.webbeans.component.*;
033: import com.caucho.webbeans.manager.*;
034:
035: import javax.annotation.PostConstruct;
036: import javax.naming.Context;
037: import javax.naming.InitialContext;
038: import javax.servlet.ServletContext;
039: import javax.servlet.ServletException;
040: import javax.servlet.http.HttpServletRequest;
041: import javax.servlet.http.HttpServletResponse;
042: import javax.webbeans.*;
043: import java.io.IOException;
044: import java.security.Principal;
045: import java.util.logging.Level;
046: import java.util.logging.Logger;
047:
048: /**
049: * Used to authenticate users in a servlet request. AbstractLogin handles
050: * the different login types like "basic" or "form". Normally, a Login
051: * will delegate the actual authentication to a ServletAuthenticator.
052: *
053: * <p>The Login is primarily responsible for extracting the credentials
054: * from the request (typically username and password) and passing those
055: * to the ServletAuthenticator.
056: *
057: * <p>The Servlet API calls the Login in two contexts: directly from
058: * <code>ServletRequest.getUserPrincipal()</code>, and during
059: * security checking. When called from the Servlet API, the login class
060: * can't change the response. In other words, if an application
061: * calls getUserPrincipal(), the Login class can't return a forbidden
062: * error page. When the servlet engine calls authenticate(), the login class
063: * can return an error page (or forward internally.)
064: *
065: * <p>Normally, Login implementations will defer the actual authentication
066: * to a ServletAuthenticator class. That way, both "basic" and "form" login
067: * can use the same JdbcAuthenticator. Some applications, like SSL
068: * client certificate login, may want to combine the Login and authentication
069: * into one class.
070: *
071: * <p>Login instances are configured through bean introspection. Adding
072: * a public <code>setFoo(String foo)</code> method will be configured with
073: * the following login-config:
074: *
075: * <code><pre>
076: * <login-config>
077: * <class-name>test.CustomLogin</class-name>
078: * <foo>bar</bar>
079: * </login-config>
080: * </pre></code>
081: *
082: * @since Resin 2.0.2
083: */
084: public abstract class AbstractLogin implements LoginFilter {
085: protected final static Logger log = Logger
086: .getLogger(AbstractLogin.class.getName());
087:
088: /**
089: * The configured authenticator for the login. Implementing classes will
090: * typically delegate calls to the authenticator after extracting the
091: * username and password.
092: */
093: protected ServletAuthenticator _auth;
094:
095: /**
096: * Sets the authenticator.
097: */
098: public void setAuthenticator(ServletAuthenticator auth) {
099: _auth = auth;
100: }
101:
102: /**
103: * Gets the authenticator.
104: */
105: public ServletAuthenticator getAuthenticator() {
106: if (_auth == null) {
107: try {
108: WebBeansContainer webBeans = WebBeansContainer.create();
109:
110: ComponentFactory factory = webBeans
111: .resolveByType(ServletAuthenticator.class);
112:
113: if (factory != null)
114: _auth = (ServletAuthenticator) factory.get();
115: } catch (Exception e) {
116: log.log(Level.FINER, e.toString(), e);
117: }
118:
119: if (_auth == null)
120: _auth = new NullAuthenticator();
121:
122: if (log.isLoggable(Level.FINE))
123: log.fine(toString() + " using " + _auth);
124: }
125:
126: return _auth;
127: }
128:
129: /**
130: * Initialize the login. <code>init()</code> will be called after all
131: * the bean parameters have been set.
132: */
133: @PostConstruct
134: public void init() throws ServletException {
135: }
136:
137: /**
138: * Returns the authentication type. <code>getAuthType</code> is called
139: * by <code>HttpServletRequest.getAuthType</code>.
140: */
141: public String getAuthType() {
142: return "none";
143: }
144:
145: /**
146: * Logs a user in. The authenticate method is called during the
147: * security check. If the user does not exist, <code>authenticate</code>
148: * sets the reponse error page and returns null.
149: *
150: * @param request servlet request
151: * @param response servlet response for a failed authentication.
152: * @param application servlet application
153: *
154: * @return the logged in principal on success, null on failure.
155: */
156: public Principal authenticate(HttpServletRequest request,
157: HttpServletResponse response, ServletContext application)
158: throws ServletException, IOException {
159: // Most login classes will extract the user and password (or some other
160: // credentials) from the request and call auth.login.
161: Principal user = getUserPrincipal(request, response,
162: application);
163:
164: if (user == null)
165: response.sendError(HttpServletResponse.SC_FORBIDDEN);
166:
167: return user;
168: }
169:
170: /**
171: * Returns the Principal associated with the current request.
172: * getUserPrincipal is called in response to the Request.getUserPrincipal
173: * call. Login.getUserPrincipal can't modify the response or return
174: * an error page.
175: *
176: * <p/>authenticate is used for the security checks.
177: *
178: * @param request servlet request
179: * @param application servlet application
180: *
181: * @return the logged in principal on success, null on failure.
182: */
183: public Principal getUserPrincipal(HttpServletRequest request,
184: HttpServletResponse response, ServletContext application)
185: throws ServletException {
186: return getAuthenticator().getUserPrincipal(request, response,
187: application);
188: }
189:
190: /**
191: * Returns true if the current user plays the named role.
192: * <code>isUserInRole</code> is called in response to the
193: * <code>HttpServletRequest.isUserInRole</code> call.
194: *
195: * @param request servlet request
196: * @param application servlet application
197: *
198: * @return the logged in principal on success, null on failure.
199: */
200: public boolean isUserInRole(HttpServletRequest request,
201: HttpServletResponse response, ServletContext application,
202: Principal user, String role) throws ServletException {
203: return getAuthenticator().isUserInRole(request, response,
204: application, user, role);
205: }
206:
207: /**
208: * Logs the user out from the given request.
209: *
210: * <p>Since there is no servlet API for logout, this must be called
211: * directly from user code. Resin stores the web-app's login object
212: * in the ServletContext attribute "caucho.login".
213: */
214: public void logout(HttpServletRequest request,
215: HttpServletResponse response, ServletContext application)
216: throws ServletException {
217: Principal principal = getUserPrincipal(request, response,
218: application);
219:
220: if (principal != null)
221: getAuthenticator().logout(application, null,
222: request.getRequestedSessionId(), principal);
223: }
224:
225: @Override
226: public String toString() {
227: return getClass().getSimpleName() + "[]";
228: }
229: }
|