001/* 002 * (C) Copyright 2006-2008 Nuxeo SAS (http://nuxeo.com/) and contributors. 003 * 004 * All rights reserved. This program and the accompanying materials 005 * are made available under the terms of the GNU Lesser General Public License 006 * (LGPL) version 2.1 which accompanies this distribution, and is available at 007 * http://www.gnu.org/licenses/lgpl.html 008 * 009 * This library is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * Contributors: 015 * ldoguin 016 */ 017package org.nuxeo.ecm.platform.web.common.exceptionhandling; 018 019import java.io.IOException; 020import java.security.Principal; 021import java.util.HashMap; 022import java.util.Map; 023 024import javax.faces.context.FacesContext; 025import javax.servlet.ServletException; 026import javax.servlet.http.HttpServletRequest; 027import javax.servlet.http.HttpServletResponse; 028 029import org.apache.commons.logging.Log; 030import org.apache.commons.logging.LogFactory; 031import org.nuxeo.common.utils.URIUtils; 032import org.nuxeo.ecm.core.api.NuxeoPrincipal; 033import org.nuxeo.ecm.platform.ui.web.auth.NuxeoAuthenticationFilter; 034import org.nuxeo.ecm.platform.ui.web.auth.service.PluggableAuthenticationService; 035import org.nuxeo.runtime.api.Framework; 036 037import static org.nuxeo.ecm.platform.ui.web.auth.NXAuthConstants.*; 038 039/** 040 * This exception handler adds security error flag in the URL parameters to ensure the anonymous user will get 041 * appropriate error message when being redirected to login page. 042 * <p> 043 * If it isn't a security exception, or if the user is not anonymous, this handler ends up using 044 * DefaultNuxeoExceptionHandler. 045 * 046 * @author ldoguin 047 */ 048public class NuxeoSecurityExceptionHandler extends DefaultNuxeoExceptionHandler { 049 050 private static final Log log = LogFactory.getLog(NuxeoSecurityExceptionHandler.class); 051 052 protected PluggableAuthenticationService service; 053 054 @Override 055 public void handleException(HttpServletRequest request, HttpServletResponse response, Throwable t) 056 throws IOException, ServletException { 057 058 Throwable unwrappedException = unwrapException(t); 059 if (!ExceptionHelper.isSecurityError(unwrappedException)) { 060 super.handleException(request, response, t); 061 return; 062 } 063 064 Principal principal = request.getUserPrincipal(); 065 if (principal instanceof NuxeoPrincipal) { 066 NuxeoPrincipal nuxeoPrincipal = (NuxeoPrincipal) principal; 067 if (nuxeoPrincipal.isAnonymous()) { 068 // redirect to login than to requested page 069 if (handleAnonymousException(request, response)) { 070 return; 071 } 072 } 073 } 074 // go back to default handler 075 super.handleException(request, response, t); 076 } 077 078 /** 079 * Handles the Security Error when the user is anonymous. 080 * 081 * @return {@code true} if the Security Error is handled so that the calling method won't fallback on the default 082 * handler, {@code false} otherwise. 083 */ 084 protected boolean handleAnonymousException(HttpServletRequest request, HttpServletResponse response) 085 throws IOException, ServletException { 086 getAuthenticationService().invalidateSession(request); 087 Map<String, String> urlParameters = new HashMap<String, String>(); 088 urlParameters.put(SECURITY_ERROR, "true"); 089 urlParameters.put(FORCE_ANONYMOUS_LOGIN, "true"); 090 if (request.getAttribute(REQUESTED_URL) != null) { 091 urlParameters.put(REQUESTED_URL, (String) request.getAttribute(REQUESTED_URL)); 092 } else { 093 urlParameters.put(REQUESTED_URL, NuxeoAuthenticationFilter.getRequestedUrl(request)); 094 } 095 // Redirect to login with urlParameters 096 if (!response.isCommitted()) { 097 String baseURL = getAuthenticationService().getBaseURL(request) + LOGOUT_PAGE; 098 request.setAttribute(DISABLE_REDIRECT_REQUEST_KEY, true); 099 baseURL = URIUtils.addParametersToURIQuery(baseURL, urlParameters); 100 response.sendRedirect(baseURL); 101 FacesContext fContext = FacesContext.getCurrentInstance(); 102 if (fContext != null) { 103 fContext.responseComplete(); 104 } else { 105 log.error("Cannot set response complete: faces context is null"); 106 } 107 } else { 108 log.error("Cannot redirect to login page: response is already committed"); 109 } 110 return true; 111 } 112 113 protected PluggableAuthenticationService getAuthenticationService() throws ServletException { 114 if (service != null) { 115 return service; 116 } 117 service = (PluggableAuthenticationService) Framework.getRuntime().getComponent( 118 PluggableAuthenticationService.NAME); 119 if (service == null) { 120 throw new ServletException("Can't initialize Nuxeo Pluggable Authentication Service: " 121 + PluggableAuthenticationService.NAME); 122 } 123 return service; 124 } 125 126}