/* * 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 Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.server.http; import com.caucho.util.CharBuffer; import com.caucho.util.L10N; import com.caucho.vfs.*; import com.caucho.network.listen.SocketLink; import com.caucho.server.dispatch.ServletInvocation; import com.caucho.server.session.SessionImpl; import com.caucho.server.session.SessionManager; import com.caucho.server.webapp.WebApp; import com.caucho.security.AbstractLogin; import com.caucho.security.Authenticator; import com.caucho.security.RoleMapManager; import com.caucho.security.Login; import com.caucho.util.Alarm; import java.io.*; import java.util.*; import java.util.logging.*; import java.security.*; import javax.servlet.*; import javax.servlet.http.*; abstract public class AbstractCauchoRequest implements CauchoRequest { private static final L10N L = new L10N(AbstractCauchoRequest.class); private static final Logger log = Logger.getLogger(AbstractCauchoRequest.class.getName()); private int _sessionGroup = -1; private boolean _sessionIsLoaded; private SessionImpl _session; abstract public CauchoResponse getResponse(); public RequestDispatcher getRequestDispatcher(String path) { if (path == null || path.length() == 0) return null; else if (path.charAt(0) == '/') return getWebApp().getRequestDispatcher(path); else { CharBuffer cb = new CharBuffer(); WebApp webApp = getWebApp(); String servletPath = getPageServletPath(); if (servletPath != null) cb.append(servletPath); String pathInfo = getPagePathInfo(); if (pathInfo != null) cb.append(pathInfo); int p = cb.lastIndexOf('/'); if (p >= 0) cb.setLength(p); cb.append('/'); cb.append(path); if (webApp != null) return webApp.getRequestDispatcher(cb.toString()); return null; } } public String getRealPath(String uri) { WebApp webApp = getWebApp(); return webApp.getRealPath(uri); } /** * Returns the URL for the request */ public StringBuffer getRequestURL() { StringBuffer sb = new StringBuffer(); sb.append(getScheme()); sb.append("://"); sb.append(getServerName()); int port = getServerPort(); if (port > 0 && port != 80 && port != 443) { sb.append(":"); sb.append(port); } sb.append(getRequestURI()); return sb; } /** * Returns the real path of pathInfo. */ public String getPathTranslated() { // server/106w String pathInfo = getPathInfo(); if (pathInfo == null) return null; else return getRealPath(pathInfo); } public boolean isTop() { return false; } // // session management // public abstract boolean isSessionIdFromCookie(); public abstract String getSessionId(); public abstract void setSessionId(String sessionId); /** * Returns the memory session. */ public HttpSession getMemorySession() { if (_session != null && _session.isValid()) return _session; else return null; } /** * Returns the current session, creating one if necessary. * Sessions are a convenience for keeping user state * across requests. */ public HttpSession getSession() { return getSession(true); } /** * Returns the current session. * * @param create true if a new session should be created * * @return the current session */ @Override public HttpSession getSession(boolean create) { if (_session != null) { if (_session.isValid()) return _session; } else if (! create && _sessionIsLoaded) return null; _sessionIsLoaded = true; _session = createSession(create); return _session; } /** * Returns the current session. * * @return the current session */ public HttpSession getLoadedSession() { if (_session != null && _session.isValid()) return _session; else return null; } /** * Returns true if the HTTP request's session id refers to a valid * session. */ public boolean isRequestedSessionIdValid() { String id = getRequestedSessionId(); if (id == null) return false; SessionImpl session = _session; if (session == null) session = (SessionImpl) getSession(false); return session != null && session.isValid() && session.getId().equals(id); } /** * Returns the current session. * * XXX: duplicated in RequestAdapter * * @param create true if a new session should be created * * @return the current session */ private SessionImpl createSession(boolean create) { SessionManager manager = getSessionManager(); if (manager == null) return null; String id = getSessionId(); long now = Alarm.getCurrentTime(); SessionImpl session = manager.createSession(create, this, id, now, isSessionIdFromCookie()); if (session != null && (id == null || ! session.getId().equals(id)) && manager.enableSessionCookies()) { setSessionId(session.getId()); } // server/0123 vs TCK /* if (session != null) session.setAccessTime(now); */ return session; } /** * Returns the session manager. */ protected final SessionManager getSessionManager() { WebApp webApp = getWebApp(); if (webApp != null) return webApp.getSessionManager(); else return null; } /** * Returns the session cookie. */ protected final String getSessionCookie(SessionManager manager) { if (isSecure()) return manager.getSSLCookieName(); else return manager.getCookieName(); } public int getSessionGroup() { return _sessionGroup; } void saveSession() { SessionImpl session = _session; if (session != null) session.save(); } // // security // protected String getRunAs() { return null; } protected ServletInvocation getInvocation() { return null; } /** * Returns the next request in a chain. */ protected HttpServletRequest getRequest() { return null; } /** * @since Servlet 3.0 */ @Override public void login(String username, String password) throws ServletException { WebApp webApp = getWebApp(); Authenticator auth = webApp.getConfiguredAuthenticator(); if (auth == null) throw new ServletException(L.l("No authentication mechanism is configured for '{0}'", getWebApp())); // server/1aj0 Login login = webApp.getLogin(); if (login == null) throw new ServletException(L.l("No login mechanism is configured for '{0}'", getWebApp())); if (! login.isPasswordBased()) throw new ServletException(L.l("Authentication mechanism '{0}' does not support password authentication", login)); removeAttribute(Login.LOGIN_USER_NAME); removeAttribute(Login.LOGIN_USER_PRINCIPAL); removeAttribute(Login.LOGIN_PASSWORD); Principal principal = login.getUserPrincipal(this); if (principal != null) throw new ServletException(L.l("UserPrincipal object has already been established")); setAttribute(Login.LOGIN_USER_NAME, username); setAttribute(Login.LOGIN_PASSWORD, password); try { login.login(this, getResponse(), false); } finally { removeAttribute(Login.LOGIN_USER_NAME); removeAttribute(Login.LOGIN_PASSWORD); } principal = login.getUserPrincipal(this); if (principal == null) throw new ServletException("can't authenticate a user"); } @Override public boolean login(boolean isFail) { try { WebApp webApp = getWebApp(); if (webApp == null) { if (log.isLoggable(Level.FINE)) log.finer("authentication failed, no web-app found"); getResponse().sendError(HttpServletResponse.SC_FORBIDDEN); return false; } if (webApp.isSecure() && ! isSecure()) { if (log.isLoggable(Level.FINE)) log.finer("authentication failed, requires secure"); getResponse().sendError(HttpServletResponse.SC_FORBIDDEN); return false; } // If the authenticator can find the user, return it. Login login = webApp.getLogin(); if (login != null) { Principal user = login.login(this, getResponse(), isFail); if (user != null) { setAttribute(Login.LOGIN_USER_PRINCIPAL, user); return true; } else return false; } else if (isFail) { if (log.isLoggable(Level.FINE)) log.finer("authentication failed, no login module found for " + webApp); getResponse().sendError(HttpServletResponse.SC_FORBIDDEN); return false; } else { // if a non-failure, then missing login is fine return false; } } catch (IOException e) { log.log(Level.FINE, e.toString(), e); return false; } } /** * Returns true if any authentication is requested */ abstract public boolean isLoginRequested(); abstract public void requestLogin(); /** * @since Servlet 3.0 */ @Override public boolean authenticate(HttpServletResponse response) throws IOException, ServletException { WebApp webApp = getWebApp(); if (webApp == null) throw new ServletException(L.l("No authentication mechanism is configured for '{0}'", getWebApp())); // server/1aj{0,1} Authenticator auth = webApp.getConfiguredAuthenticator(); if (auth == null) throw new ServletException(L.l("No authentication mechanism is configured for '{0}'", getWebApp())); Login login = webApp.getLogin(); if (login == null) throw new ServletException(L.l("No authentication mechanism is configured for '{0}'", getWebApp())); Principal principal = login.login(this, response, true); if (principal != null) { setAttribute(Login.LOGIN_USER_PRINCIPAL, principal); return true; } return false; } /** * Returns the Principal representing the logged in user. */ public Principal getUserPrincipal() { requestLogin(); Principal user; user = (Principal) getAttribute(AbstractLogin.LOGIN_USER_NAME); if (user != null) return user; WebApp webApp = getWebApp(); if (webApp == null) return null; // If the authenticator can find the user, return it. Login login = webApp.getLogin(); if (login != null) { user = login.getUserPrincipal(this); if (user != null) { getResponse().setPrivateCache(true); } else { // server/123h, server/1920 // distinguishes between setPrivateCache and setPrivateOrResinCache // _response.setPrivateOrResinCache(true); } } return user; } /** * Returns true if the user represented by the current request * plays the named role. * * @param role the named role to test. * @return true if the user plays the role. */ @Override public boolean isUserInRole(String role) { ServletInvocation invocation = getInvocation(); if (invocation == null) { if (getRequest() != null) return getRequest().isUserInRole(role); else return false; } HashMap<String,String> roleMap = invocation.getSecurityRoleMap(); if (roleMap != null) { String linkRole = roleMap.get(role); if (linkRole != null) role = linkRole; } String runAs = getRunAs(); if (runAs != null) return runAs.equals(role); WebApp webApp = getWebApp(); Principal user = getUserPrincipal(); if (user == null) { if (log.isLoggable(Level.FINE)) log.fine(this + " isUserInRole request has no getUserPrincipal value"); return false; } RoleMapManager roleManager = webApp != null ? webApp.getRoleMapManager() : null; if (roleManager != null) { Boolean result = roleManager.isUserInRole(role, user); if (result != null) { if (log.isLoggable(Level.FINE)) log.fine(this + " userInRole(" + role + ")->" + result); return result; } } Login login = webApp == null ? null : webApp.getLogin(); boolean inRole = login != null && login.isUserInRole(user, role); if (log.isLoggable(Level.FINE)) { if (login == null) log.fine(this + " no Login for isUserInRole"); else if (user == null) log.fine(this + " no user for isUserInRole"); else if (inRole) log.fine(this + " " + user + " is in role: " + role); else log.fine(this + " failed " + user + " in role: " + role); } return inRole; } @Override public SocketLink getSocketLink() { AbstractHttpRequest request = getAbstractHttpRequest(); if (request != null) return request.getConnection(); else return null; } // // lifecycle // protected void finishRequest() throws IOException { SessionImpl session = _session; if (session == null && getSessionId() != null) { WebApp webApp = getWebApp(); if (webApp != null && webApp.isActive()) { session = (SessionImpl) getSession(false); } } if (session != null) session.finishRequest(); } @Override public String toString() { return getClass().getSimpleName() + "[" + getRequestURL() + "]"; } }