diff --git a/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java b/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java new file mode 100644 index 0000000000..91532de055 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/intercept/web/AuthenticationEntryPoint.java @@ -0,0 +1,56 @@ +/* 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. + * 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. + */ + +package net.sf.acegisecurity.intercept.web; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; + + +/** + * Used by {@link SecurityEnforcementFilter} to commence an authentication + * scheme. + * + * @author Ben Alex + * @version $Id$ + */ +public interface AuthenticationEntryPoint { + //~ Methods ================================================================ + + /** + * 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 to as necessary to commence the
+ * authentication process.
+ *
AuthenticationException
+ * @param response so that the user agent can begin authentication
+ */
+ public void commence(ServletRequest request, ServletResponse response)
+ 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 32f816826f..712f269b3a 100644
--- a/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java
+++ b/core/src/main/java/org/acegisecurity/intercept/web/SecurityEnforcementFilter.java
@@ -59,8 +59,7 @@ import javax.servlet.http.HttpServletResponse;
*
*
* - * To use this filter, it is necessary to specify the following filter - * initialization parameters: + * To use this filter, it is necessary to specify the following properties: *
* *loginFormUrl indicates the URL that should be used for
- * redirection if an AuthenticationException is detected.
+ * authenticationEntryPoint indicates the handler that should
+ * commence the authentication process if an
+ * AuthenticationException is detected.
* AuthenticationException is detected.
- */
- protected String loginFormUrl;
+ private AuthenticationEntryPoint authenticationEntryPoint;
+ private FilterSecurityInterceptor filterSecurityInterceptor;
//~ Methods ================================================================
+ public void setAuthenticationEntryPoint(
+ AuthenticationEntryPoint authenticationEntryPoint) {
+ this.authenticationEntryPoint = authenticationEntryPoint;
+ }
+
+ public AuthenticationEntryPoint getAuthenticationEntryPoint() {
+ return authenticationEntryPoint;
+ }
+
public void setFilterSecurityInterceptor(
FilterSecurityInterceptor filterSecurityInterceptor) {
this.filterSecurityInterceptor = filterSecurityInterceptor;
@@ -111,17 +115,10 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
return filterSecurityInterceptor;
}
- public void setLoginFormUrl(String loginFormUrl) {
- this.loginFormUrl = loginFormUrl;
- }
-
- public String getLoginFormUrl() {
- return loginFormUrl;
- }
-
public void afterPropertiesSet() throws Exception {
- if ((loginFormUrl == null) || "".equals(loginFormUrl)) {
- throw new IllegalArgumentException("loginFormUrl must be specified");
+ if (authenticationEntryPoint == null) {
+ throw new IllegalArgumentException(
+ "authenticationEntryPoint must be specified");
}
if (filterSecurityInterceptor == null) {
@@ -161,8 +158,7 @@ public class SecurityEnforcementFilter implements Filter, InitializingBean {
((HttpServletRequest) request).getSession().setAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY,
fi.getRequestUrl());
- ((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request)
- .getContextPath() + loginFormUrl);
+ authenticationEntryPoint.commence(request, response);
} catch (AccessDeniedException accessDenied) {
if (logger.isDebugEnabled()) {
logger.debug(
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 47b0c902f6..1107970f9a 100644
--- a/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java
+++ b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilter.java
@@ -18,6 +18,7 @@ package net.sf.acegisecurity.ui.basicauth;
import net.sf.acegisecurity.Authentication;
import net.sf.acegisecurity.AuthenticationException;
import net.sf.acegisecurity.AuthenticationManager;
+import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
import net.sf.acegisecurity.providers.UsernamePasswordAuthenticationToken;
import net.sf.acegisecurity.ui.webapp.HttpSessionIntegrationFilter;
@@ -63,9 +64,9 @@ import javax.servlet.http.HttpServletResponse;
*
*
* - * Requests containing BASIC authentication headers are generally created by - * remoting protocol libraries. This filter is intended to process requests - * made by such libraries. + * This filter can be used to provide BASIC authentication services to both + * remoting protocol clients (such as Hessian and SOAP) as well as standard + * user agents (such as Internet Explorer and Netscape). *
* *@@ -75,10 +76,9 @@ import javax.servlet.http.HttpServletResponse; *
* *
- * If authentication fails, a HttpServletResponse.SC_FORBIDDEN
- * (403 error) response is sent. This is consistent with RFC 1945, Section 11,
- * which states, "If the server does not wish to accept the credentials
- * sent with a request, it should return a 403 (forbidden) response.".
+ * If authentication fails, an {@link AuthenticationEntryPoint} implementation
+ * is called. Usually this should be {@link BasicProcessingFilterEntryPoint},
+ * which will prompt the user to authenticate again via BASIC authentication.
*
@@ -97,10 +97,20 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
//~ Instance fields ========================================================
+ private AuthenticationEntryPoint authenticationEntryPoint;
private AuthenticationManager authenticationManager;
//~ Methods ================================================================
+ public void setAuthenticationEntryPoint(
+ AuthenticationEntryPoint authenticationEntryPoint) {
+ this.authenticationEntryPoint = authenticationEntryPoint;
+ }
+
+ public AuthenticationEntryPoint getAuthenticationEntryPoint() {
+ return authenticationEntryPoint;
+ }
+
public void setAuthenticationManager(
AuthenticationManager authenticationManager) {
this.authenticationManager = authenticationManager;
@@ -115,6 +125,11 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
throw new IllegalArgumentException(
"An AuthenticationManager is required");
}
+
+ if (this.authenticationEntryPoint == null) {
+ throw new IllegalArgumentException(
+ "An AuthenticationEntryPoint is required");
+ }
}
public void destroy() {}
@@ -166,7 +181,7 @@ public class BasicProcessingFilter implements Filter, InitializingBean {
+ " failed: " + failed.toString());
}
- ((HttpServletResponse) response).sendError(HttpServletResponse.SC_FORBIDDEN); // 403
+ authenticationEntryPoint.commence(request, response);
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
new file mode 100644
index 0000000000..00bda24770
--- /dev/null
+++ b/core/src/main/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPoint.java
@@ -0,0 +1,75 @@
+/* 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.
+ * 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.
+ */
+
+package net.sf.acegisecurity.ui.basicauth;
+
+import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
+
+import org.springframework.beans.factory.InitializingBean;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Used by the SecurityEnforcementFilter to commence
+ * authentication via the {@link BasicProcessingFilter}.
+ *
+ *
+ * Once a user agent is authenticated using BASIC authentication, logout + * requires that the browser be closed or an unauthorized (401) header be + * sent. The simplest way of achieving the latter is to call the {@link + * #commence(ServletRequest, ServletResponse)} method below. This will + * indicate to the browser its credentials are no longer authorized, causing + * it to prompt the user to login again. + *
+ * + * @author Ben Alex + * @version $Id$ + */ +public class BasicProcessingFilterEntryPoint implements AuthenticationEntryPoint, + InitializingBean { + //~ Instance fields ======================================================== + + private String realmName; + + //~ Methods ================================================================ + + public void setRealmName(String realmName) { + this.realmName = realmName; + } + + public String getRealmName() { + return realmName; + } + + public void afterPropertiesSet() throws Exception { + if ((realmName == null) || "".equals(realmName)) { + throw new IllegalArgumentException("realmName must be specified"); + } + } + + public void commence(ServletRequest request, ServletResponse response) + throws IOException, ServletException { + HttpServletResponse httpResponse = (HttpServletResponse) response; + httpResponse.addHeader("WWW-Authenticate", + "Basic realm=\"" + realmName + "\""); + httpResponse.sendError(401); + } +} diff --git a/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java new file mode 100644 index 0000000000..c42a3cdd43 --- /dev/null +++ b/core/src/main/java/org/acegisecurity/ui/webapp/AuthenticationProcessingFilterEntryPoint.java @@ -0,0 +1,69 @@ +/* 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. + * 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. + */ + +package net.sf.acegisecurity.ui.webapp; + +import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint; + +import org.springframework.beans.factory.InitializingBean; + +import java.io.IOException; + +import javax.servlet.ServletException; +import javax.servlet.ServletRequest; +import javax.servlet.ServletResponse; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/** + * Used by theSecurityEnforcementFilter to commence
+ * authentication via the {@link AuthenticationProcessingFilter}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class AuthenticationProcessingFilterEntryPoint
+ implements AuthenticationEntryPoint, InitializingBean {
+ //~ Instance fields ========================================================
+
+ /**
+ * The URL where the AuthenticationProcessingFilter login page
+ * can be found.
+ */
+ private String loginFormUrl;
+
+ //~ Methods ================================================================
+
+ public void setLoginFormUrl(String loginFormUrl) {
+ this.loginFormUrl = loginFormUrl;
+ }
+
+ public String getLoginFormUrl() {
+ return loginFormUrl;
+ }
+
+ public void afterPropertiesSet() throws Exception {
+ if ((loginFormUrl == null) || "".equals(loginFormUrl)) {
+ throw new IllegalArgumentException("loginFormUrl must be specified");
+ }
+ }
+
+ public void commence(ServletRequest request, ServletResponse response)
+ throws IOException, ServletException {
+ ((HttpServletResponse) response).sendRedirect(((HttpServletRequest) request)
+ .getContextPath() + loginFormUrl);
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java b/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java
new file mode 100644
index 0000000000..8a286d0653
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/MockAuthenticationEntryPoint.java
@@ -0,0 +1,57 @@
+/* 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.
+ * 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.
+ */
+
+package net.sf.acegisecurity;
+
+import net.sf.acegisecurity.intercept.web.AuthenticationEntryPoint;
+
+import java.io.IOException;
+
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+
+/**
+ * Performs a HTTP redirect to the constructor-indicated URL.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class MockAuthenticationEntryPoint implements AuthenticationEntryPoint {
+ //~ Instance fields ========================================================
+
+ private String url;
+
+ //~ Constructors ===========================================================
+
+ public MockAuthenticationEntryPoint(String url) {
+ this.url = url;
+ }
+
+ private MockAuthenticationEntryPoint() {
+ super();
+ }
+
+ //~ Methods ================================================================
+
+ public void commence(ServletRequest request, ServletResponse response)
+ 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 ad6010fc51..61c0db7f82 100644
--- a/core/src/test/java/org/acegisecurity/MockHttpServletResponse.java
+++ b/core/src/test/java/org/acegisecurity/MockHttpServletResponse.java
@@ -18,7 +18,9 @@ package net.sf.acegisecurity;
import java.io.IOException;
import java.io.PrintWriter;
+import java.util.HashMap;
import java.util.Locale;
+import java.util.Map;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
@@ -35,6 +37,7 @@ import javax.servlet.http.HttpServletResponse;
public class MockHttpServletResponse implements HttpServletResponse {
//~ Instance fields ========================================================
+ private Map headersMap = new HashMap();
private String redirect;
private int error;
@@ -76,6 +79,16 @@ public class MockHttpServletResponse implements HttpServletResponse {
throw new UnsupportedOperationException("mock method not implemented");
}
+ public String getHeader(String arg0) {
+ Object result = headersMap.get(arg0);
+
+ if (result != null) {
+ return (String) headersMap.get(arg0);
+ } else {
+ return null;
+ }
+ }
+
public void setIntHeader(String arg0, int arg1) {
throw new UnsupportedOperationException("mock method not implemented");
}
@@ -117,7 +130,7 @@ public class MockHttpServletResponse implements HttpServletResponse {
}
public void addHeader(String arg0, String arg1) {
- throw new UnsupportedOperationException("mock method not implemented");
+ headersMap.put(arg0, arg1);
}
public void addIntHeader(String arg0, int arg1) {
diff --git a/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java b/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
index 8427ac4d26..51eed372f4 100644
--- a/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
+++ b/core/src/test/java/org/acegisecurity/intercept/web/SecurityEnforcementFilterTests.java
@@ -19,6 +19,7 @@ import junit.framework.TestCase;
import net.sf.acegisecurity.AccessDeniedException;
import net.sf.acegisecurity.BadCredentialsException;
+import net.sf.acegisecurity.MockAuthenticationEntryPoint;
import net.sf.acegisecurity.MockHttpServletRequest;
import net.sf.acegisecurity.MockHttpServletResponse;
import net.sf.acegisecurity.MockHttpSession;
@@ -76,7 +77,8 @@ public class SecurityEnforcementFilterTests extends TestCase {
// Test
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
filter.setFilterSecurityInterceptor(interceptor);
- filter.setLoginFormUrl("/login.jsp");
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
MockHttpServletResponse response = new MockHttpServletResponse();
filter.doFilter(request, response, chain);
@@ -115,8 +117,9 @@ public class SecurityEnforcementFilterTests extends TestCase {
false, false));
assertTrue(filter.getFilterSecurityInterceptor() != null);
- filter.setLoginFormUrl("/u");
- assertEquals("/u", filter.getLoginFormUrl());
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
+ assertTrue(filter.getAuthenticationEntryPoint() != null);
}
public void testRedirectedToLoginFormAndSessionShowsOriginalTargetWhenAuthenticationException()
@@ -136,7 +139,8 @@ public class SecurityEnforcementFilterTests extends TestCase {
// Test
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
filter.setFilterSecurityInterceptor(interceptor);
- filter.setLoginFormUrl("/login.jsp");
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
filter.afterPropertiesSet();
MockHttpServletResponse response = new MockHttpServletResponse();
@@ -146,21 +150,7 @@ public class SecurityEnforcementFilterTests extends TestCase {
request.getSession().getAttribute(AuthenticationProcessingFilter.ACEGI_SECURITY_TARGET_URL_KEY));
}
- public void testStartupDetectsMissingFilterSecurityInterceptor()
- throws Exception {
- SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
- filter.setLoginFormUrl("/login.jsp");
-
- try {
- filter.afterPropertiesSet();
- fail("Should have thrown IllegalArgumentException");
- } catch (IllegalArgumentException expected) {
- assertEquals("filterSecurityInterceptor must be specified",
- expected.getMessage());
- }
- }
-
- public void testStartupDetectsMissingLoginFormUrl()
+ public void testStartupDetectsMissingAuthenticationEntryPoint()
throws Exception {
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
filter.setFilterSecurityInterceptor(new MockFilterSecurityInterceptor(
@@ -170,7 +160,23 @@ public class SecurityEnforcementFilterTests extends TestCase {
filter.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
- assertEquals("loginFormUrl must be specified", expected.getMessage());
+ assertEquals("authenticationEntryPoint must be specified",
+ expected.getMessage());
+ }
+ }
+
+ public void testStartupDetectsMissingFilterSecurityInterceptor()
+ throws Exception {
+ SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
+
+ try {
+ filter.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("filterSecurityInterceptor must be specified",
+ expected.getMessage());
}
}
@@ -190,7 +196,8 @@ public class SecurityEnforcementFilterTests extends TestCase {
// Test
SecurityEnforcementFilter filter = new SecurityEnforcementFilter();
filter.setFilterSecurityInterceptor(interceptor);
- filter.setLoginFormUrl("/login.jsp");
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "/login.jsp"));
MockHttpServletResponse response = new MockHttpServletResponse();
filter.doFilter(request, response, chain);
diff --git a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java
new file mode 100644
index 0000000000..3eb9913f93
--- /dev/null
+++ b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterEntryPointTests.java
@@ -0,0 +1,82 @@
+/* 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.
+ * 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.
+ */
+
+package net.sf.acegisecurity.ui.basicauth;
+
+import junit.framework.TestCase;
+
+import net.sf.acegisecurity.MockHttpServletRequest;
+import net.sf.acegisecurity.MockHttpServletResponse;
+
+
+/**
+ * Tests {@link BasicProcessingFilterEntryPoint}.
+ *
+ * @author Ben Alex
+ * @version $Id$
+ */
+public class BasicProcessingFilterEntryPointTests extends TestCase {
+ //~ Constructors ===========================================================
+
+ public BasicProcessingFilterEntryPointTests() {
+ super();
+ }
+
+ public BasicProcessingFilterEntryPointTests(String arg0) {
+ super(arg0);
+ }
+
+ //~ Methods ================================================================
+
+ public final void setUp() throws Exception {
+ super.setUp();
+ }
+
+ public static void main(String[] args) {
+ junit.textui.TestRunner.run(BasicProcessingFilterEntryPointTests.class);
+ }
+
+ public void testDetectsMissingRealmName() throws Exception {
+ BasicProcessingFilterEntryPoint ep = new BasicProcessingFilterEntryPoint();
+
+ try {
+ ep.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("realmName must be specified", expected.getMessage());
+ }
+ }
+
+ public void testGettersSetters() {
+ BasicProcessingFilterEntryPoint ep = new BasicProcessingFilterEntryPoint();
+ ep.setRealmName("realm");
+ assertEquals("realm", ep.getRealmName());
+ }
+
+ public void testNormalOperation() throws Exception {
+ BasicProcessingFilterEntryPoint ep = new BasicProcessingFilterEntryPoint();
+ ep.setRealmName("hello");
+
+ MockHttpServletRequest request = new MockHttpServletRequest(
+ "/some_path");
+ MockHttpServletResponse response = new MockHttpServletResponse();
+
+ ep.afterPropertiesSet();
+ ep.commence(request, response);
+ assertEquals(401, response.getError());
+ assertEquals("Basic realm=\"hello\"",
+ response.getHeader("WWW-Authenticate"));
+ }
+}
diff --git a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java
index d61238e2c4..a1fa7dede5 100644
--- a/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java
+++ b/core/src/test/java/org/acegisecurity/ui/basicauth/BasicProcessingFilterTests.java
@@ -18,6 +18,7 @@ package net.sf.acegisecurity.ui.basicauth;
import junit.framework.TestCase;
import net.sf.acegisecurity.Authentication;
+import net.sf.acegisecurity.MockAuthenticationEntryPoint;
import net.sf.acegisecurity.MockAuthenticationManager;
import net.sf.acegisecurity.MockFilterConfig;
import net.sf.acegisecurity.MockHttpServletRequest;
@@ -130,6 +131,10 @@ public class BasicProcessingFilterTests extends TestCase {
BasicProcessingFilter filter = new BasicProcessingFilter();
filter.setAuthenticationManager(new MockAuthenticationManager());
assertTrue(filter.getAuthenticationManager() != null);
+
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "sx"));
+ assertTrue(filter.getAuthenticationEntryPoint() != null);
}
public void testInvalidBasicAuthorizationTokenIsIgnored()
@@ -228,10 +233,25 @@ public class BasicProcessingFilterTests extends TestCase {
assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null);
}
+ public void testStartupDetectsMissingAuthenticationEntryPoint()
+ throws Exception {
+ try {
+ BasicProcessingFilter filter = new BasicProcessingFilter();
+ filter.setAuthenticationManager(new MockAuthenticationManager());
+ filter.afterPropertiesSet();
+ fail("Should have thrown IllegalArgumentException");
+ } catch (IllegalArgumentException expected) {
+ assertEquals("An AuthenticationEntryPoint is required",
+ expected.getMessage());
+ }
+ }
+
public void testStartupDetectsMissingAuthenticationManager()
throws Exception {
try {
BasicProcessingFilter filter = new BasicProcessingFilter();
+ filter.setAuthenticationEntryPoint(new MockAuthenticationEntryPoint(
+ "x"));
filter.afterPropertiesSet();
fail("Should have thrown IllegalArgumentException");
} catch (IllegalArgumentException expected) {
@@ -293,7 +313,7 @@ public class BasicProcessingFilterTests extends TestCase {
chain);
assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null);
- assertEquals(403, response.getError());
+ assertEquals(401, response.getError());
}
public void testWrongPasswordReturnsForbidden() throws Exception {
@@ -325,7 +345,7 @@ public class BasicProcessingFilterTests extends TestCase {
chain);
assertTrue(request.getSession().getAttribute(HttpSessionIntegrationFilter.ACEGI_SECURITY_AUTHENTICATION_KEY) == null);
- assertEquals(403, response.getError());
+ assertEquals(401, response.getError());
}
private void executeFilterInContainerSimulator(FilterConfig filterConfig,
diff --git a/core/src/test/java/org/acegisecurity/ui/basicauth/filtertest-valid.xml b/core/src/test/java/org/acegisecurity/ui/basicauth/filtertest-valid.xml
index cc13218cfc..08c20c8af0 100644
--- a/core/src/test/java/org/acegisecurity/ui/basicauth/filtertest-valid.xml
+++ b/core/src/test/java/org/acegisecurity/ui/basicauth/filtertest-valid.xml
@@ -49,6 +49,11 @@