/*************************GO-LICENSE-START********************************* * Copyright 2014 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. *************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.server.security; import java.io.IOException; import java.util.regex.Pattern; import javax.servlet.FilterChain; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.thoughtworks.go.server.service.SecurityService; import org.apache.commons.lang.StringUtils; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.security.AuthenticationException; import org.springframework.security.context.SecurityContextHolder; import org.springframework.security.ui.AbstractProcessingFilter; import org.springframework.security.ui.AuthenticationEntryPoint; import org.springframework.security.ui.ExceptionTranslationFilter; import org.springframework.security.ui.savedrequest.SavedRequest; public class GoExceptionTranslationFilter extends ExceptionTranslationFilter { private String urlPatternsThatShouldNotBeRedirectedToAfterLogin; private AuthenticationEntryPoint basicAuthenticationEntryPoint; public static final String REQUEST__FORMAT = "format"; private SecurityService securityService; protected void sendStartAuthentication(ServletRequest request, ServletResponse response, FilterChain chain, AuthenticationException reason) throws ServletException, IOException { HttpServletRequest httpRequest = (HttpServletRequest) request; HttpServletResponse httpResponse = (HttpServletResponse) response; //TODO: This is a hack for bug #3175, we should revisit this code in V2.0 if (isJson(httpRequest) || isJsonFormat(httpRequest)) { httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED); return; } final Log logger = LogFactory.getLog(GoExceptionTranslationFilter.class); SavedRequest savedRequest = new SavedRequest(httpRequest, getPortResolver()); if (logger.isDebugEnabled()) { logger.debug("Authentication entry point being called; SavedRequest added to Session: " + savedRequest); } if (isCreateSessionAllowed() && shouldRedirect(savedRequest.getRequestUrl())) { // Store the HTTP request itself. Used by AbstractProcessingFilter // for redirection after successful authentication (SEC-29) httpRequest.getSession().setAttribute(AbstractProcessingFilter.SPRING_SECURITY_SAVED_REQUEST_KEY, savedRequest); } // SEC-112: Clear the SecurityContextHolder's Authentication, as the // existing Authentication is no longer considered valid SecurityContextHolder.getContext().setAuthentication(null); determineAuthenticationPoint(httpRequest).commence(httpRequest, response, reason); } private AuthenticationEntryPoint determineAuthenticationPoint(HttpServletRequest httpRequest) { AuthenticationEntryPoint point = getAuthenticationEntryPoint(); if (isJsonp(httpRequest)) { return basicAuthenticationEntryPoint; } return point; } private boolean isJsonFormat(HttpServletRequest httpRequest) { String format = httpRequest.getParameter(REQUEST__FORMAT); return format != null && format.equalsIgnoreCase("json"); } private boolean isJson(HttpServletRequest httpRequest) { return httpRequest.getRequestURI().endsWith(".json") && StringUtils.isBlank(httpRequest.getParameter("callback")); } private boolean isJsonp(HttpServletRequest httpRequest) { return httpRequest.getRequestURI().endsWith(".json") && !StringUtils.isBlank(httpRequest.getParameter("callback")); } boolean shouldRedirect(String url) { Pattern regexPattern = Pattern.compile(urlPatternsThatShouldNotBeRedirectedToAfterLogin); return !regexPattern.matcher(url).find(); } public String getUrlPatternsThatShouldNotBeRedirectedToAfterLogin() { return urlPatternsThatShouldNotBeRedirectedToAfterLogin; } public void setUrlPatternsThatShouldNotBeRedirectedToAfterLogin(String value) { urlPatternsThatShouldNotBeRedirectedToAfterLogin = value; } public void setBasicAuthenticationEntryPoint(AuthenticationEntryPoint basicAuthenticationEntryPoint) { this.basicAuthenticationEntryPoint = basicAuthenticationEntryPoint; } public void setSecurityService(SecurityService service) { this.securityService = service; } }