/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * Free SoftwareFoundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.server.security; import com.caucho.security.FormLogin; import com.caucho.security.Login; import com.caucho.security.LoginList; import com.caucho.server.http.CauchoResponse; import com.caucho.server.webapp.WebApp; import com.caucho.server.webapp.RequestDispatcherImpl; import com.caucho.util.L10N; import javax.servlet.GenericServlet; import javax.servlet.RequestDispatcher; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; import java.io.IOException; import java.security.Principal; import java.util.logging.Level; import java.util.logging.Logger; public class FormLoginServlet extends GenericServlet { private final Logger log = Logger.getLogger(FormLoginServlet.class.getName()); private static final L10N L = new L10N(FormLoginServlet.class); @Override public void service(ServletRequest request, ServletResponse response) throws ServletException, IOException { HttpServletRequest req = (HttpServletRequest) request; HttpServletResponse res = (HttpServletResponse) response; WebApp webApp = (WebApp) getServletContext(); FormLogin login = getFormLogin(webApp.getLogin()); Principal user = login.login(req, res, true); if (log.isLoggable(Level.FINE)) log.fine(this + " login " + user + " using " + login); if (res.isCommitted()) return; if (user == null) { // A failure internally redirects to the error page (not redirect) String errorPage = login.getFormErrorPage(); RequestDispatcherImpl disp; disp = (RequestDispatcherImpl) webApp.getRequestDispatcher(errorPage); // req.setAttribute("caucho.login", "login"); if (res instanceof CauchoResponse) { ((CauchoResponse) res).killCache(); ((CauchoResponse) res).setNoCache(true); } else { res.setDateHeader("Expires", 0); res.setHeader("Cache-Control", "no-cache"); } disp.error(req, res); return; } HttpSession session = req.getSession(); String uri = (String) session.getAttribute(FormLogin.LOGIN_SAVED_PATH); String query = (String) session.getAttribute(FormLogin.LOGIN_SAVED_QUERY); session.removeAttribute(FormLogin.LOGIN_SAVED_PATH); session.removeAttribute(FormLogin.LOGIN_SAVED_QUERY); if (log.isLoggable(Level.FINE)) { log.fine("old path:" + uri + " query:" + query + " j_uri:" + req.getParameter("j_uri")); } boolean formURIPriority = login.getFormURIPriority(); // The saved uri has priority. if ((uri == null || formURIPriority) && req.getParameter("j_uri") != null) uri = req.getParameter("j_uri"); else if (uri != null && query != null) uri = uri + "?" + query; if (uri == null) { log.warning(L.l("FormLogin: session has timed out for session '{0}'", req.getSession().getId())); RequestDispatcher disp = request.getRequestDispatcher("/"); if (disp != null) { disp.forward(request, response); return; } else { throw new ServletException(L.l("Session has timed out for form authentication, no forwarding URI is available. Either the login form must specify j_uri or the session must have a saved URI.")); } } if (uri.indexOf('\n') >= 0 || uri.indexOf('\r') >= 0) throw new ServletException(L.l("Forwarding URI '{0}' is invalid.", uri)); String uriPwd = req.getRequestURI(); int p = uriPwd.indexOf("/j_security_check"); if (p >= 0) uriPwd = uriPwd.substring(0, p + 1); if (uri.length() == 0) { } else if (uri.charAt(0) == '/') uri = req.getContextPath() + uri; else if (uri.indexOf(':') >= 0 && (uri.indexOf(':') < uri.indexOf('/') || uri.indexOf('/') < 0)) { } else { uri = uriPwd + uri; } // The spec says that a successful login uses a redirect. Resin // adds a configuration option to allow an internal forward // if the URL is in the same directory. // Logins to POST pages need to use an internal forward. // Most GETs will want a redirect. boolean useInternalForward = login.getInternalForward(); if (useInternalForward && uri.startsWith(uriPwd) && uri.indexOf('/', uriPwd.length() + 1) < 0) { WebApp newApp = (WebApp) webApp.getContext(uri); String suffix = uri.substring(newApp.getContextPath().length()); // force authorization of the page because the normal forward() // bypasses authorization RequestDispatcher disp = newApp.getLoginDispatcher(suffix); if (disp != null) { disp.forward(req, res); return; } } res.sendRedirect(res.encodeRedirectURL(uri)); } private FormLogin getFormLogin(Login login) throws ServletException { if (login == null) throw new ServletException(L.l("j_security_check requires a login")); if (login instanceof FormLogin) return (FormLogin) login; else if (login instanceof LoginList) { for (Login subLogin : ((LoginList) login).getLoginList()) { if (subLogin instanceof FormLogin) return (FormLogin) subLogin; } } throw new ServletException(L.l("FormLoginServlet requires a form login auth-type configuration at '{0}' in '{1}'", login != null ? login.getAuthType() : null, getServletContext())); } }