|
@@ -1,1239 +0,0 @@
|
|
-package org.springframework.security.config.http;
|
|
|
|
-
|
|
|
|
-import static org.hamcrest.Matchers.*;
|
|
|
|
-import static org.junit.Assert.*;
|
|
|
|
-import static org.springframework.security.config.ConfigTestUtils.AUTH_PROVIDER_XML;
|
|
|
|
-import static org.springframework.security.config.http.AuthenticationConfigBuilder.*;
|
|
|
|
-
|
|
|
|
-import java.lang.reflect.Method;
|
|
|
|
-import java.util.ArrayList;
|
|
|
|
-import java.util.Collection;
|
|
|
|
-import java.util.HashSet;
|
|
|
|
-import java.util.Iterator;
|
|
|
|
-import java.util.List;
|
|
|
|
-import java.util.Map;
|
|
|
|
-import java.util.Set;
|
|
|
|
-import java.util.regex.Pattern;
|
|
|
|
-
|
|
|
|
-import javax.servlet.Filter;
|
|
|
|
-import javax.servlet.http.HttpServletRequest;
|
|
|
|
-
|
|
|
|
-import org.junit.After;
|
|
|
|
-import org.junit.Test;
|
|
|
|
-import org.springframework.beans.factory.BeanCreationException;
|
|
|
|
-import org.springframework.beans.factory.parsing.BeanDefinitionParsingException;
|
|
|
|
-import org.springframework.context.support.AbstractXmlApplicationContext;
|
|
|
|
-import org.springframework.mock.web.MockFilterChain;
|
|
|
|
-import org.springframework.mock.web.MockHttpServletRequest;
|
|
|
|
-import org.springframework.mock.web.MockHttpServletResponse;
|
|
|
|
-import org.springframework.security.access.AccessDeniedException;
|
|
|
|
-import org.springframework.security.access.ConfigAttribute;
|
|
|
|
-import org.springframework.security.access.SecurityConfig;
|
|
|
|
-import org.springframework.security.authentication.ProviderManager;
|
|
|
|
-import org.springframework.security.authentication.RememberMeAuthenticationProvider;
|
|
|
|
-import org.springframework.security.authentication.TestingAuthenticationToken;
|
|
|
|
-import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
|
|
|
-import org.springframework.security.config.BeanIds;
|
|
|
|
-import org.springframework.security.config.PostProcessedMockUserDetailsService;
|
|
|
|
-import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
|
|
|
-import org.springframework.security.core.context.SecurityContext;
|
|
|
|
-import org.springframework.security.core.context.SecurityContextHolder;
|
|
|
|
-import org.springframework.security.core.session.SessionRegistryImpl;
|
|
|
|
-import org.springframework.security.openid.OpenID4JavaConsumer;
|
|
|
|
-import org.springframework.security.openid.OpenIDAttribute;
|
|
|
|
-import org.springframework.security.openid.OpenIDAuthenticationFilter;
|
|
|
|
-import org.springframework.security.openid.OpenIDAuthenticationProvider;
|
|
|
|
-import org.springframework.security.openid.OpenIDAuthenticationToken;
|
|
|
|
-import org.springframework.security.openid.OpenIDConsumer;
|
|
|
|
-import org.springframework.security.openid.OpenIDConsumerException;
|
|
|
|
-import org.springframework.security.openid.RegexBasedAxFetchListFactory;
|
|
|
|
-import org.springframework.security.util.FieldUtils;
|
|
|
|
-import org.springframework.security.web.FilterChainProxy;
|
|
|
|
-import org.springframework.security.web.FilterInvocation;
|
|
|
|
-import org.springframework.security.web.PortMapperImpl;
|
|
|
|
-import org.springframework.security.web.access.AccessDeniedHandlerImpl;
|
|
|
|
-import org.springframework.security.web.access.ExceptionTranslationFilter;
|
|
|
|
-import org.springframework.security.web.access.channel.ChannelProcessingFilter;
|
|
|
|
-import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
|
|
|
|
-import org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource;
|
|
|
|
-import org.springframework.security.web.access.intercept.FilterInvocationSecurityMetadataSource;
|
|
|
|
-import org.springframework.security.web.access.intercept.FilterSecurityInterceptor;
|
|
|
|
-import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
|
|
|
|
-import org.springframework.security.web.authentication.AuthenticationFailureHandler;
|
|
|
|
-import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
|
|
|
|
-import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint;
|
|
|
|
-import org.springframework.security.web.authentication.RememberMeServices;
|
|
|
|
-import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
|
|
|
|
-import org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler;
|
|
|
|
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
|
|
|
|
-import org.springframework.security.web.authentication.logout.LogoutFilter;
|
|
|
|
-import org.springframework.security.web.authentication.logout.LogoutHandler;
|
|
|
|
-import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
|
|
|
|
-import org.springframework.security.web.authentication.preauth.x509.SubjectDnX509PrincipalExtractor;
|
|
|
|
-import org.springframework.security.web.authentication.preauth.x509.X509AuthenticationFilter;
|
|
|
|
-import org.springframework.security.web.authentication.rememberme.AbstractRememberMeServices;
|
|
|
|
-import org.springframework.security.web.authentication.rememberme.InMemoryTokenRepositoryImpl;
|
|
|
|
-import org.springframework.security.web.authentication.rememberme.PersistentTokenBasedRememberMeServices;
|
|
|
|
-import org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter;
|
|
|
|
-import org.springframework.security.web.authentication.rememberme.TokenBasedRememberMeServices;
|
|
|
|
-import org.springframework.security.web.authentication.ui.DefaultLoginPageGeneratingFilter;
|
|
|
|
-import org.springframework.security.web.authentication.www.BasicAuthenticationFilter;
|
|
|
|
-import org.springframework.security.web.context.HttpSessionSecurityContextRepository;
|
|
|
|
-import org.springframework.security.web.context.NullSecurityContextRepository;
|
|
|
|
-import org.springframework.security.web.context.SaveContextOnUpdateOrErrorResponseWrapper;
|
|
|
|
-import org.springframework.security.web.context.SecurityContextPersistenceFilter;
|
|
|
|
-import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
|
|
|
|
-import org.springframework.security.web.savedrequest.RequestCacheAwareFilter;
|
|
|
|
-import org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter;
|
|
|
|
-import org.springframework.security.web.session.ConcurrentSessionFilter;
|
|
|
|
-import org.springframework.security.web.session.SessionManagementFilter;
|
|
|
|
-import org.springframework.util.ReflectionUtils;
|
|
|
|
-
|
|
|
|
-/**
|
|
|
|
- * @author Luke Taylor
|
|
|
|
- */
|
|
|
|
-public class HttpSecurityBeanDefinitionParserTests {
|
|
|
|
- private static final int AUTO_CONFIG_FILTERS = 11;
|
|
|
|
- private AbstractXmlApplicationContext appContext;
|
|
|
|
-
|
|
|
|
- @After
|
|
|
|
- public void closeAppContext() {
|
|
|
|
- if (appContext != null) {
|
|
|
|
- appContext.close();
|
|
|
|
- appContext = null;
|
|
|
|
- }
|
|
|
|
- SecurityContextHolder.clearContext();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void minimalConfigurationParses() {
|
|
|
|
- setContext("<http><http-basic /></http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void beanClassNamesAreCorrect() throws Exception {
|
|
|
|
- assertEquals(DefaultWebSecurityExpressionHandler.class.getName(), HttpSecurityBeanDefinitionParser.EXPRESSION_HANDLER_CLASS);
|
|
|
|
- assertEquals(ExpressionBasedFilterInvocationSecurityMetadataSource.class.getName(), HttpSecurityBeanDefinitionParser.EXPRESSION_FIMDS_CLASS);
|
|
|
|
- assertEquals(UsernamePasswordAuthenticationFilter.class.getName(), AUTHENTICATION_PROCESSING_FILTER_CLASS);
|
|
|
|
- assertEquals(OpenIDAuthenticationFilter.class.getName(), OPEN_ID_AUTHENTICATION_PROCESSING_FILTER_CLASS);
|
|
|
|
- assertEquals(OpenIDAuthenticationProvider.class.getName(), OPEN_ID_AUTHENTICATION_PROVIDER_CLASS);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void httpAutoConfigSetsUpCorrectFilterList() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' />" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- List<Filter> filterList = getFilters("/anyurl");
|
|
|
|
-
|
|
|
|
- checkAutoConfigFilters(filterList);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void checkAutoConfigFilters(List<Filter> filterList) throws Exception {
|
|
|
|
- Iterator<Filter> filters = filterList.iterator();
|
|
|
|
-
|
|
|
|
- assertTrue(filters.next() instanceof SecurityContextPersistenceFilter);
|
|
|
|
- assertTrue(filters.next() instanceof LogoutFilter);
|
|
|
|
- Object authProcFilter = filters.next();
|
|
|
|
- assertTrue(authProcFilter instanceof UsernamePasswordAuthenticationFilter);
|
|
|
|
- assertTrue(filters.next() instanceof DefaultLoginPageGeneratingFilter);
|
|
|
|
- assertTrue(filters.next() instanceof BasicAuthenticationFilter);
|
|
|
|
- assertTrue(filters.next() instanceof RequestCacheAwareFilter);
|
|
|
|
- assertTrue(filters.next() instanceof SecurityContextHolderAwareRequestFilter);
|
|
|
|
- assertTrue(filters.next() instanceof AnonymousAuthenticationFilter);
|
|
|
|
- assertTrue(filters.next() instanceof SessionManagementFilter);
|
|
|
|
- assertTrue(filters.next() instanceof ExceptionTranslationFilter);
|
|
|
|
- Object fsiObj = filters.next();
|
|
|
|
- assertTrue(fsiObj instanceof FilterSecurityInterceptor);
|
|
|
|
- FilterSecurityInterceptor fsi = (FilterSecurityInterceptor) fsiObj;
|
|
|
|
- assertTrue(fsi.isObserveOncePerRequest());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void filterListShouldBeEmptyForPatternWithNoFilters() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http pattern='/unprotected' secured='false' />" +
|
|
|
|
- " <http auto-config='true'/> " + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- List<Filter> filters = getFilters("/unprotected");
|
|
|
|
-
|
|
|
|
- assertTrue(filters.size() == 0);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void filtersEqualsNoneSupportsPlaceholderForPattern() throws Exception {
|
|
|
|
- System.setProperty("pattern.nofilters", "/unprotected");
|
|
|
|
- setContext(
|
|
|
|
- " <b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- " <http pattern='${pattern.nofilters}' secured='false' />" +
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_A' />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- List<Filter> filters = getFilters("/unprotected");
|
|
|
|
-
|
|
|
|
- assertTrue(filters.size() == 0);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void regexPathsWorkCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http pattern='\\A\\/[a-z]+' secured='false' request-matcher='regex'/>" +
|
|
|
|
- " <http auto-config='true' />"
|
|
|
|
- + AUTH_PROVIDER_XML);
|
|
|
|
- assertEquals(0, getFilters("/imlowercase").size());
|
|
|
|
- List<Filter> allFilters = getFilters("/ImCaughtByTheAnyRequestMatcher");
|
|
|
|
- checkAutoConfigFilters(allFilters);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void ciRegexPathsWorkCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http pattern='\\A\\/[a-z]+' secured='false' request-matcher='ciRegex' />" +
|
|
|
|
- " <http auto-config='true' />"
|
|
|
|
- + AUTH_PROVIDER_XML);
|
|
|
|
- assertEquals(0, getFilters("/imMixedCase").size());
|
|
|
|
- // This will be matched by the default pattern ".*"
|
|
|
|
- List<Filter> allFilters = getFilters("/Im_Caught_By_The_AnyRequestMatcher");
|
|
|
|
- assertTrue(allFilters.size() > 0);
|
|
|
|
- checkAutoConfigFilters(allFilters);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void formLoginWithNoLoginPageAddsDefaultLoginPageFilter() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true' request-matcher='ant'>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- // These will be matched by the default pattern "/**"
|
|
|
|
- checkAutoConfigFilters(getFilters("/anything"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void formLoginAlwaysUseDefaultSetsCorrectProperty() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login default-target-url='/default' always-use-default-target='true' />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- // These will be matched by the default pattern "/**"
|
|
|
|
- UsernamePasswordAuthenticationFilter filter = getFilter(UsernamePasswordAuthenticationFilter.class);
|
|
|
|
- assertEquals("/default", FieldUtils.getFieldValue(filter, "successHandler.defaultTargetUrl"));
|
|
|
|
- assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "successHandler.alwaysUseDefaultTargetUrl"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // SEC-1152
|
|
|
|
- @Test
|
|
|
|
- public void anonymousFilterIsAddedByDefault() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- assertThat(getFilters("/anything").get(5), instanceOf(AnonymousAuthenticationFilter.class));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void anonymousFilterIsRemovedIfDisabledFlagSet() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- " <anonymous enabled='false'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- assertThat(getFilters("/anything").get(5), not(instanceOf(AnonymousAuthenticationFilter.class)));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void anonymousCustomAttributesAreSetCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- " <anonymous enabled='true' username='joe' granted-authority='anonymity' key='customKey' />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- AnonymousAuthenticationFilter filter = getFilter(AnonymousAuthenticationFilter.class);
|
|
|
|
- assertEquals("customKey", filter.getKey());
|
|
|
|
- assertEquals("joe", filter.getUserAttribute().getPassword());
|
|
|
|
- assertEquals("anonymity", filter.getUserAttribute().getAuthorities().get(0).getAuthority());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanCreationException.class)
|
|
|
|
- public void invalidLoginPageIsDetected() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login login-page='noLeadingSlash'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanCreationException.class)
|
|
|
|
- public void invalidDefaultTargetUrlIsDetected() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login default-target-url='noLeadingSlash'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanCreationException.class)
|
|
|
|
- public void invalidLogoutUrlIsDetected() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <logout logout-url='noLeadingSlash'/>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanCreationException.class)
|
|
|
|
- public void invalidLogoutSuccessUrlIsDetected() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <logout logout-success-url='noLeadingSlash'/>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void logoutSuccessHandlerIsSetCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <logout success-handler-ref='logoutHandler' />" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='logoutHandler' class='org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler' />"
|
|
|
|
- + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- LogoutFilter filter = (LogoutFilter) getFilter(LogoutFilter.class);
|
|
|
|
- LogoutSuccessHandler handler = (LogoutSuccessHandler) FieldUtils.getFieldValue(filter, "logoutSuccessHandler");
|
|
|
|
- assertSame(appContext.getBean("logoutHandler"), handler);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // SEC-1201
|
|
|
|
- @Test
|
|
|
|
- public void interceptUrlsAndFormLoginSupportPropertyPlaceholders() throws Exception {
|
|
|
|
- System.setProperty("secure.Url", "/Secure");
|
|
|
|
- System.setProperty("secure.role", "ROLE_A");
|
|
|
|
- System.setProperty("login.page", "/loginPage");
|
|
|
|
- System.setProperty("default.target", "/defaultTarget");
|
|
|
|
- System.setProperty("auth.failure", "/authFailure");
|
|
|
|
- setContext(
|
|
|
|
- "<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- "<http pattern='${login.page}' secured='false' />" +
|
|
|
|
- "<http>" +
|
|
|
|
- " <intercept-url pattern='${secure.Url}' access='${secure.role}' />" +
|
|
|
|
- " <form-login login-page='${login.page}' default-target-url='${default.target}' " +
|
|
|
|
- " authentication-failure-url='${auth.failure}' />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- checkPropertyValues();
|
|
|
|
- assertEquals(0, getFilters("/loginPage").size());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- // SEC-1309
|
|
|
|
- @Test
|
|
|
|
- public void interceptUrlsAndFormLoginSupportEL() throws Exception {
|
|
|
|
- System.setProperty("secure.url", "/Secure");
|
|
|
|
- System.setProperty("secure.role", "ROLE_A");
|
|
|
|
- System.setProperty("login.page", "/loginPage");
|
|
|
|
- System.setProperty("default.target", "/defaultTarget");
|
|
|
|
- System.setProperty("auth.failure", "/authFailure");
|
|
|
|
- setContext(
|
|
|
|
- "<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- "<http>" +
|
|
|
|
- " <intercept-url pattern=\"#{systemProperties['secure.url']}\" access=\"#{systemProperties['secure.role']}\" />" +
|
|
|
|
- " <form-login login-page=\"#{systemProperties['login.page']}\" default-target-url=\"#{systemProperties['default.target']}\" " +
|
|
|
|
- " authentication-failure-url=\"#{systemProperties['auth.failure']}\" />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- checkPropertyValues() ;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void checkPropertyValues() throws Exception {
|
|
|
|
- // Check the security attribute
|
|
|
|
- FilterSecurityInterceptor fis = getFilter(FilterSecurityInterceptor.class);
|
|
|
|
- FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
|
|
|
- Collection<ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/secure", null));
|
|
|
|
- assertNotNull(attrs);
|
|
|
|
- assertEquals(1, attrs.size());
|
|
|
|
- assertTrue(attrs.contains(new SecurityConfig("ROLE_A")));
|
|
|
|
-
|
|
|
|
- // Check the form login properties are set
|
|
|
|
- UsernamePasswordAuthenticationFilter apf = getFilter(UsernamePasswordAuthenticationFilter.class);
|
|
|
|
- assertEquals("/defaultTarget", FieldUtils.getFieldValue(apf, "successHandler.defaultTargetUrl"));
|
|
|
|
- assertEquals("/authFailure", FieldUtils.getFieldValue(apf, "failureHandler.defaultFailureUrl"));
|
|
|
|
-
|
|
|
|
- ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- assertEquals("/loginPage", FieldUtils.getFieldValue(etf, "authenticationEntryPoint.loginFormUrl"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void httpMethodMatchIsSupported() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <intercept-url pattern='/secure*' method='DELETE' access='ROLE_SUPERVISOR' />" +
|
|
|
|
- " <intercept-url pattern='/secure*' method='POST' access='ROLE_A,ROLE_B' />" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_C' />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- FilterSecurityInterceptor fis = getFilter(FilterSecurityInterceptor.class);
|
|
|
|
- FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
|
|
|
- Collection<ConfigAttribute> attrs = fids.getAttributes(createFilterinvocation("/secure", "POST"));
|
|
|
|
- assertEquals(2, attrs.size());
|
|
|
|
- assertTrue(attrs.contains(new SecurityConfig("ROLE_A")));
|
|
|
|
- assertTrue(attrs.contains(new SecurityConfig("ROLE_B")));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void oncePerRequestAttributeIsSupported() throws Exception {
|
|
|
|
- setContext("<http once-per-request='false'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- FilterSecurityInterceptor fsi = getFilter(FilterSecurityInterceptor.class);
|
|
|
|
-
|
|
|
|
- assertFalse(fsi.isObserveOncePerRequest());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void httpBasicSupportsSeparateEntryPoint() throws Exception {
|
|
|
|
- setContext("<http><http-basic entry-point-ref='ep' /></http>" +
|
|
|
|
- "<b:bean id='ep' class='org.springframework.security.web.authentication.www.BasicAuthenticationEntryPoint'>" +
|
|
|
|
- " <b:property name='realmName' value='whocares'/>" +
|
|
|
|
- "</b:bean>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- BasicAuthenticationFilter baf = getFilter(BasicAuthenticationFilter.class);
|
|
|
|
- assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(baf, "authenticationEntryPoint"));
|
|
|
|
- // Since no other authentication system is in use, this should also end up on the ETF
|
|
|
|
- ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- assertSame(appContext.getBean("ep"), FieldUtils.getFieldValue(etf, "authenticationEntryPoint"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void accessDeniedPageAttributeIsSupported() throws Exception {
|
|
|
|
- setContext("<http access-denied-page='/access-denied'><http-basic /></http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
-
|
|
|
|
- assertEquals("/access-denied", FieldUtils.getFieldValue(etf, "accessDeniedHandler.errorPage"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanCreationException.class)
|
|
|
|
- public void invalidAccessDeniedUrlIsDetected() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' access-denied-page='noLeadingSlash'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void interceptUrlWithRequiresChannelAddsChannelFilterToStack() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <intercept-url pattern='/**' requires-channel='https' />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- List<Filter> filters = getFilters("/someurl");
|
|
|
|
-
|
|
|
|
- assertEquals("Expected " + (AUTO_CONFIG_FILTERS + 1) +" filters in chain", AUTO_CONFIG_FILTERS + 1, filters.size());
|
|
|
|
-
|
|
|
|
- assertTrue(filters.get(0) instanceof ChannelProcessingFilter);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void requiresChannelSupportsPlaceholder() throws Exception {
|
|
|
|
- System.setProperty("secure.url", "/secure");
|
|
|
|
- System.setProperty("required.channel", "https");
|
|
|
|
- setContext(
|
|
|
|
- " <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <intercept-url pattern='${secure.url}' requires-channel='${required.channel}' />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- List<Filter> filters = getFilters("/secure");
|
|
|
|
-
|
|
|
|
- assertTrue(filters.get(0) instanceof ChannelProcessingFilter);
|
|
|
|
- ChannelProcessingFilter filter = (ChannelProcessingFilter) filters.get(0);
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
|
- request.setServletPath("/secure");
|
|
|
|
- MockHttpServletResponse response = new MockHttpServletResponse();
|
|
|
|
- filter.doFilter(request, response, new MockFilterChain());
|
|
|
|
- assertNotNull(response.getRedirectedUrl());
|
|
|
|
- assertTrue(response.getRedirectedUrl().startsWith("https"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void portMappingsAreParsedCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <port-mappings>" +
|
|
|
|
- " <port-mapping http='9080' https='9443'/>" +
|
|
|
|
- " </port-mappings>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- PortMapperImpl pm = getPortMapper();
|
|
|
|
- assertEquals(1, pm.getTranslatedPortMappings().size());
|
|
|
|
- assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
|
|
|
|
- assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void portMappingsWorkWithPlaceholdersAndEL() throws Exception {
|
|
|
|
- System.setProperty("http", "9080");
|
|
|
|
- System.setProperty("https", "9443");
|
|
|
|
- setContext(
|
|
|
|
- " <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <port-mappings>" +
|
|
|
|
- " <port-mapping http='#{systemProperties.http}' https='${https}'/>" +
|
|
|
|
- " </port-mappings>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- PortMapperImpl pm = getPortMapper();
|
|
|
|
- assertEquals(1, pm.getTranslatedPortMappings().size());
|
|
|
|
- assertEquals(Integer.valueOf(9080), pm.lookupHttpPort(9443));
|
|
|
|
- assertEquals(Integer.valueOf(9443), pm.lookupHttpsPort(9080));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private PortMapperImpl getPortMapper() {
|
|
|
|
- Map<String,PortMapperImpl> beans = appContext.getBeansOfType(PortMapperImpl.class);
|
|
|
|
- return new ArrayList<PortMapperImpl>(beans.values()).get(0);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void accessDeniedPageWorksWithPlaceholders() throws Exception {
|
|
|
|
- System.setProperty("accessDenied", "/go-away");
|
|
|
|
- setContext(
|
|
|
|
- " <b:bean id='configurer' class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- " <http auto-config='true' access-denied-page='${accessDenied}'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter filter = (ExceptionTranslationFilter) getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void accessDeniedHandlerPageWorksWithEL() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <access-denied-handler error-page=\"#{'/go' + '-away'} \" />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter filter = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void accessDeniedHandlerIsSetCorectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <b:bean id='adh' class='" + AccessDeniedHandlerImpl.class.getName() + "'/>" +
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <access-denied-handler ref='adh'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter filter = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- AccessDeniedHandlerImpl adh = (AccessDeniedHandlerImpl) appContext.getBean("adh");
|
|
|
|
- assertSame(adh, FieldUtils.getFieldValue(filter, "accessDeniedHandler"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanDefinitionParsingException.class)
|
|
|
|
- public void accessDeniedPageAndAccessDeniedHandlerAreMutuallyExclusive() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http auto-config='true' access-denied-page='/go-away'>" +
|
|
|
|
- " <access-denied-handler error-page='/go-away'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter filter = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanDefinitionParsingException.class)
|
|
|
|
- public void accessDeniedHandlerPageAndRefAreMutuallyExclusive() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <b:bean id='adh' class='" + AccessDeniedHandlerImpl.class.getName() + "'/>" +
|
|
|
|
- " <http auto-config='true'>" +
|
|
|
|
- " <access-denied-handler error-page='/go-away' ref='adh'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter filter = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- assertEquals("/go-away", FieldUtils.getFieldValue(filter, "accessDeniedHandler.errorPage"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void externalFiltersAreTreatedCorrectly() throws Exception {
|
|
|
|
- // Decorated user-filters should be added to stack. The others should be ignored.
|
|
|
|
- String contextHolderFilterClass = SecurityContextHolderAwareRequestFilter.class.getName();
|
|
|
|
- String contextPersistenceFilterClass = SecurityContextPersistenceFilter.class.getName();
|
|
|
|
- System.setProperty("customFilterRef", "userFilter1");
|
|
|
|
-
|
|
|
|
- setContext(
|
|
|
|
- "<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <custom-filter position='FIRST' ref='${customFilterRef}' />" +
|
|
|
|
- " <custom-filter after='LOGOUT_FILTER' ref='userFilter' />" +
|
|
|
|
- " <custom-filter before='SECURITY_CONTEXT_FILTER' ref='userFilter3'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML +
|
|
|
|
- "<b:bean id='userFilter' class='"+ contextHolderFilterClass +"'/>" +
|
|
|
|
- "<b:bean id='userFilter1' class='" + contextPersistenceFilterClass + "'/>" +
|
|
|
|
- "<b:bean id='userFilter2' class='" + contextPersistenceFilterClass + "'/>" +
|
|
|
|
- "<b:bean id='userFilter3' class='" + contextPersistenceFilterClass + "'/>" +
|
|
|
|
- "<b:bean id='userFilter4' class='"+ contextHolderFilterClass +"'/>"
|
|
|
|
- );
|
|
|
|
- List<Filter> filters = getFilters("/someurl");
|
|
|
|
-
|
|
|
|
- assertEquals(AUTO_CONFIG_FILTERS + 3, filters.size());
|
|
|
|
- assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
|
|
|
- assertTrue(filters.get(1) instanceof SecurityContextPersistenceFilter);
|
|
|
|
- assertTrue(filters.get(4) instanceof SecurityContextHolderAwareRequestFilter);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanDefinitionParsingException.class)
|
|
|
|
- public void twoFiltersWithSameOrderAreRejected() {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <custom-filter position='LOGOUT_FILTER' ref='userFilter'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML +
|
|
|
|
- "<b:bean id='userFilter' class='" + SecurityContextHolderAwareRequestFilter.class.getName() + "'/>");
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void rememberMeServiceWorksWithTokenRepoRef() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me token-repository-ref='tokenRepo'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='tokenRepo' " +
|
|
|
|
- "class='" + InMemoryTokenRepositoryImpl.class.getName() + "'/> " + AUTH_PROVIDER_XML);
|
|
|
|
- RememberMeServices rememberMeServices = getRememberMeServices();
|
|
|
|
-
|
|
|
|
- assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
|
|
|
|
- assertFalse((Boolean)FieldUtils.getFieldValue(getRememberMeServices(), "useSecureCookie"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void rememberMeServiceWorksWithDataSourceRef() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me data-source-ref='ds'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='ds' class='org.springframework.security.TestDataSource'> " +
|
|
|
|
- " <b:constructor-arg value='tokendb'/>" +
|
|
|
|
- "</b:bean>" + AUTH_PROVIDER_XML);
|
|
|
|
- RememberMeServices rememberMeServices = getRememberMeServices();
|
|
|
|
-
|
|
|
|
- assertTrue(rememberMeServices instanceof PersistentTokenBasedRememberMeServices);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- public void rememberMeServiceWorksWithExternalServicesImpl() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me key=\"#{'our' + 'key'}\" services-ref='rms'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='rms' class='"+ TokenBasedRememberMeServices.class.getName() +"'> " +
|
|
|
|
- " <b:property name='userDetailsService' ref='us'/>" +
|
|
|
|
- " <b:property name='key' value='ourkey' />" +
|
|
|
|
- " <b:property name='tokenValiditySeconds' value='5000'/>" +
|
|
|
|
- "</b:bean>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- assertEquals(5000, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds"));
|
|
|
|
- // SEC-909
|
|
|
|
- List<LogoutHandler> logoutHandlers = (List<LogoutHandler>) FieldUtils.getFieldValue(getFilter(LogoutFilter.class), "handlers");
|
|
|
|
- assertEquals(2, logoutHandlers.size());
|
|
|
|
- assertEquals(getRememberMeServices(), logoutHandlers.get(1));
|
|
|
|
- // SEC-1281
|
|
|
|
- Map ams = appContext.getBeansOfType(ProviderManager.class);
|
|
|
|
- ams.remove(BeanIds.AUTHENTICATION_MANAGER);
|
|
|
|
- RememberMeAuthenticationProvider rmp = (RememberMeAuthenticationProvider) ((ProviderManager)ams.values().toArray()[0]).getProviders().get(1);
|
|
|
|
- assertEquals("ourkey", rmp.getKey());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void rememberMeTokenValidityIsParsedCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me key='ourkey' token-validity-seconds='10000' />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- assertEquals(10000, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void rememberMeTokenValidityAllowsNegativeValueForNonPersistentImplementation() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me key='ourkey' token-validity-seconds='-1' />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- assertEquals(-1, FieldUtils.getFieldValue(getRememberMeServices(), "tokenValiditySeconds"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void rememberMeSecureCookieAttributeIsSetCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me key='ourkey' use-secure-cookie='true' />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- assertTrue((Boolean)FieldUtils.getFieldValue(getRememberMeServices(), "useSecureCookie"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanDefinitionParsingException.class)
|
|
|
|
- public void rememberMeTokenValidityRejectsNegativeValueForPersistentImplementation() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me token-validity-seconds='-1' token-repository-ref='tokenRepo'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='tokenRepo' class='org.springframework.security.ui.rememberme.InMemoryTokenRepositoryImpl'/> " +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void rememberMeServiceConfigurationParsesWithCustomUserService() {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me key='somekey' user-service-ref='userService'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='userService' class='org.springframework.security.core.userdetails.MockUserDetailsService'/> " +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void x509SupportAddsFilterAtExpectedPosition() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <x509 />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- List<Filter> filters = getFilters("/someurl");
|
|
|
|
-
|
|
|
|
- assertTrue(filters.get(2) instanceof X509AuthenticationFilter);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void x509SubjectPrincipalRegexCanBeSetUsingPropertyPlaceholder() throws Exception {
|
|
|
|
- System.setProperty("subject-principal-regex", "uid=(.*),");
|
|
|
|
- setContext(
|
|
|
|
- "<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <x509 subject-principal-regex='${subject-principal-regex}'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- X509AuthenticationFilter filter = getFilter(X509AuthenticationFilter.class);
|
|
|
|
- SubjectDnX509PrincipalExtractor pe = (SubjectDnX509PrincipalExtractor) FieldUtils.getFieldValue(filter, "principalExtractor");
|
|
|
|
- Pattern p = (Pattern) FieldUtils.getFieldValue(pe, "subjectDnPattern");
|
|
|
|
- assertEquals("uid=(.*),", p.pattern());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void concurrentSessionSupportAddsFilterAndExpectedBeans() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <session-management>" +
|
|
|
|
- " <concurrency-control session-registry-alias='sr' expired-url='/expired'/>" +
|
|
|
|
- " </session-management>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- List<Filter> filters = getFilters("/someurl");
|
|
|
|
-
|
|
|
|
- assertTrue(filters.get(0) instanceof ConcurrentSessionFilter);
|
|
|
|
- assertNotNull(appContext.getBean("sr"));
|
|
|
|
- SessionManagementFilter smf = getFilter(SessionManagementFilter.class);
|
|
|
|
- assertNotNull(smf);
|
|
|
|
- checkSessionRegistry();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void externalSessionStrategyIsSupported() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <session-management session-authentication-strategy-ref='ss'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='ss' class='org.springframework.security.web.authentication.session.SessionFixationProtectionStrategy'/>"
|
|
|
|
- + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void externalSessionRegistryBeanIsConfiguredCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <session-management>" +
|
|
|
|
- " <concurrency-control session-registry-ref='sr' />" +
|
|
|
|
- " </session-management>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='sr' class='" + SessionRegistryImpl.class.getName() + "'/>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- checkSessionRegistry();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private void checkSessionRegistry() throws Exception {
|
|
|
|
- Object sessionRegistry = appContext.getBean("sr");
|
|
|
|
- Object sessionRegistryFromConcurrencyFilter = FieldUtils.getFieldValue(
|
|
|
|
- getFilter(ConcurrentSessionFilter.class), "sessionRegistry");
|
|
|
|
- Object sessionRegistryFromFormLoginFilter = FieldUtils.getFieldValue(
|
|
|
|
- getFilter(UsernamePasswordAuthenticationFilter.class),"sessionStrategy.sessionRegistry");
|
|
|
|
- Object sessionRegistryFromMgmtFilter = FieldUtils.getFieldValue(
|
|
|
|
- getFilter(SessionManagementFilter.class),"sessionStrategy.sessionRegistry");
|
|
|
|
-
|
|
|
|
- assertSame(sessionRegistry, sessionRegistryFromConcurrencyFilter);
|
|
|
|
- assertSame(sessionRegistry, sessionRegistryFromMgmtFilter);
|
|
|
|
- // SEC-1143
|
|
|
|
- assertSame(sessionRegistry, sessionRegistryFromFormLoginFilter);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void concurrentSessionMaxSessionsIsCorrectlyConfigured() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <session-management session-authentication-error-url='/max-exceeded'>" +
|
|
|
|
- " <concurrency-control max-sessions='2' error-if-maximum-exceeded='true' />" +
|
|
|
|
- " </session-management>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- SessionManagementFilter seshFilter = getFilter(SessionManagementFilter.class);
|
|
|
|
- UsernamePasswordAuthenticationToken auth = new UsernamePasswordAuthenticationToken("bob", "pass");
|
|
|
|
- SecurityContextHolder.getContext().setAuthentication(auth);
|
|
|
|
- // Register 2 sessions and then check a third
|
|
|
|
- MockHttpServletResponse mockResponse = new MockHttpServletResponse();
|
|
|
|
- SaveContextOnUpdateOrErrorResponseWrapper response = new SaveContextOnUpdateOrErrorResponseWrapper(mockResponse, false) {
|
|
|
|
- protected void saveContext(SecurityContext context) {
|
|
|
|
- }
|
|
|
|
- };
|
|
|
|
- seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
|
|
|
- assertNull(mockResponse.getRedirectedUrl());
|
|
|
|
- seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
|
|
|
- assertNull(mockResponse.getRedirectedUrl());
|
|
|
|
- seshFilter.doFilter(new MockHttpServletRequest(), response, new MockFilterChain());
|
|
|
|
- assertEquals("/max-exceeded", mockResponse.getRedirectedUrl());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void externalRequestCacheIsConfiguredCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <request-cache ref='cache' />" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='cache' class='" + HttpSessionRequestCache.class.getName() + "'/>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- Object requestCache = appContext.getBean("cache");
|
|
|
|
- assertSame(requestCache, FieldUtils.getFieldValue(getFilter(ExceptionTranslationFilter.class), "requestCache"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void customEntryPointIsSupported() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true' entry-point-ref='entryPoint'/>" +
|
|
|
|
- "<b:bean id='entryPoint' class='" + MockEntryPoint.class.getName() + "'>" +
|
|
|
|
- "</b:bean>" + AUTH_PROVIDER_XML);
|
|
|
|
- assertTrue("ExceptionTranslationFilter should be configured with custom entry point",
|
|
|
|
- getFilter(ExceptionTranslationFilter.class).getAuthenticationEntryPoint() instanceof MockEntryPoint);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @SuppressWarnings("unused")
|
|
|
|
- private static class MockEntryPoint extends LoginUrlAuthenticationEntryPoint {
|
|
|
|
- public MockEntryPoint() {
|
|
|
|
- super.setLoginFormUrl("/notused");
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- /** SEC-742 */
|
|
|
|
- public void rememberMeServicesWorksWithoutBasicProcessingFilter() {
|
|
|
|
- setContext(
|
|
|
|
- " <http>" +
|
|
|
|
- " <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
|
|
|
- " <logout logout-success-url='/login.jsp'/>" +
|
|
|
|
- " <anonymous username='guest' granted-authority='guest'/>" +
|
|
|
|
- " <remember-me />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void disablingSessionProtectionRemovesSessionManagementFilterIfNoInvalidSessionUrlSet() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <session-management session-fixation-protection='none'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- List<Filter> filters = getFilters("/someurl");
|
|
|
|
- assertFalse(filters.get(8) instanceof SessionManagementFilter);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void disablingSessionProtectionRetainsSessionManagementFilterInvalidSessionUrlSet() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <session-management session-fixation-protection='none' invalid-session-url='/timeoutUrl'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- List<Filter> filters = getFilters("/someurl");
|
|
|
|
- Object filter = filters.get(8);
|
|
|
|
- assertTrue(filter instanceof SessionManagementFilter);
|
|
|
|
- assertEquals("/timeoutUrl", FieldUtils.getProtectedFieldValue("invalidSessionUrl", filter));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * See SEC-750. If the http security post processor causes beans to be instantiated too eagerly, they way miss
|
|
|
|
- * additional processing. In this method we have a UserDetailsService which is referenced from the namespace
|
|
|
|
- * and also has a post processor registered which will modify it.
|
|
|
|
- */
|
|
|
|
- @Test
|
|
|
|
- public void httpElementDoesntInterfereWithBeanPostProcessing() {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'/>" +
|
|
|
|
- "<authentication-manager>" +
|
|
|
|
- " <authentication-provider user-service-ref='myUserService'/>" +
|
|
|
|
- "</authentication-manager>" +
|
|
|
|
- "<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
|
|
|
- "<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
|
|
|
- );
|
|
|
|
-
|
|
|
|
- PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
|
|
|
|
-
|
|
|
|
- assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- /**
|
|
|
|
- * SEC-795. Two methods that exercise the scenarios that will or won't result in a protected login page warning.
|
|
|
|
- * Check the log.
|
|
|
|
- */
|
|
|
|
- @Test
|
|
|
|
- public void unprotectedLoginPageDoesntResultInWarning() {
|
|
|
|
- // Anonymous access configured
|
|
|
|
- setContext(
|
|
|
|
- " <http>" +
|
|
|
|
- " <intercept-url pattern='/login.jsp*' access='IS_AUTHENTICATED_ANONYMOUSLY'/>" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_A'/>" +
|
|
|
|
- " <anonymous />" +
|
|
|
|
- " <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- closeAppContext();
|
|
|
|
- // No filters applied to login page
|
|
|
|
- setContext(
|
|
|
|
- " <http pattern='/login.jsp*' secured='false'/>" +
|
|
|
|
- " <http>" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_A'/>" +
|
|
|
|
- " <anonymous />" +
|
|
|
|
- " <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void protectedLoginPageResultsInWarning() {
|
|
|
|
- // Protected, no anonymous filter configured.
|
|
|
|
- setContext(
|
|
|
|
- " <http>" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_A'/>" +
|
|
|
|
- " <anonymous enabled='false' />" +
|
|
|
|
- " <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- closeAppContext();
|
|
|
|
- // Protected, anonymous provider but no access
|
|
|
|
- setContext(
|
|
|
|
- " <http>" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_A'/>" +
|
|
|
|
- " <anonymous />" +
|
|
|
|
- " <form-login login-page='/login.jsp' default-target-url='/messageList.html'/>" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void settingCreateSessionToAlwaysSetsFilterPropertiesCorrectly() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' create-session='always'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- Object filter = getFilter(SecurityContextPersistenceFilter.class);
|
|
|
|
-
|
|
|
|
- assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
|
|
|
- assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
|
|
|
|
- // Just check that the repo has url rewriting enabled by default
|
|
|
|
- assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void settingCreateSessionToNeverSetsFilterPropertiesCorrectly() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' create-session='never'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- Object filter = getFilter(SecurityContextPersistenceFilter.class);
|
|
|
|
- assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
|
|
|
- assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
|
|
|
|
- // Check that an invocation doesn't create a session
|
|
|
|
- FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
|
- request.setServletPath("/anything");
|
|
|
|
- fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
|
|
|
- assertNull(request.getSession(false));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void settingCreateSessionToStatelessSetsFilterPropertiesCorrectly() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' create-session='stateless'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- SecurityContextPersistenceFilter filter = getFilter(SecurityContextPersistenceFilter.class);
|
|
|
|
- assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
|
|
|
- assertTrue(FieldUtils.getFieldValue(filter, "repo") instanceof NullSecurityContextRepository);
|
|
|
|
- assertNull("Session management filter should not be in stack", getFilter(SessionManagementFilter.class));
|
|
|
|
- assertNull("Request cache filter should not be in stack", getFilter(RequestCacheAwareFilter.class));
|
|
|
|
-
|
|
|
|
- // Check that an invocation doesn't create a session
|
|
|
|
- FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
|
- request.setServletPath("/anything");
|
|
|
|
- fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
|
|
|
- assertNull(request.getSession(false));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void settingCreateSessionToIfRequiredDoesntCreateASessionForPublicInvocation() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' create-session='ifRequired'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- Object filter = getFilter(SecurityContextPersistenceFilter.class);
|
|
|
|
- assertEquals(Boolean.FALSE, FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
|
|
|
- assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.allowSessionCreation"));
|
|
|
|
- // Check that an invocation doesn't create a session
|
|
|
|
- FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
|
- request.setServletPath("/anything");
|
|
|
|
- fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
|
|
|
- assertNull(request.getSession(false));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- /* SEC-934 */
|
|
|
|
- @Test
|
|
|
|
- public void supportsTwoIdenticalInterceptUrls() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <intercept-url pattern='/someurl' access='ROLE_A'/>" +
|
|
|
|
- " <intercept-url pattern='/someurl' access='ROLE_B'/>" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- FilterSecurityInterceptor fis = getFilter(FilterSecurityInterceptor.class);
|
|
|
|
-
|
|
|
|
- FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
|
|
|
- Collection<ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/someurl", null));
|
|
|
|
- assertEquals(1, attrDef.size());
|
|
|
|
- assertTrue(attrDef.contains(new SecurityConfig("ROLE_B")));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void supportsExternallyDefinedSecurityContextRepository() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<b:bean id='repo' class='" + HttpSessionSecurityContextRepository.class.getName() + "'/>" +
|
|
|
|
- "<http create-session='always' security-context-repository-ref='repo'>" +
|
|
|
|
- " <http-basic />" +
|
|
|
|
- "</http>" + AUTH_PROVIDER_XML);
|
|
|
|
- SecurityContextPersistenceFilter filter = getFilter(SecurityContextPersistenceFilter.class);;
|
|
|
|
- HttpSessionSecurityContextRepository repo = (HttpSessionSecurityContextRepository) appContext.getBean("repo");
|
|
|
|
- assertSame(repo, FieldUtils.getFieldValue(filter, "repo"));
|
|
|
|
- assertTrue((Boolean)FieldUtils.getFieldValue(filter, "forceEagerSessionCreation"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void expressionBasedAccessAllowsAndDeniesAccessAsExpected() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- " <http auto-config='true' use-expressions='true'>" +
|
|
|
|
- " <intercept-url pattern='/secure*' access=\"hasAnyRole('ROLE_A','ROLE_C')\" />" +
|
|
|
|
- " <intercept-url pattern='/**' access='permitAll()' />" +
|
|
|
|
- " </http>" + AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- FilterSecurityInterceptor fis = getFilter(FilterSecurityInterceptor.class);
|
|
|
|
-
|
|
|
|
- FilterInvocationSecurityMetadataSource fids = fis.getSecurityMetadataSource();
|
|
|
|
- Collection<ConfigAttribute> attrDef = fids.getAttributes(createFilterinvocation("/secure", null));
|
|
|
|
- assertEquals(1, attrDef.size());
|
|
|
|
-
|
|
|
|
- // Try an unprotected invocation
|
|
|
|
- SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ROLE_A"));
|
|
|
|
- fis.invoke(createFilterinvocation("/permitallurl", null));
|
|
|
|
- // Try secure Url as a valid user
|
|
|
|
- fis.invoke(createFilterinvocation("/securex", null));
|
|
|
|
- // And as a user without the required role
|
|
|
|
- SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("joe", "", "ROLE_B"));
|
|
|
|
- try {
|
|
|
|
- fis.invoke(createFilterinvocation("/securex", null));
|
|
|
|
- fail("Expected AccessDeniedInvocation");
|
|
|
|
- } catch (AccessDeniedException expected) {
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void customSuccessAndFailureHandlersCanBeSetThroughTheNamespace() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login authentication-success-handler-ref='sh' authentication-failure-handler-ref='fh'/>" +
|
|
|
|
- "</http>" +
|
|
|
|
- "<b:bean id='sh' class='" + SavedRequestAwareAuthenticationSuccessHandler.class.getName() +"'/>" +
|
|
|
|
- "<b:bean id='fh' class='" + SimpleUrlAuthenticationFailureHandler.class.getName() + "'/>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- UsernamePasswordAuthenticationFilter apf = getFilter(UsernamePasswordAuthenticationFilter.class);
|
|
|
|
- AuthenticationSuccessHandler sh = (AuthenticationSuccessHandler) appContext.getBean("sh");
|
|
|
|
- AuthenticationFailureHandler fh = (AuthenticationFailureHandler) appContext.getBean("fh");
|
|
|
|
- assertSame(sh, FieldUtils.getFieldValue(apf, "successHandler"));
|
|
|
|
- assertSame(fh, FieldUtils.getFieldValue(apf, "failureHandler"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void disablingUrlRewritingThroughTheNamespaceSetsCorrectPropertyOnContextRepo() throws Exception {
|
|
|
|
- setContext("<http auto-config='true' disable-url-rewriting='true'/>" + AUTH_PROVIDER_XML);
|
|
|
|
- Object filter = getFilter(SecurityContextPersistenceFilter.class);
|
|
|
|
- assertEquals(Boolean.TRUE, FieldUtils.getFieldValue(filter, "repo.disableUrlRewriting"));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void userDetailsServiceInParentContextIsLocatedSuccessfully() throws Exception {
|
|
|
|
- appContext = new InMemoryXmlApplicationContext(AUTH_PROVIDER_XML);
|
|
|
|
-
|
|
|
|
- appContext = new InMemoryXmlApplicationContext(
|
|
|
|
- "<http auto-config='true'>" +
|
|
|
|
- " <remember-me />" +
|
|
|
|
- "</http>", appContext);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void openIDAndFormLoginWorkTogether() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <openid-login />" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- LoginUrlAuthenticationEntryPoint ap = (LoginUrlAuthenticationEntryPoint) etf.getAuthenticationEntryPoint();
|
|
|
|
- assertEquals("/spring_security_login", ap.getLoginFormUrl());
|
|
|
|
- // Default login filter should be present since we haven't specified any login URLs
|
|
|
|
- getFilter(DefaultLoginPageGeneratingFilter.class);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void openIDAndRememberMeWorkTogether() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <intercept-url pattern='/**' access='ROLE_NOBODY'/>" +
|
|
|
|
- " <openid-login />" +
|
|
|
|
- " <remember-me />" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- // Default login filter should be present since we haven't specified any login URLs
|
|
|
|
- DefaultLoginPageGeneratingFilter loginFilter = getFilter(DefaultLoginPageGeneratingFilter.class);
|
|
|
|
- OpenIDAuthenticationFilter openIDFilter = getFilter(OpenIDAuthenticationFilter.class);
|
|
|
|
- openIDFilter.setConsumer(new OpenIDConsumer() {
|
|
|
|
- public String beginConsumption(HttpServletRequest req, String claimedIdentity, String returnToUrl, String realm)
|
|
|
|
- throws OpenIDConsumerException {
|
|
|
|
- return "http://testopenid.com?openid.return_to=" + returnToUrl;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- public OpenIDAuthenticationToken endConsumption(HttpServletRequest req) throws OpenIDConsumerException {
|
|
|
|
- throw new UnsupportedOperationException();
|
|
|
|
- }
|
|
|
|
- });
|
|
|
|
- Set<String> returnToUrlParameters = new HashSet<String>();
|
|
|
|
- returnToUrlParameters.add(AbstractRememberMeServices.DEFAULT_PARAMETER);
|
|
|
|
- openIDFilter.setReturnToUrlParameters(returnToUrlParameters);
|
|
|
|
- assertNotNull(FieldUtils.getFieldValue(loginFilter, "openIDrememberMeParameter"));
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
|
- MockHttpServletResponse response = new MockHttpServletResponse();
|
|
|
|
-
|
|
|
|
- FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
|
|
|
- request.setServletPath("/something.html");
|
|
|
|
- fcp.doFilter(request, response, new MockFilterChain());
|
|
|
|
- assertTrue(response.getRedirectedUrl().endsWith("/spring_security_login"));
|
|
|
|
- request.setServletPath("/spring_security_login");
|
|
|
|
- request.setRequestURI("/spring_security_login");
|
|
|
|
- response = new MockHttpServletResponse();
|
|
|
|
- fcp.doFilter(request, response, new MockFilterChain());
|
|
|
|
- assertTrue(response.getContentAsString().contains(AbstractRememberMeServices.DEFAULT_PARAMETER));
|
|
|
|
- request.setRequestURI("/j_spring_openid_security_check");
|
|
|
|
- request.setParameter(OpenIDAuthenticationFilter.DEFAULT_CLAIMED_IDENTITY_FIELD, "http://hey.openid.com/");
|
|
|
|
- request.setParameter(AbstractRememberMeServices.DEFAULT_PARAMETER, "on");
|
|
|
|
- response = new MockHttpServletResponse();
|
|
|
|
- fcp.doFilter(request, response, new MockFilterChain());
|
|
|
|
- String expectedReturnTo = request.getRequestURL().append("?")
|
|
|
|
- .append(AbstractRememberMeServices.DEFAULT_PARAMETER)
|
|
|
|
- .append("=").append("on").toString();
|
|
|
|
- assertEquals("http://testopenid.com?openid.return_to=" + expectedReturnTo, response.getRedirectedUrl());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void formLoginEntryPointTakesPrecedenceIfLoginUrlIsSet() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <openid-login />" +
|
|
|
|
- " <form-login login-page='/form_login_page' />" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- LoginUrlAuthenticationEntryPoint ap = (LoginUrlAuthenticationEntryPoint) etf.getAuthenticationEntryPoint();
|
|
|
|
- assertEquals("/form_login_page", ap.getLoginFormUrl());
|
|
|
|
- assertNull(getFilter(DefaultLoginPageGeneratingFilter.class));
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void openIDEntryPointTakesPrecedenceIfLoginUrlIsSet() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <openid-login login-page='/openid_login' />" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- ExceptionTranslationFilter etf = getFilter(ExceptionTranslationFilter.class);
|
|
|
|
- LoginUrlAuthenticationEntryPoint ap = (LoginUrlAuthenticationEntryPoint) etf.getAuthenticationEntryPoint();
|
|
|
|
- assertEquals("/openid_login", ap.getLoginFormUrl());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void openIDWithAttributeExchangeConfigurationIsParsedCorrectly() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <openid-login>" +
|
|
|
|
- " <attribute-exchange>" +
|
|
|
|
- " <openid-attribute name='nickname' type='http://schema.openid.net/namePerson/friendly'/>" +
|
|
|
|
- " <openid-attribute name='email' type='http://schema.openid.net/contact/email' required='true' count='2'/>" +
|
|
|
|
- " </attribute-exchange>" +
|
|
|
|
- " </openid-login>" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- OpenIDAuthenticationFilter apf = getFilter(OpenIDAuthenticationFilter.class);
|
|
|
|
-
|
|
|
|
- OpenID4JavaConsumer consumer = (OpenID4JavaConsumer) FieldUtils.getFieldValue(apf, "consumer");
|
|
|
|
- RegexBasedAxFetchListFactory axFactory = (RegexBasedAxFetchListFactory) FieldUtils.getFieldValue(consumer, "attributesToFetchFactory");
|
|
|
|
- List<OpenIDAttribute> attributes = axFactory.createAttributeList("https://anyopenidprovider.com/");
|
|
|
|
- assertEquals(2, attributes.size());
|
|
|
|
- assertEquals("nickname", attributes.get(0).getName());
|
|
|
|
- assertEquals("http://schema.openid.net/namePerson/friendly", attributes.get(0).getType());
|
|
|
|
- assertFalse(attributes.get(0).isRequired());
|
|
|
|
- assertTrue(attributes.get(1).isRequired());
|
|
|
|
- assertEquals(2, attributes.get(1).getCount());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test(expected=BeanDefinitionParsingException.class)
|
|
|
|
- public void multipleLoginPagesCausesError() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <openid-login login-page='/openid_login_page' />" +
|
|
|
|
- " <form-login login-page='/form_login_page' />" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @Test
|
|
|
|
- public void httpConfigWithNoAuthProvidersWorksOk() throws Exception {
|
|
|
|
- setContext(
|
|
|
|
- "<http>" +
|
|
|
|
- " <form-login />" +
|
|
|
|
- " <anonymous enabled='false' />" +
|
|
|
|
- "</http>" +
|
|
|
|
- AUTH_PROVIDER_XML);
|
|
|
|
- FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest("POST", "/j_spring_security_check");
|
|
|
|
- request.setServletPath("/j_spring_security_check");
|
|
|
|
- request.addParameter("j_username", "bob");
|
|
|
|
- request.addParameter("j_password", "bob");
|
|
|
|
- fcp.doFilter(request, new MockHttpServletResponse(), new MockFilterChain());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-
|
|
|
|
- private void setContext(String context) {
|
|
|
|
- appContext = new InMemoryXmlApplicationContext(context);
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- @SuppressWarnings("unchecked")
|
|
|
|
- private <T extends Filter> List<T> getFilters(String url) throws Exception {
|
|
|
|
- FilterChainProxy fcp = (FilterChainProxy) appContext.getBean(BeanIds.FILTER_CHAIN_PROXY);
|
|
|
|
- Method getFilters = fcp.getClass().getDeclaredMethod("getFilters", String.class);
|
|
|
|
- getFilters.setAccessible(true);
|
|
|
|
- return (List<T>) ReflectionUtils.invokeMethod(getFilters, fcp, new Object[] {url});
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private FilterInvocation createFilterinvocation(String path, String method) {
|
|
|
|
- MockHttpServletRequest request = new MockHttpServletRequest();
|
|
|
|
- request.setMethod(method);
|
|
|
|
- request.setRequestURI(null);
|
|
|
|
- request.setServletPath(path);
|
|
|
|
-
|
|
|
|
- return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private <T extends Filter> T getFilter(Class<T> type) throws Exception {
|
|
|
|
- List<T> filters = getFilters("/any");
|
|
|
|
-
|
|
|
|
- for (T f : filters) {
|
|
|
|
- if (f.getClass().isAssignableFrom(type)) {
|
|
|
|
- return f;
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- return null;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
- private RememberMeServices getRememberMeServices() throws Exception {
|
|
|
|
- return getFilter(RememberMeAuthenticationFilter.class).getRememberMeServices();
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
-}
|
|
|