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: * Free SoftwareFoundation, Inc.
023: * 59 Temple Place, Suite 330
024: * Boston, MA 02111-1307 USA
025: *
026: * @author Scott Ferguson
027: */
028:
029: package com.caucho.server.security;
030:
031: import com.caucho.config.ConfigException;
032: import com.caucho.server.connection.CauchoResponse;
033: import com.caucho.server.webapp.Application;
034: import com.caucho.util.L10N;
035:
036: import javax.annotation.PostConstruct;
037: import javax.servlet.RequestDispatcher;
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.servlet.http.HttpSession;
043: import java.io.IOException;
044: import java.security.Principal;
045: import java.util.logging.Level;
046:
047: /**
048: * Used to authenticate users in a servlet request. Applications will
049: * implement the Authenticator interface with a bean for authentication.
050: *
051: * @since Resin 2.0.2
052: */
053: public class FormLogin extends AbstractLogin {
054: static L10N L = new L10N(FormLogin.class);
055:
056: public static final String LOGIN_SAVED_PATH = "com.caucho.servlet.login.path";
057: public static final String LOGIN_SAVED_QUERY = "com.caucho.servlet.login.query";
058:
059: protected String _loginPage;
060: protected String _errorPage;
061: protected boolean _internalForward;
062: protected boolean _formURIPriority;
063:
064: /**
065: * Sets the login page.
066: */
067: public void setFormLoginPage(String formLoginPage)
068: throws ConfigException {
069: int colon = formLoginPage.indexOf(':');
070: int slash = formLoginPage.indexOf('/');
071:
072: if (colon > 0 && colon < slash) {
073: } else if (slash != 0)
074: throw new ConfigException(
075: L
076: .l(
077: "form-login-page '{0}' must start with '/'. The form-login-page is relative to the web-app root.",
078: formLoginPage));
079:
080: _loginPage = formLoginPage;
081: }
082:
083: public void setLoginPage(String loginPage) {
084: setFormLoginPage(loginPage);
085: }
086:
087: /**
088: * Gets the login page.
089: */
090: public String getFormLoginPage() {
091: return _loginPage;
092: }
093:
094: /**
095: * Sets the error page.
096: */
097: public void setFormErrorPage(String formErrorPage)
098: throws ConfigException {
099: if (!formErrorPage.startsWith("/"))
100: throw new ConfigException(
101: L
102: .l(
103: "form-error-page '{0}' must start with '/'. The form-error-page is relative to the web-app root.",
104: formErrorPage));
105:
106: _errorPage = formErrorPage;
107: }
108:
109: public void setErrorPage(String errorPage) {
110: setFormErrorPage(errorPage);
111: }
112:
113: /**
114: * Gets the error page.
115: */
116: public String getFormErrorPage() {
117: return _errorPage;
118: }
119:
120: /**
121: * Returns true if a successful login allows an internal forward
122: * instead of a redirect.
123: */
124: public boolean getInternalForward() {
125: return _internalForward;
126: }
127:
128: /**
129: * Set true if a successful login allows an internal forward
130: * instead of a redirect.
131: */
132: public void setInternalForward(boolean internalForward) {
133: _internalForward = internalForward;
134: }
135:
136: /**
137: * Returns true if the form's j_uri has priority over the saved
138: * URL.
139: */
140: public boolean getFormURIPriority() {
141: return _formURIPriority;
142: }
143:
144: /**
145: * True if the form's j_uri has priority over the saved URL.
146: */
147: public void setFormURIPriority(boolean formPriority) {
148: _formURIPriority = formPriority;
149: }
150:
151: /**
152: * Initialize
153: */
154: @PostConstruct
155: public void init() throws ServletException {
156: super .init();
157:
158: if (_errorPage == null)
159: _errorPage = _loginPage;
160:
161: if (_loginPage == null)
162: _loginPage = _errorPage;
163:
164: if (_loginPage == null)
165: throw new ConfigException(L
166: .l("FormLogin needs an form-login-page"));
167: }
168:
169: /**
170: * Returns the authentication type.
171: */
172: public String getAuthType() {
173: return "Form";
174: }
175:
176: /**
177: * Logs a user in with a user name and a password.
178: *
179: * @param request servlet request
180: * @param response servlet response, in case any cookie need sending.
181: * @param application servlet application
182: *
183: * @return the logged in principal on success, null on failure.
184: */
185: public Principal authenticate(HttpServletRequest request,
186: HttpServletResponse response, ServletContext application)
187: throws ServletException, IOException {
188: Principal user = getUserPrincipal(request, response,
189: application);
190:
191: if (user != null)
192: return user;
193:
194: String path = request.getServletPath();
195: if (path == null)
196: path = request.getPathInfo();
197: else if (request.getPathInfo() != null)
198: path = path + request.getPathInfo();
199:
200: if (path.equals("")) {
201: // Forward?
202: path = request.getContextPath() + "/";
203: response.sendRedirect(response.encodeRedirectURL(path));
204: return null;
205: }
206:
207: Application app = (Application) application;
208:
209: String uri = request.getRequestURI();
210:
211: if (path.endsWith("/j_security_check")) {
212: RequestDispatcher disp;
213: disp = application.getNamedDispatcher("j_security_check");
214:
215: if (disp == null)
216: throw new ServletException(
217: L
218: .l("j_security_check servlet must be defined to use form-based login."));
219:
220: disp.forward(request, response);
221: return null;
222: } else if (uri.equals(_loginPage) || uri.equals(_errorPage)) {
223: request.getRequestDispatcher(path).forward(request,
224: response);
225: return null;
226: }
227:
228: HttpSession session = request.getSession();
229:
230: session.putValue(LOGIN_SAVED_PATH, path);
231: session.putValue(LOGIN_SAVED_QUERY, request.getQueryString());
232:
233: if (response instanceof CauchoResponse) {
234: ((CauchoResponse) response).killCache();
235: ((CauchoResponse) response).setNoCache(true);
236: } else {
237: response.setHeader("Cache-Control", "no-cache");
238: }
239:
240: // In case where the authenticator is somethin like https:/
241: if (!_loginPage.startsWith("/")) {
242: response.sendRedirect(response
243: .encodeRedirectURL(_loginPage));
244: return null;
245: }
246:
247: // Forwards to the loginPage, never redirects according to the spec.
248: request.setAttribute("caucho.login", "login");
249: //RequestDispatcher disp = app.getLoginDispatcher(loginPage);
250: RequestDispatcher disp = app.getRequestDispatcher(_loginPage);
251: disp.forward(request, response);
252:
253: if (log.isLoggable(Level.FINE))
254: log.fine("the form request has no authenticated user");
255:
256: return null;
257: }
258: }
|