diff --git a/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java b/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java index 1f114faaec..b9f59d0638 100644 --- a/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java +++ b/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java @@ -15,6 +15,8 @@ package net.sf.acegisecurity.intercept.web; +import net.sf.acegisecurity.AuthenticationException; + import java.io.IOException; import javax.servlet.ServletException; @@ -34,14 +36,14 @@ public interface AuthenticationEntryPoint { /** * Commences an authentication scheme. - * + * *

* SecurityEnforcementFilter will populate the * HttpSession attribute named * AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY * with the requested target URL before calling this method. *

- * + * *

* Implementations should modify the headers on the * ServletResponse as necessary to commence the @@ -50,7 +52,9 @@ public interface AuthenticationEntryPoint { * * @param request that resulted in an AuthenticationException * @param response so that the user agent can begin authentication + * @param authException that caused the invocation */ - public void commence(ServletRequest request, ServletResponse response) + public void commence(ServletRequest request, ServletResponse response, + AuthenticationException authException) throws IOException, ServletException; } diff --git a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java index 4bcf31b837..de19a2b6d6 100644 --- a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java +++ b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java @@ -199,7 +199,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean { ((HttpServletRequest) request).getSession().setAttribute(AbstractProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY, targetUrl); - authenticationEntryPoint.commence(request, response); + authenticationEntryPoint.commence(request, response, authentication); } catch (AccessDeniedException accessDenied) { if (logger.isDebugEnabled()) { logger.debug( @@ -208,7 +208,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean { ((HttpServletRequest) request).getSession().setAttribute(ACEGI_SECURITY_ACCESS_DENIED_EXCEPTION_KEY, accessDenied); - sendAccessDeniedError(request, response); + sendAccessDeniedError(request, response, accessDenied); } catch (Throwable otherException) { throw new ServletException(otherException); } @@ -221,11 +221,14 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean { * * @param request * @param response + * @param accessDenied * * @throws IOException */ protected void sendAccessDeniedError(ServletRequest request, - ServletResponse response) throws IOException { - ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN); // 403 + ServletResponse response, AccessDeniedException accessDenied) + throws IOException { + ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN, + accessDenied.getMessage()); // 403 } } diff --git a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java index bfc754a26b..d9ff62e1bb 100644 --- a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java +++ b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java @@ -145,7 +145,6 @@ public class BasicProcessingFilter implements Filter, InitializingBean { } HttpServletRequest httpRequest = (HttpServletRequest) request; - HttpServletResponse httpResponse = (HttpServletResponse) response; String header = httpRequest.getHeader("Authorization"); @@ -182,7 +181,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean { + " failed: " + failed.toString()); } - authenticationEntryPoint.commence(request, response); + authenticationEntryPoint.commence(request, response, failed); return; } diff --git a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPoint.java b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPoint.java index f4fd0b8196..285d45efb7 100644 --- a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPoint.java +++ b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPoint.java @@ -1,4 +1,4 @@ -/* Copyright 2004, 2005 Acegi Technology Pty Limited +/* Copyright 2004 Acegi Technology Pty Limited * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,6 +15,7 @@ package net.sf.acegisecurity.ui.basicauth; +import net.sf.acegisecurity.AuthenticationException; import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint; import org.springframework.beans.factory.InitializingBean; @@ -65,11 +66,13 @@ public class BasicProcessingFilterEntryPoint implements AuthenticationEntryPoint } } - public void commence(ServletRequest request, ServletResponse response) + public void commence(ServletRequest request, ServletResponse response, + AuthenticationException authException) throws IOException, ServletException { HttpServletResponse httpResponse = (HttpServletResponse) response; httpResponse.addHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\""); - httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED); // 401 + httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, + authException.getMessage()); } } diff --git a/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPoint.java b/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPoint.java index 04956b4760..59fd6ff4a7 100644 --- a/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPoint.java +++ b/core/src/main/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPoint.java @@ -15,6 +15,7 @@ package net.sf.acegisecurity.ui.cas; +import net.sf.acegisecurity.AuthenticationException; import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint; import org.springframework.beans.factory.InitializingBean; @@ -88,7 +89,8 @@ public class CasProcessingFilterEntryPoint implements AuthenticationEntryPoint, } } - public void commence(ServletRequest request, ServletResponse response) + public void commence(ServletRequest request, ServletResponse response, + AuthenticationException authenticationException) throws IOException, ServletException { String url; diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java index b5d8d9ee09..437060f567 100644 --- a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java +++ b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java @@ -15,6 +15,7 @@ package net.sf.acegisecurity.ui.webapp; +import net.sf.acegisecurity.AuthenticationException; import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint; import net.sf.acegisecurity.util.PortMapper; import net.sf.acegisecurity.util.PortMapperImpl; @@ -133,7 +134,8 @@ public class AuthenticationProcessingFilterEntryPoint } } - public void commence(ServletRequest request, ServletResponse response) + public void commence(ServletRequest request, ServletResponse response, + AuthenticationException authException) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) request; String scheme = request.getScheme(); diff --git a/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java b/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java index 8a286d0653..70023ee65d 100644 --- a/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java +++ b/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java @@ -49,7 +49,8 @@ public class MockAuthenticationEntryPoint implements AuthenticationEntryPoint { //~ Methods ================================================================ - public void commence(ServletRequest request, ServletResponse response) + public void commence(ServletRequest request, ServletResponse response, + AuthenticationException authenticationException) throws IOException, ServletException { ((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request) .getContextPath() + url); diff --git a/core/src/test/java/org/acegisecurity/MockHttpServletResponse.java b/core/src/test/java/org/acegisecurity/MockHttpServletResponse.java index 890c91e448..5393c85fe5 100644 --- a/core/src/test/java/org/acegisecurity/MockHttpServletResponse.java +++ b/core/src/test/java/org/acegisecurity/MockHttpServletResponse.java @@ -38,6 +38,7 @@ public class MockHttpServletResponse implements HttpServletResponse { //~ Instance fields ======================================================== private Map headersMap = new HashMap(); + private String errorMessage; private String redirect; private int error; @@ -79,6 +80,10 @@ public class MockHttpServletResponse implements HttpServletResponse { return this.error; } + public String getErrorMessage() { + return this.errorMessage; + } + public void setHeader(String arg0, String arg1) { throw new UnsupportedOperationException("mock method not implemented"); } @@ -174,7 +179,8 @@ public class MockHttpServletResponse implements HttpServletResponse { } public void sendError(int arg0, String arg1) throws IOException { - throw new UnsupportedOperationException("mock method not implemented"); + this.error = arg0; + this.errorMessage = arg1; } public void sendError(int arg0) throws IOException { diff --git a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java index 3eb9913f93..3eba0a83cb 100644 --- a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java +++ b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java @@ -17,6 +17,7 @@ package net.sf.acegisecurity.ui.basicauth; import junit.framework.TestCase; +import net.sf.acegisecurity.DisabledException; import net.sf.acegisecurity.MockHttpServletRequest; import net.sf.acegisecurity.MockHttpServletResponse; @@ -74,8 +75,13 @@ public class BasicProcessingFilterEntryPointTests extends TestCase { MockHttpServletResponse response = new MockHttpServletResponse(); ep.afterPropertiesSet(); - ep.commence(request, response); + + String msg = "These are the jokes kid"; + ep.commence(request, response, new DisabledException(msg)); + assertEquals(401, response.getError()); + assertEquals(msg, response.getErrorMessage()); + assertEquals("Basic realm=\"hello\"", response.getHeader("WWW-Authenticate")); } diff --git a/core/src/test/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPointTests.java b/core/src/test/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPointTests.java index 1cc674e0bc..ac83ac0959 100644 --- a/core/src/test/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPointTests.java +++ b/core/src/test/java/org/acegisecurity/ui/cas/CasProcessingFilterEntryPointTests.java @@ -100,7 +100,7 @@ public class CasProcessingFilterEntryPointTests extends TestCase { MockHttpServletResponse response = new MockHttpServletResponse(); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://cas/login?service=" + URLEncoder.encode( @@ -124,7 +124,7 @@ public class CasProcessingFilterEntryPointTests extends TestCase { MockHttpServletResponse response = new MockHttpServletResponse(); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://cas/login?renew=true&service=https://mycompany.com/bigWebApp/j_acegi_cas_security_check", response.getRedirect()); } diff --git a/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java b/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java index 5b11b8f579..0b0812bb18 100644 --- a/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java +++ b/core/src/test/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPointTests.java @@ -117,19 +117,19 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase { ep.setPortResolver(new MockPortResolver(80, 443)); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://www.example.com/bigWebApp/hello", response.getRedirect()); request.setServerPort(8080); ep.setPortResolver(new MockPortResolver(8080, 8443)); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://www.example.com:8443/bigWebApp/hello", response.getRedirect()); // Now test an unusual custom HTTP:HTTPS is handled properly request.setServerPort(8888); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://www.example.com:8443/bigWebApp/hello", response.getRedirect()); @@ -146,7 +146,7 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase { ep.setPortResolver(new MockPortResolver(8888, 9999)); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://www.example.com:9999/bigWebApp/hello", response.getRedirect()); } @@ -170,13 +170,13 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase { ep.setPortResolver(new MockPortResolver(80, 443)); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://www.example.com/bigWebApp/hello", response.getRedirect()); request.setServerPort(8443); ep.setPortResolver(new MockPortResolver(8080, 8443)); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("https://www.example.com:8443/bigWebApp/hello", response.getRedirect()); } @@ -199,7 +199,7 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase { MockHttpServletResponse response = new MockHttpServletResponse(); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); assertEquals("http://www.example.com/bigWebApp/hello", response.getRedirect()); } @@ -224,7 +224,7 @@ public class AuthenticationProcessingFilterEntryPointTests extends TestCase { MockHttpServletResponse response = new MockHttpServletResponse(); ep.afterPropertiesSet(); - ep.commence(request, response); + ep.commence(request, response, null); // Response doesn't switch to HTTPS, as we didn't know HTTP port 8888 to HTTP port mapping assertEquals("http://www.example.com:8888/bigWebApp/hello", diff --git a/doc/xdocs/changes.xml b/doc/xdocs/changes.xml index a26aa1cbd4..f13dd34002 100644 --- a/doc/xdocs/changes.xml +++ b/doc/xdocs/changes.xml @@ -36,8 +36,9 @@ FilterSecurityInterceptor now only executes once per request (improves performance with SiteMesh) Contacts sample web.xml no longer expect Log4j to be in classpath JaasAuthenticatinProvider now uses System.property "java.security.auth.login.config" - JaasAuthenticationCallbackHandler Authentication is passed to handle method setAuthenticatoin removed - Use static HttpServletResponse.SC_UNAUTHORIZED instead of 401 HTTP response code + JaasAuthenticationCallbackHandler Authentication is passed to handle method setAuthentication removed + Added AuthenticationException to the AutenticationEntryPoint.commence method signature + Added AccessDeniedException to the SecurityEncorcementFilter.sendAccessDeniedError method signature Major CVS repository restructure to support Maven and eliminate libraries diff --git a/doc/xdocs/upgrade/upgrade-070-100.html b/doc/xdocs/upgrade/upgrade-070-100.html index e02a2baddc..4274289125 100644 --- a/doc/xdocs/upgrade/upgrade-070-100.html +++ b/doc/xdocs/upgrade/upgrade-070-100.html @@ -9,12 +9,14 @@ The following should help most casual users of the project update their applications: -