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