SEC-2915: Updated Java Code Formatting
This commit is contained in:
@@ -9,20 +9,22 @@ import java.util.*;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class BeanNameCollectingPostProcessor implements BeanPostProcessor {
|
||||
Set<String> beforeInitPostProcessedBeans = new HashSet<String>();
|
||||
Set<String> afterInitPostProcessedBeans = new HashSet<String>();
|
||||
Set<String> beforeInitPostProcessedBeans = new HashSet<String>();
|
||||
Set<String> afterInitPostProcessedBeans = new HashSet<String>();
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (beanName != null) {
|
||||
beforeInitPostProcessedBeans.add(beanName);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (beanName != null) {
|
||||
beforeInitPostProcessedBeans.add(beanName);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (beanName != null) {
|
||||
afterInitPostProcessedBeans.add(beanName);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (beanName != null) {
|
||||
afterInitPostProcessedBeans.add(beanName);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,39 +15,39 @@ import org.springframework.security.authentication.event.AbstractAuthenticationF
|
||||
* @since 3.1
|
||||
*/
|
||||
public class CollectingAppListener implements ApplicationListener {
|
||||
Set<ApplicationEvent> events = new HashSet<ApplicationEvent>();
|
||||
Set<AbstractAuthenticationEvent> authenticationEvents = new HashSet<AbstractAuthenticationEvent>();
|
||||
Set<AbstractAuthenticationFailureEvent> authenticationFailureEvents = new HashSet<AbstractAuthenticationFailureEvent>();
|
||||
Set<AbstractAuthorizationEvent> authorizationEvents = new HashSet<AbstractAuthorizationEvent>();
|
||||
Set<ApplicationEvent> events = new HashSet<ApplicationEvent>();
|
||||
Set<AbstractAuthenticationEvent> authenticationEvents = new HashSet<AbstractAuthenticationEvent>();
|
||||
Set<AbstractAuthenticationFailureEvent> authenticationFailureEvents = new HashSet<AbstractAuthenticationFailureEvent>();
|
||||
Set<AbstractAuthorizationEvent> authorizationEvents = new HashSet<AbstractAuthorizationEvent>();
|
||||
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event instanceof AbstractAuthenticationEvent) {
|
||||
events.add(event);
|
||||
authenticationEvents.add((AbstractAuthenticationEvent) event);
|
||||
}
|
||||
if (event instanceof AbstractAuthenticationFailureEvent) {
|
||||
events.add(event);
|
||||
authenticationFailureEvents.add((AbstractAuthenticationFailureEvent) event);
|
||||
}
|
||||
if (event instanceof AbstractAuthorizationEvent) {
|
||||
events.add(event);
|
||||
authorizationEvents.add((AbstractAuthorizationEvent) event);
|
||||
}
|
||||
}
|
||||
public void onApplicationEvent(ApplicationEvent event) {
|
||||
if (event instanceof AbstractAuthenticationEvent) {
|
||||
events.add(event);
|
||||
authenticationEvents.add((AbstractAuthenticationEvent) event);
|
||||
}
|
||||
if (event instanceof AbstractAuthenticationFailureEvent) {
|
||||
events.add(event);
|
||||
authenticationFailureEvents.add((AbstractAuthenticationFailureEvent) event);
|
||||
}
|
||||
if (event instanceof AbstractAuthorizationEvent) {
|
||||
events.add(event);
|
||||
authorizationEvents.add((AbstractAuthorizationEvent) event);
|
||||
}
|
||||
}
|
||||
|
||||
public Set<ApplicationEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
public Set<ApplicationEvent> getEvents() {
|
||||
return events;
|
||||
}
|
||||
|
||||
public Set<AbstractAuthenticationEvent> getAuthenticationEvents() {
|
||||
return authenticationEvents;
|
||||
}
|
||||
public Set<AbstractAuthenticationEvent> getAuthenticationEvents() {
|
||||
return authenticationEvents;
|
||||
}
|
||||
|
||||
public Set<AbstractAuthenticationFailureEvent> getAuthenticationFailureEvents() {
|
||||
return authenticationFailureEvents;
|
||||
}
|
||||
public Set<AbstractAuthenticationFailureEvent> getAuthenticationFailureEvents() {
|
||||
return authenticationFailureEvents;
|
||||
}
|
||||
|
||||
public Set<AbstractAuthorizationEvent> getAuthorizationEvents() {
|
||||
return authorizationEvents;
|
||||
}
|
||||
public Set<AbstractAuthorizationEvent> getAuthorizationEvents() {
|
||||
return authorizationEvents;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
package org.springframework.security.config;
|
||||
|
||||
public abstract class ConfigTestUtils {
|
||||
public static final String AUTH_PROVIDER_XML =
|
||||
"<authentication-manager alias='authManager'>" +
|
||||
" <authentication-provider>" +
|
||||
" <user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
" <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />" +
|
||||
" <user name='admin' password='password' authorities='ROLE_ADMIN,ROLE_USER' />" +
|
||||
" <user name='user' password='password' authorities='ROLE_USER' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>" +
|
||||
"</authentication-manager>";
|
||||
public static final String AUTH_PROVIDER_XML = "<authentication-manager alias='authManager'>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <user-service id='us'>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />"
|
||||
+ " <user name='bill' password='billspassword' authorities='ROLE_A,ROLE_B,AUTH_OTHER' />"
|
||||
+ " <user name='admin' password='password' authorities='ROLE_ADMIN,ROLE_USER' />"
|
||||
+ " <user name='user' password='password' authorities='ROLE_USER' />"
|
||||
+ " </user-service>"
|
||||
+ " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
}
|
||||
|
||||
@@ -20,53 +20,49 @@ import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.jdbc.core.JdbcTemplate;
|
||||
import org.springframework.util.Assert;
|
||||
|
||||
|
||||
/**
|
||||
* Populates a database with test data for JDBC testing.
|
||||
*
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class DataSourcePopulator implements InitializingBean {
|
||||
//~ Instance fields ================================================================================================
|
||||
// ~ Instance fields
|
||||
// ================================================================================================
|
||||
|
||||
JdbcTemplate template;
|
||||
JdbcTemplate template;
|
||||
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(template, "dataSource required");
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
Assert.notNull(template, "dataSource required");
|
||||
|
||||
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL);");
|
||||
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
|
||||
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
|
||||
template.execute("CREATE TABLE USERS(USERNAME VARCHAR_IGNORECASE(50) NOT NULL PRIMARY KEY,PASSWORD VARCHAR_IGNORECASE(500) NOT NULL,ENABLED BOOLEAN NOT NULL);");
|
||||
template.execute("CREATE TABLE AUTHORITIES(USERNAME VARCHAR_IGNORECASE(50) NOT NULL,AUTHORITY VARCHAR_IGNORECASE(50) NOT NULL,CONSTRAINT FK_AUTHORITIES_USERS FOREIGN KEY(USERNAME) REFERENCES USERS(USERNAME));");
|
||||
template.execute("CREATE UNIQUE INDEX IX_AUTH_USERNAME ON AUTHORITIES(USERNAME,AUTHORITY);");
|
||||
|
||||
/*
|
||||
Passwords encoded using MD5, NOT in Base64 format, with null as salt
|
||||
Encoded password for rod is "koala"
|
||||
Encoded password for dianne is "emu"
|
||||
Encoded password for scott is "wombat"
|
||||
Encoded password for peter is "opal" (but user is disabled)
|
||||
Encoded password for bill is "wombat"
|
||||
Encoded password for bob is "wombat"
|
||||
Encoded password for jane is "wombat"
|
||||
/*
|
||||
* Passwords encoded using MD5, NOT in Base64 format, with null as salt Encoded
|
||||
* password for rod is "koala" Encoded password for dianne is "emu" Encoded
|
||||
* password for scott is "wombat" Encoded password for peter is "opal" (but user
|
||||
* is disabled) Encoded password for bill is "wombat" Encoded password for bob is
|
||||
* "wombat" Encoded password for jane is "wombat"
|
||||
*/
|
||||
template.execute("INSERT INTO USERS VALUES('rod','koala',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('dianne','65d15fe9156f9c4bbffd98085992a44e',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('scott','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('peter','22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bill','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bob','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('jane','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_SUPERVISOR');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
|
||||
}
|
||||
|
||||
*/
|
||||
template.execute("INSERT INTO USERS VALUES('rod','koala',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('dianne','65d15fe9156f9c4bbffd98085992a44e',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('scott','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('peter','22b5c9accc6e1ba628cedc63a72d57f8',FALSE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bill','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('bob','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO USERS VALUES('jane','2b58af6dddbd072ed27ffc86725d7d3a',TRUE);");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('rod','ROLE_SUPERVISOR');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('dianne','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('scott','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('peter','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bill','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('bob','ROLE_USER');");
|
||||
template.execute("INSERT INTO AUTHORITIES VALUES('jane','ROLE_USER');");
|
||||
}
|
||||
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.template = new JdbcTemplate(dataSource);
|
||||
}
|
||||
public void setDataSource(DataSource dataSource) {
|
||||
this.template = new JdbcTemplate(dataSource);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,107 +50,119 @@ import org.springframework.security.web.util.matcher.RequestMatcher;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class FilterChainProxyConfigTests {
|
||||
private ClassPathXmlApplicationContext appCtx;
|
||||
private ClassPathXmlApplicationContext appCtx;
|
||||
|
||||
//~ Methods ========================================================================================================
|
||||
// ~ Methods
|
||||
// ========================================================================================================
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
System.setProperty("sec1235.pattern1", "/login");
|
||||
System.setProperty("sec1235.pattern2", "/logout");
|
||||
appCtx = new ClassPathXmlApplicationContext("org/springframework/security/util/filtertest-valid.xml");
|
||||
}
|
||||
@Before
|
||||
public void loadContext() {
|
||||
System.setProperty("sec1235.pattern1", "/login");
|
||||
System.setProperty("sec1235.pattern2", "/logout");
|
||||
appCtx = new ClassPathXmlApplicationContext(
|
||||
"org/springframework/security/util/filtertest-valid.xml");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeContext() {
|
||||
if (appCtx != null) {
|
||||
appCtx.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperation() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain", FilterChainProxy.class);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
@Test
|
||||
public void normalOperation() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("filterChain",
|
||||
FilterChainProxy.class);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfig() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
@Test
|
||||
public void normalOperationWithNewConfig() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxy",
|
||||
FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfigRegex() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
@Test
|
||||
public void normalOperationWithNewConfigRegex() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyRegex",
|
||||
FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
@Test
|
||||
public void normalOperationWithNewConfigNonNamespace() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean(
|
||||
"newFilterChainProxyNonNamespace", FilterChainProxy.class);
|
||||
checkPathAndFilterOrder(filterChainProxy);
|
||||
doNormalOperation(filterChainProxy);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pathWithNoMatchHasNoFilters() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean("newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
||||
}
|
||||
@Test
|
||||
public void pathWithNoMatchHasNoFilters() throws Exception {
|
||||
FilterChainProxy filterChainProxy = appCtx.getBean(
|
||||
"newFilterChainProxyNoDefaultPath", FilterChainProxy.class);
|
||||
assertEquals(null, filterChainProxy.getFilters("/nomatch"));
|
||||
}
|
||||
|
||||
// SEC-1235
|
||||
@Test
|
||||
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
|
||||
FilterChainProxy fcp = appCtx.getBean("sec1235FilterChainProxy", FilterChainProxy.class);
|
||||
// SEC-1235
|
||||
@Test
|
||||
public void mixingPatternsAndPlaceholdersDoesntCauseOrderingIssues() throws Exception {
|
||||
FilterChainProxy fcp = appCtx.getBean("sec1235FilterChainProxy",
|
||||
FilterChainProxy.class);
|
||||
|
||||
List<SecurityFilterChain> chains = fcp.getFilterChains();
|
||||
assertEquals("/login*", getPattern(chains.get(0)));
|
||||
assertEquals("/logout", getPattern(chains.get(1)));
|
||||
assertTrue(((DefaultSecurityFilterChain)chains.get(2)).getRequestMatcher() instanceof AnyRequestMatcher);
|
||||
}
|
||||
List<SecurityFilterChain> chains = fcp.getFilterChains();
|
||||
assertEquals("/login*", getPattern(chains.get(0)));
|
||||
assertEquals("/logout", getPattern(chains.get(1)));
|
||||
assertTrue(((DefaultSecurityFilterChain) chains.get(2)).getRequestMatcher() instanceof AnyRequestMatcher);
|
||||
}
|
||||
|
||||
private String getPattern(SecurityFilterChain chain) {
|
||||
return ((AntPathRequestMatcher)((DefaultSecurityFilterChain)chain).getRequestMatcher()).getPattern();
|
||||
}
|
||||
private String getPattern(SecurityFilterChain chain) {
|
||||
return ((AntPathRequestMatcher) ((DefaultSecurityFilterChain) chain)
|
||||
.getRequestMatcher()).getPattern();
|
||||
}
|
||||
|
||||
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy) throws Exception {
|
||||
List<Filter> filters = filterChainProxy.getFilters("/foo/blah;x=1");
|
||||
assertEquals(1, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
private void checkPathAndFilterOrder(FilterChainProxy filterChainProxy)
|
||||
throws Exception {
|
||||
List<Filter> filters = filterChainProxy.getFilters("/foo/blah;x=1");
|
||||
assertEquals(1, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
|
||||
filters = filterChainProxy.getFilters("/some;x=2,y=3/other/path;z=4/blah");
|
||||
assertNotNull(filters);
|
||||
assertEquals(3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
assertTrue(filters.get(2) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
filters = filterChainProxy.getFilters("/some;x=2,y=3/other/path;z=4/blah");
|
||||
assertNotNull(filters);
|
||||
assertEquals(3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.get(1) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
assertTrue(filters.get(2) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
|
||||
filters = filterChainProxy.getFilters("/do/not/filter;x=7");
|
||||
assertEquals(0, filters.size());
|
||||
filters = filterChainProxy.getFilters("/do/not/filter;x=7");
|
||||
assertEquals(0, filters.size());
|
||||
|
||||
filters = filterChainProxy.getFilters("/another/nonspecificmatch");
|
||||
assertEquals(3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.get(1) instanceof UsernamePasswordAuthenticationFilter);
|
||||
assertTrue(filters.get(2) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
}
|
||||
filters = filterChainProxy.getFilters("/another/nonspecificmatch");
|
||||
assertEquals(3, filters.size());
|
||||
assertTrue(filters.get(0) instanceof SecurityContextPersistenceFilter);
|
||||
assertTrue(filters.get(1) instanceof UsernamePasswordAuthenticationFilter);
|
||||
assertTrue(filters.get(2) instanceof SecurityContextHolderAwareRequestFilter);
|
||||
}
|
||||
|
||||
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/foo/secure/super/somefile.html");
|
||||
private void doNormalOperation(FilterChainProxy filterChainProxy) throws Exception {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setServletPath("/foo/secure/super/somefile.html");
|
||||
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
MockHttpServletResponse response = new MockHttpServletResponse();
|
||||
FilterChain chain = mock(FilterChain.class);
|
||||
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
verify(chain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
verify(chain).doFilter(any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class));
|
||||
|
||||
request.setServletPath("/a/path/which/doesnt/match/any/filter.html");
|
||||
chain = mock(FilterChain.class);
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
verify(chain).doFilter(any(HttpServletRequest.class), any(HttpServletResponse.class));
|
||||
}
|
||||
request.setServletPath("/a/path/which/doesnt/match/any/filter.html");
|
||||
chain = mock(FilterChain.class);
|
||||
filterChainProxy.doFilter(request, response, chain);
|
||||
verify(chain).doFilter(any(HttpServletRequest.class),
|
||||
any(HttpServletResponse.class));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,54 +11,56 @@ import org.springframework.security.config.authentication.AuthenticationManagerF
|
||||
import org.springframework.security.config.util.InMemoryXmlApplicationContext;
|
||||
|
||||
/**
|
||||
* Tests which make sure invalid configurations are rejected by the namespace. In particular invalid top-level
|
||||
* elements. These are likely to fail after the namespace has been updated using trang, but the spring-security.xsl
|
||||
* transform has not been applied.
|
||||
* Tests which make sure invalid configurations are rejected by the namespace. In
|
||||
* particular invalid top-level elements. These are likely to fail after the namespace has
|
||||
* been updated using trang, but the spring-security.xsl transform has not been applied.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class InvalidConfigurationTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
// Parser should throw a SAXParseException
|
||||
@Test(expected=XmlBeanDefinitionStoreException.class)
|
||||
public void passwordEncoderCannotAppearAtTopLevel() {
|
||||
setContext("<password-encoder hash='md5'/>");
|
||||
}
|
||||
// Parser should throw a SAXParseException
|
||||
@Test(expected = XmlBeanDefinitionStoreException.class)
|
||||
public void passwordEncoderCannotAppearAtTopLevel() {
|
||||
setContext("<password-encoder hash='md5'/>");
|
||||
}
|
||||
|
||||
@Test(expected=XmlBeanDefinitionStoreException.class)
|
||||
public void authenticationProviderCannotAppearAtTopLevel() {
|
||||
setContext("<authentication-provider ref='blah'/>");
|
||||
}
|
||||
@Test(expected = XmlBeanDefinitionStoreException.class)
|
||||
public void authenticationProviderCannotAppearAtTopLevel() {
|
||||
setContext("<authentication-provider ref='blah'/>");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingAuthenticationManagerGivesSensibleErrorMessage() {
|
||||
try {
|
||||
setContext("<http auto-config='true' />");
|
||||
} catch (BeanCreationException e) {
|
||||
Throwable cause = ultimateCause(e);
|
||||
assertTrue(cause instanceof NoSuchBeanDefinitionException);
|
||||
NoSuchBeanDefinitionException nsbe = (NoSuchBeanDefinitionException) cause;
|
||||
assertEquals(BeanIds.AUTHENTICATION_MANAGER, nsbe.getBeanName());
|
||||
assertTrue(nsbe.getMessage().endsWith(AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE));
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void missingAuthenticationManagerGivesSensibleErrorMessage() {
|
||||
try {
|
||||
setContext("<http auto-config='true' />");
|
||||
}
|
||||
catch (BeanCreationException e) {
|
||||
Throwable cause = ultimateCause(e);
|
||||
assertTrue(cause instanceof NoSuchBeanDefinitionException);
|
||||
NoSuchBeanDefinitionException nsbe = (NoSuchBeanDefinitionException) cause;
|
||||
assertEquals(BeanIds.AUTHENTICATION_MANAGER, nsbe.getBeanName());
|
||||
assertTrue(nsbe.getMessage().endsWith(
|
||||
AuthenticationManagerFactoryBean.MISSING_BEAN_ERROR_MESSAGE));
|
||||
}
|
||||
}
|
||||
|
||||
private Throwable ultimateCause(Throwable e) {
|
||||
if (e.getCause() == null) {
|
||||
return e;
|
||||
}
|
||||
return ultimateCause(e.getCause());
|
||||
}
|
||||
private Throwable ultimateCause(Throwable e) {
|
||||
if (e.getCause() == null) {
|
||||
return e;
|
||||
}
|
||||
return ultimateCause(e.getCause());
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,17 +9,18 @@ import org.springframework.security.core.Authentication;
|
||||
|
||||
public class MockAfterInvocationProvider implements AfterInvocationProvider {
|
||||
|
||||
public Object decide(Authentication authentication, Object object, Collection<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
return returnedObject;
|
||||
}
|
||||
public Object decide(Authentication authentication, Object object,
|
||||
Collection<ConfigAttribute> config, Object returnedObject)
|
||||
throws AccessDeniedException {
|
||||
return returnedObject;
|
||||
}
|
||||
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return true;
|
||||
}
|
||||
public boolean supports(ConfigAttribute attribute) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
public boolean supports(Class<?> clazz) {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -11,13 +11,14 @@ import org.springframework.transaction.TransactionStatus;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class MockTransactionManager implements PlatformTransactionManager {
|
||||
public TransactionStatus getTransaction(TransactionDefinition definition) throws TransactionException {
|
||||
return mock(TransactionStatus.class);
|
||||
}
|
||||
public TransactionStatus getTransaction(TransactionDefinition definition)
|
||||
throws TransactionException {
|
||||
return mock(TransactionStatus.class);
|
||||
}
|
||||
|
||||
public void commit(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
public void commit(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
|
||||
public void rollback(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
public void rollback(TransactionStatus status) throws TransactionException {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,25 @@ import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.config.BeanPostProcessor;
|
||||
|
||||
/**
|
||||
* Test bean post processor which injects a message into a PostProcessedMockUserDetailsService.
|
||||
* Test bean post processor which injects a message into a
|
||||
* PostProcessedMockUserDetailsService.
|
||||
*
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class MockUserServiceBeanPostProcessor implements BeanPostProcessor {
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if (bean instanceof PostProcessedMockUserDetailsService) {
|
||||
((PostProcessedMockUserDetailsService)bean).setPostProcessorWasHere("Hello from the post processor!");
|
||||
}
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof PostProcessedMockUserDetailsService) {
|
||||
((PostProcessedMockUserDetailsService) bean)
|
||||
.setPostProcessorWasHere("Hello from the post processor!");
|
||||
}
|
||||
|
||||
return bean;
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,21 +4,21 @@ import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
|
||||
public class PostProcessedMockUserDetailsService implements UserDetailsService {
|
||||
private String postProcessorWasHere;
|
||||
private String postProcessorWasHere;
|
||||
|
||||
public PostProcessedMockUserDetailsService() {
|
||||
this.postProcessorWasHere = "Post processor hasn't been yet";
|
||||
}
|
||||
public PostProcessedMockUserDetailsService() {
|
||||
this.postProcessorWasHere = "Post processor hasn't been yet";
|
||||
}
|
||||
|
||||
public String getPostProcessorWasHere() {
|
||||
return postProcessorWasHere;
|
||||
}
|
||||
public String getPostProcessorWasHere() {
|
||||
return postProcessorWasHere;
|
||||
}
|
||||
|
||||
public void setPostProcessorWasHere(String postProcessorWasHere) {
|
||||
this.postProcessorWasHere = postProcessorWasHere;
|
||||
}
|
||||
public void setPostProcessorWasHere(String postProcessorWasHere) {
|
||||
this.postProcessorWasHere = postProcessorWasHere;
|
||||
}
|
||||
|
||||
public UserDetails loadUserByUsername(String username) {
|
||||
throw new UnsupportedOperationException("Not for actual use");
|
||||
}
|
||||
public UserDetails loadUserByUsername(String username) {
|
||||
throw new UnsupportedOperationException("Not for actual use");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,115 +24,112 @@ import org.springframework.util.ClassUtils;
|
||||
* @since 3.0
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ClassUtils.class})
|
||||
@PrepareForTest({ ClassUtils.class })
|
||||
public class SecurityNamespaceHandlerTests {
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
@Rule
|
||||
public ExpectedException thrown = ExpectedException.none();
|
||||
|
||||
private static final String XML_AUTHENTICATION_MANAGER =
|
||||
"<authentication-manager>"+
|
||||
" <authentication-provider>"+
|
||||
" <user-service id='us'>"+
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
|
||||
" </user-service>"+
|
||||
" </authentication-provider>"+
|
||||
"</authentication-manager>";
|
||||
private static final String XML_HTTP_BLOCK = "<http auto-config='true'/>";
|
||||
private static final String FILTER_CHAIN_PROXY_CLASSNAME = "org.springframework.security.web.FilterChainProxy";
|
||||
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
|
||||
+ " <authentication-provider>" + " <user-service id='us'>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
private static final String XML_HTTP_BLOCK = "<http auto-config='true'/>";
|
||||
private static final String FILTER_CHAIN_PROXY_CLASSNAME = "org.springframework.security.web.FilterChainProxy";
|
||||
|
||||
@Test
|
||||
public void constructionSucceeds() {
|
||||
new SecurityNamespaceHandler();
|
||||
// Shameless class coverage stats boosting
|
||||
new BeanIds() {};
|
||||
new Elements() {};
|
||||
}
|
||||
@Test
|
||||
public void constructionSucceeds() {
|
||||
new SecurityNamespaceHandler();
|
||||
// Shameless class coverage stats boosting
|
||||
new BeanIds() {
|
||||
};
|
||||
new Elements() {
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void pre32SchemaAreNotSupported() throws Exception {
|
||||
try {
|
||||
new InMemoryXmlApplicationContext(
|
||||
"<user-service id='us'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
|
||||
"</user-service>", "3.0.3", null
|
||||
);
|
||||
fail("Expected BeanDefinitionParsingException");
|
||||
} catch (BeanDefinitionParsingException expected) {
|
||||
assertTrue(expected.getMessage().contains("You cannot use a spring-security-2.0.xsd"));
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void pre32SchemaAreNotSupported() throws Exception {
|
||||
try {
|
||||
new InMemoryXmlApplicationContext(
|
||||
"<user-service id='us'>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
|
||||
+ "</user-service>", "3.0.3", null);
|
||||
fail("Expected BeanDefinitionParsingException");
|
||||
}
|
||||
catch (BeanDefinitionParsingException expected) {
|
||||
assertTrue(expected.getMessage().contains(
|
||||
"You cannot use a spring-security-2.0.xsd"));
|
||||
}
|
||||
}
|
||||
|
||||
// SEC-1868
|
||||
@Test
|
||||
public void initDoesNotLogErrorWhenFilterChainProxyFailsToLoad() throws Exception {
|
||||
String className = "javax.servlet.Filter";
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class,"forName",eq(FILTER_CHAIN_PROXY_CLASSNAME),any(ClassLoader.class));
|
||||
// SEC-1868
|
||||
@Test
|
||||
public void initDoesNotLogErrorWhenFilterChainProxyFailsToLoad() throws Exception {
|
||||
String className = "javax.servlet.Filter";
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
|
||||
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
|
||||
|
||||
Log logger = mock(Log.class);
|
||||
SecurityNamespaceHandler handler = new SecurityNamespaceHandler();
|
||||
WhiteboxImpl.setInternalState(handler, Log.class, logger);
|
||||
Log logger = mock(Log.class);
|
||||
SecurityNamespaceHandler handler = new SecurityNamespaceHandler();
|
||||
WhiteboxImpl.setInternalState(handler, Log.class, logger);
|
||||
|
||||
handler.init();
|
||||
handler.init();
|
||||
|
||||
verifyStatic();
|
||||
ClassUtils.forName(eq(FILTER_CHAIN_PROXY_CLASSNAME),any(ClassLoader.class));
|
||||
verifyZeroInteractions(logger);
|
||||
}
|
||||
verifyStatic();
|
||||
ClassUtils.forName(eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
|
||||
verifyZeroInteractions(logger);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterNoClassDefFoundError() throws Exception {
|
||||
String className = "javax.servlet.Filter";
|
||||
thrown.expect(BeanDefinitionParsingException.class);
|
||||
thrown.expectMessage("NoClassDefFoundError: "+className);
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class,"forName",eq(FILTER_CHAIN_PROXY_CLASSNAME),any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(
|
||||
XML_AUTHENTICATION_MANAGER +
|
||||
XML_HTTP_BLOCK);
|
||||
}
|
||||
@Test
|
||||
public void filterNoClassDefFoundError() throws Exception {
|
||||
String className = "javax.servlet.Filter";
|
||||
thrown.expect(BeanDefinitionParsingException.class);
|
||||
thrown.expectMessage("NoClassDefFoundError: " + className);
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
|
||||
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER + XML_HTTP_BLOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterNoClassDefFoundErrorNoHttpBlock() throws Exception {
|
||||
String className = "javax.servlet.Filter";
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class,"forName",eq(FILTER_CHAIN_PROXY_CLASSNAME),any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
// should load just fine since no http block
|
||||
}
|
||||
@Test
|
||||
public void filterNoClassDefFoundErrorNoHttpBlock() throws Exception {
|
||||
String className = "javax.servlet.Filter";
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new NoClassDefFoundError(className)).when(ClassUtils.class, "forName",
|
||||
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER);
|
||||
// should load just fine since no http block
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterChainProxyClassNotFoundException() throws Exception {
|
||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||
thrown.expect(BeanDefinitionParsingException.class);
|
||||
thrown.expectMessage("ClassNotFoundException: "+className);
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class,"forName",eq(FILTER_CHAIN_PROXY_CLASSNAME),any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(
|
||||
XML_AUTHENTICATION_MANAGER +
|
||||
XML_HTTP_BLOCK);
|
||||
}
|
||||
@Test
|
||||
public void filterChainProxyClassNotFoundException() throws Exception {
|
||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||
thrown.expect(BeanDefinitionParsingException.class);
|
||||
thrown.expectMessage("ClassNotFoundException: " + className);
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
|
||||
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER + XML_HTTP_BLOCK);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void filterChainProxyClassNotFoundExceptionNoHttpBlock() throws Exception {
|
||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class,"forName",eq(FILTER_CHAIN_PROXY_CLASSNAME),any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
// should load just fine since no http block
|
||||
}
|
||||
@Test
|
||||
public void filterChainProxyClassNotFoundExceptionNoHttpBlock() throws Exception {
|
||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
|
||||
eq(FILTER_CHAIN_PROXY_CLASSNAME), any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER);
|
||||
// should load just fine since no http block
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Test
|
||||
public void websocketNotFoundExceptionNoMessageBlock() throws Exception {
|
||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class,"forName",eq(Message.class.getName()),any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
// should load just fine since no websocket block
|
||||
}
|
||||
@Test
|
||||
public void websocketNotFoundExceptionNoMessageBlock() throws Exception {
|
||||
String className = FILTER_CHAIN_PROXY_CLASSNAME;
|
||||
spy(ClassUtils.class);
|
||||
doThrow(new ClassNotFoundException(className)).when(ClassUtils.class, "forName",
|
||||
eq(Message.class.getName()), any(ClassLoader.class));
|
||||
new InMemoryXmlApplicationContext(XML_AUTHENTICATION_MANAGER);
|
||||
// should load just fine since no websocket block
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,13 +5,13 @@ package org.springframework.security.config;
|
||||
*/
|
||||
public interface TestBusinessBean {
|
||||
|
||||
void setInteger(int i);
|
||||
void setInteger(int i);
|
||||
|
||||
int getInteger();
|
||||
int getInteger();
|
||||
|
||||
void setString(String s);
|
||||
void setString(String s);
|
||||
|
||||
void doSomething();
|
||||
void doSomething();
|
||||
|
||||
void unprotected();
|
||||
void unprotected();
|
||||
}
|
||||
|
||||
@@ -7,28 +7,29 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
/**
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class TestBusinessBeanImpl implements TestBusinessBean, ApplicationListener<SessionCreationEvent> {
|
||||
public void setInteger(int i) {
|
||||
}
|
||||
public class TestBusinessBeanImpl implements TestBusinessBean,
|
||||
ApplicationListener<SessionCreationEvent> {
|
||||
public void setInteger(int i) {
|
||||
}
|
||||
|
||||
public int getInteger() {
|
||||
return 1314;
|
||||
}
|
||||
public int getInteger() {
|
||||
return 1314;
|
||||
}
|
||||
|
||||
public void setString(String s) {
|
||||
}
|
||||
public void setString(String s) {
|
||||
}
|
||||
|
||||
public String getString() {
|
||||
return "A string.";
|
||||
}
|
||||
public String getString() {
|
||||
return "A string.";
|
||||
}
|
||||
|
||||
public void doSomething() {
|
||||
}
|
||||
public void doSomething() {
|
||||
}
|
||||
|
||||
public void unprotected() {
|
||||
}
|
||||
public void unprotected() {
|
||||
}
|
||||
|
||||
public void onApplicationEvent(SessionCreationEvent event) {
|
||||
System.out.println(event);
|
||||
}
|
||||
public void onApplicationEvent(SessionCreationEvent event) {
|
||||
System.out.println(event);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,20 +6,20 @@ import org.springframework.transaction.annotation.Transactional;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class TransactionalTestBusinessBean implements TestBusinessBean {
|
||||
public void setInteger(int i) {
|
||||
}
|
||||
public void setInteger(int i) {
|
||||
}
|
||||
|
||||
public int getInteger() {
|
||||
return 0;
|
||||
}
|
||||
public int getInteger() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void setString(String s) {
|
||||
}
|
||||
public void setString(String s) {
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void doSomething() {
|
||||
}
|
||||
@Transactional
|
||||
public void doSomething() {
|
||||
}
|
||||
|
||||
public void unprotected() {
|
||||
}
|
||||
public void unprotected() {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,84 +55,83 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc;
|
||||
@WebAppConfiguration
|
||||
public class WebMvcSecurityConfigurationTests {
|
||||
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
@Autowired
|
||||
WebApplicationContext context;
|
||||
|
||||
MockMvc mockMvc;
|
||||
MockMvc mockMvc;
|
||||
|
||||
Authentication authentication;
|
||||
Authentication authentication;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
authentication = new TestingAuthenticationToken("user","password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
mockMvc = MockMvcBuilders.webAppContextSetup(context).build();
|
||||
authentication = new TestingAuthenticationToken("user", "password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(authentication);
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
@After
|
||||
public void cleanup() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void authenticationPrincipalResolved() throws Exception {
|
||||
mockMvc
|
||||
.perform(get("/authentication-principal"))
|
||||
.andExpect(assertResult(authentication.getPrincipal()))
|
||||
.andExpect(view().name("authentication-principal-view"));
|
||||
}
|
||||
@Test
|
||||
public void authenticationPrincipalResolved() throws Exception {
|
||||
mockMvc.perform(get("/authentication-principal"))
|
||||
.andExpect(assertResult(authentication.getPrincipal()))
|
||||
.andExpect(view().name("authentication-principal-view"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void deprecatedAuthenticationPrincipalResolved() throws Exception {
|
||||
mockMvc
|
||||
.perform(get("/deprecated-authentication-principal"))
|
||||
.andExpect(assertResult(authentication.getPrincipal()))
|
||||
.andExpect(view().name("deprecated-authentication-principal-view"));
|
||||
}
|
||||
@Test
|
||||
public void deprecatedAuthenticationPrincipalResolved() throws Exception {
|
||||
mockMvc.perform(get("/deprecated-authentication-principal"))
|
||||
.andExpect(assertResult(authentication.getPrincipal()))
|
||||
.andExpect(view().name("deprecated-authentication-principal-view"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfToken() throws Exception {
|
||||
CsrfToken csrfToken = new DefaultCsrfToken("headerName", "paramName", "token");
|
||||
MockHttpServletRequestBuilder request =
|
||||
get("/csrf")
|
||||
.requestAttr(CsrfToken.class.getName(), csrfToken);
|
||||
@Test
|
||||
public void csrfToken() throws Exception {
|
||||
CsrfToken csrfToken = new DefaultCsrfToken("headerName", "paramName", "token");
|
||||
MockHttpServletRequestBuilder request = get("/csrf").requestAttr(
|
||||
CsrfToken.class.getName(), csrfToken);
|
||||
|
||||
mockMvc
|
||||
.perform(request)
|
||||
.andExpect(assertResult(csrfToken));
|
||||
}
|
||||
mockMvc.perform(request).andExpect(assertResult(csrfToken));
|
||||
}
|
||||
|
||||
private ResultMatcher assertResult(Object expected) {
|
||||
return model().attribute("result", expected);
|
||||
}
|
||||
private ResultMatcher assertResult(Object expected) {
|
||||
return model().attribute("result", expected);
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class TestController {
|
||||
@Controller
|
||||
static class TestController {
|
||||
|
||||
@RequestMapping("/authentication-principal")
|
||||
public ModelAndView authenticationPrincipal(@AuthenticationPrincipal String principal) {
|
||||
return new ModelAndView("authentication-principal-view", "result", principal);
|
||||
}
|
||||
@RequestMapping("/authentication-principal")
|
||||
public ModelAndView authenticationPrincipal(
|
||||
@AuthenticationPrincipal String principal) {
|
||||
return new ModelAndView("authentication-principal-view", "result", principal);
|
||||
}
|
||||
|
||||
@RequestMapping("/deprecated-authentication-principal")
|
||||
public ModelAndView deprecatedAuthenticationPrincipal(@org.springframework.security.web.bind.annotation.AuthenticationPrincipal String principal) {
|
||||
return new ModelAndView("deprecated-authentication-principal-view", "result", principal);
|
||||
}
|
||||
@RequestMapping("/deprecated-authentication-principal")
|
||||
public ModelAndView deprecatedAuthenticationPrincipal(
|
||||
@org.springframework.security.web.bind.annotation.AuthenticationPrincipal String principal) {
|
||||
return new ModelAndView("deprecated-authentication-principal-view", "result",
|
||||
principal);
|
||||
}
|
||||
|
||||
@RequestMapping("/csrf")
|
||||
public ModelAndView csrf(CsrfToken token) {
|
||||
return new ModelAndView("view", "result", token);
|
||||
}
|
||||
}
|
||||
@RequestMapping("/csrf")
|
||||
public ModelAndView csrf(CsrfToken token) {
|
||||
return new ModelAndView("view", "result", token);
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
static class Config {
|
||||
@Bean
|
||||
public TestController testController() {
|
||||
return new TestController();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@EnableWebMvc
|
||||
@EnableWebSecurity
|
||||
static class Config {
|
||||
@Bean
|
||||
public TestController testController() {
|
||||
return new TestController();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -36,64 +36,65 @@ import org.springframework.web.servlet.support.RequestDataValueProcessor;
|
||||
*
|
||||
*/
|
||||
public class CsrfConfigurerNoWebMvcTests {
|
||||
ConfigurableApplicationContext context;
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void teardown() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void missingDispatcherServletPreventsCsrfRequestDataValueProcessor() {
|
||||
loadContext(EnableWebConfig.class);
|
||||
@Test
|
||||
public void missingDispatcherServletPreventsCsrfRequestDataValueProcessor() {
|
||||
loadContext(EnableWebConfig.class);
|
||||
|
||||
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
|
||||
}
|
||||
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void findDispatcherServletPreventsCsrfRequestDataValueProcessor() {
|
||||
loadContext(EnableWebMvcConfig.class);
|
||||
@Test
|
||||
public void findDispatcherServletPreventsCsrfRequestDataValueProcessor() {
|
||||
loadContext(EnableWebMvcConfig.class);
|
||||
|
||||
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
|
||||
}
|
||||
assertThat(context.containsBeanDefinition("requestDataValueProcessor")).isTrue();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void overrideCsrfRequestDataValueProcessor() {
|
||||
loadContext(EnableWebOverrideRequestDataConfig.class);
|
||||
@Test
|
||||
public void overrideCsrfRequestDataValueProcessor() {
|
||||
loadContext(EnableWebOverrideRequestDataConfig.class);
|
||||
|
||||
assertThat(context.getBean(RequestDataValueProcessor.class).getClass()).isNotEqualTo(CsrfRequestDataValueProcessor.class);
|
||||
}
|
||||
assertThat(context.getBean(RequestDataValueProcessor.class).getClass())
|
||||
.isNotEqualTo(CsrfRequestDataValueProcessor.class);
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class EnableWebConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class EnableWebConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class EnableWebOverrideRequestDataConfig {
|
||||
@Bean
|
||||
public RequestDataValueProcessor requestDataValueProcessor() {
|
||||
return mock(RequestDataValueProcessor.class);
|
||||
}
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class EnableWebOverrideRequestDataConfig {
|
||||
@Bean
|
||||
public RequestDataValueProcessor requestDataValueProcessor() {
|
||||
return mock(RequestDataValueProcessor.class);
|
||||
}
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class EnableWebMvcConfig extends WebSecurityConfigurerAdapter {
|
||||
@EnableWebSecurity
|
||||
static class EnableWebMvcConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
}
|
||||
}
|
||||
|
||||
private void loadContext(Class<?> configs) {
|
||||
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
|
||||
annotationConfigApplicationContext.register(configs);
|
||||
annotationConfigApplicationContext.refresh();
|
||||
this.context = annotationConfigApplicationContext;
|
||||
}
|
||||
private void loadContext(Class<?> configs) {
|
||||
AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
|
||||
annotationConfigApplicationContext.register(configs);
|
||||
annotationConfigApplicationContext.refresh();
|
||||
this.context = annotationConfigApplicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,96 +52,104 @@ import org.springframework.security.web.csrf.CsrfToken;
|
||||
import org.springframework.security.web.csrf.HttpSessionCsrfTokenRepository;
|
||||
import org.springframework.util.ReflectionUtils;
|
||||
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Rob Winch
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ReflectionUtils.class, Method.class})
|
||||
@PrepareForTest({ ReflectionUtils.class, Method.class })
|
||||
public class SessionManagementConfigurerServlet31Tests {
|
||||
@Mock
|
||||
Method method;
|
||||
@Mock
|
||||
Method method;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
ConfigurableApplicationContext context;
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
Filter springSecurityFilterChain;
|
||||
Filter springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void teardown() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
|
||||
CsrfToken token = repository.generateToken(request);
|
||||
repository.saveToken(token, request, response);
|
||||
request.setParameter(token.getParameterName(),token.getToken());
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
@Test
|
||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
|
||||
CsrfToken token = repository.generateToken(request);
|
||||
repository.saveToken(token, request, response);
|
||||
request.setParameter(token.getParameterName(), token.getToken());
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId"))
|
||||
.thenReturn(method);
|
||||
|
||||
loadConfig(SessionManagementDefaultSessionFixationServlet31Config.class);
|
||||
loadConfig(SessionManagementDefaultSessionFixationServlet31Config.class);
|
||||
|
||||
springSecurityFilterChain.doFilter(request,response,chain);
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@EnableWebSecurity
|
||||
static class SessionManagementDefaultSessionFixationServlet31Config extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.sessionManagement();
|
||||
}
|
||||
@EnableWebSecurity
|
||||
static class SessionManagementDefaultSessionFixationServlet31Config extends
|
||||
WebSecurityConfigurerAdapter {
|
||||
// @formatter:off
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
.formLogin()
|
||||
.and()
|
||||
.sessionManagement();
|
||||
}
|
||||
// @formatter:on
|
||||
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
}
|
||||
// @formatter:off
|
||||
@Override
|
||||
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
|
||||
auth
|
||||
.inMemoryAuthentication()
|
||||
.withUser("user").password("password").roles("USER");
|
||||
}
|
||||
// @formatter:on
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>...classes) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(classes);
|
||||
context.refresh();
|
||||
this.context = context;
|
||||
this.springSecurityFilterChain = this.context.getBean("springSecurityFilterChain",Filter.class);
|
||||
}
|
||||
private void loadConfig(Class<?>... classes) {
|
||||
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
|
||||
context.register(classes);
|
||||
context.refresh();
|
||||
this.context = context;
|
||||
this.springSecurityFilterChain = this.context.getBean(
|
||||
"springSecurityFilterChain", Filter.class);
|
||||
}
|
||||
|
||||
private void login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response);
|
||||
repo.loadContext(requestResponseHolder);
|
||||
private void login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(
|
||||
request, response);
|
||||
repo.loadContext(requestResponseHolder);
|
||||
|
||||
SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(auth);
|
||||
repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
|
||||
}
|
||||
SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(auth);
|
||||
repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(),
|
||||
requestResponseHolder.getResponse());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,298 +36,270 @@ import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class MessageSecurityMetadataSourceRegistryTests {
|
||||
@Mock
|
||||
private MessageMatcher<Object> matcher;
|
||||
@Mock
|
||||
private MessageMatcher<Object> matcher;
|
||||
|
||||
private MessageSecurityMetadataSourceRegistry messages;
|
||||
private MessageSecurityMetadataSourceRegistry messages;
|
||||
|
||||
private Message<String> message;
|
||||
private Message<String> message;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
messages = new MessageSecurityMetadataSourceRegistry();
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "location")
|
||||
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.MESSAGE)
|
||||
.build();
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
messages = new MessageSecurityMetadataSourceRegistry();
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "location")
|
||||
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
|
||||
SimpMessageType.MESSAGE).build();
|
||||
}
|
||||
|
||||
// See https://github.com/spring-projects/spring-security/commit/3f30529039c76facf335d6ca69d18d8ae287f3f9#commitcomment-7412712
|
||||
// https://jira.spring.io/browse/SPR-11660
|
||||
@Test
|
||||
public void simpDestMatchersCustom() {
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
|
||||
.build();
|
||||
messages
|
||||
.simpDestPathMatcher(new AntPathMatcher("."))
|
||||
.simpDestMatchers("price.stock.*").permitAll();
|
||||
// See
|
||||
// https://github.com/spring-projects/spring-security/commit/3f30529039c76facf335d6ca69d18d8ae287f3f9#commitcomment-7412712
|
||||
// https://jira.spring.io/browse/SPR-11660
|
||||
@Test
|
||||
public void simpDestMatchersCustom() {
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER,
|
||||
"price.stock.1.2").build();
|
||||
messages.simpDestPathMatcher(new AntPathMatcher("."))
|
||||
.simpDestMatchers("price.stock.*").permitAll();
|
||||
|
||||
assertThat(getAttribute()).isNull();
|
||||
assertThat(getAttribute()).isNull();
|
||||
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
|
||||
.build();
|
||||
messages
|
||||
.simpDestPathMatcher(new AntPathMatcher("."))
|
||||
.simpDestMatchers("price.stock.**").permitAll();
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER,
|
||||
"price.stock.1.2").build();
|
||||
messages.simpDestPathMatcher(new AntPathMatcher("."))
|
||||
.simpDestMatchers("price.stock.**").permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersCustomSetAfterMatchersDoesNotMatter() {
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
|
||||
.build();
|
||||
messages
|
||||
.simpDestMatchers("price.stock.*").permitAll()
|
||||
.simpDestPathMatcher(new AntPathMatcher("."));
|
||||
@Test
|
||||
public void simpDestMatchersCustomSetAfterMatchersDoesNotMatter() {
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER,
|
||||
"price.stock.1.2").build();
|
||||
messages.simpDestMatchers("price.stock.*").permitAll()
|
||||
.simpDestPathMatcher(new AntPathMatcher("."));
|
||||
|
||||
assertThat(getAttribute()).isNull();
|
||||
assertThat(getAttribute()).isNull();
|
||||
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER, "price.stock.1.2")
|
||||
.build();
|
||||
messages
|
||||
.simpDestMatchers("price.stock.**").permitAll()
|
||||
.simpDestPathMatcher(new AntPathMatcher("."));
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.DESTINATION_HEADER,
|
||||
"price.stock.1.2").build();
|
||||
messages.simpDestMatchers("price.stock.**").permitAll()
|
||||
.simpDestPathMatcher(new AntPathMatcher("."));
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void pathMatcherNull() {
|
||||
messages.simpDestPathMatcher(null);
|
||||
}
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void pathMatcherNull() {
|
||||
messages.simpDestPathMatcher(null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchersFalse() {
|
||||
messages
|
||||
.matchers(matcher).permitAll();
|
||||
@Test
|
||||
public void matchersFalse() {
|
||||
messages.matchers(matcher).permitAll();
|
||||
|
||||
assertThat(getAttribute()).isNull();
|
||||
}
|
||||
assertThat(getAttribute()).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void matchersTrue() {
|
||||
when(matcher.matches(message)).thenReturn(true);
|
||||
messages
|
||||
.matchers(matcher).permitAll();
|
||||
@Test
|
||||
public void matchersTrue() {
|
||||
when(matcher.matches(message)).thenReturn(true);
|
||||
messages.matchers(matcher).permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersExact() {
|
||||
messages
|
||||
.simpDestMatchers("location").permitAll();
|
||||
@Test
|
||||
public void simpDestMatchersExact() {
|
||||
messages.simpDestMatchers("location").permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersMulti() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","api/**").hasRole("ADMIN")
|
||||
.simpDestMatchers("location").permitAll();
|
||||
@Test
|
||||
public void simpDestMatchersMulti() {
|
||||
messages.simpDestMatchers("admin/**", "api/**").hasRole("ADMIN")
|
||||
.simpDestMatchers("location").permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersRole() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").hasRole("ADMIN")
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersRole() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").hasRole("ADMIN")
|
||||
.anyMessage().denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("hasRole('ROLE_ADMIN')");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("hasRole('ROLE_ADMIN')");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersAnyRole() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").hasAnyRole("ADMIN", "ROOT")
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersAnyRole() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").hasAnyRole("ADMIN", "ROOT")
|
||||
.anyMessage().denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("hasAnyRole('ROLE_ADMIN','ROLE_ROOT')");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("hasAnyRole('ROLE_ADMIN','ROLE_ROOT')");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersAuthority() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").hasAuthority("ROLE_ADMIN")
|
||||
.anyMessage().fullyAuthenticated();
|
||||
@Test
|
||||
public void simpDestMatchersAuthority() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").hasAuthority("ROLE_ADMIN")
|
||||
.anyMessage().fullyAuthenticated();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("hasAuthority('ROLE_ADMIN')");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("hasAuthority('ROLE_ADMIN')");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersAccess() {
|
||||
String expected = "hasRole('ROLE_ADMIN') and fullyAuthenticated";
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").access(expected)
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersAccess() {
|
||||
String expected = "hasRole('ROLE_ADMIN') and fullyAuthenticated";
|
||||
messages.simpDestMatchers("admin/**", "location/**").access(expected)
|
||||
.anyMessage().denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo(expected);
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo(expected);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersAnyAuthority() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").hasAnyAuthority("ROLE_ADMIN", "ROLE_ROOT")
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersAnyAuthority() {
|
||||
messages.simpDestMatchers("admin/**", "location/**")
|
||||
.hasAnyAuthority("ROLE_ADMIN", "ROLE_ROOT").anyMessage().denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("hasAnyAuthority('ROLE_ADMIN','ROLE_ROOT')");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("hasAnyAuthority('ROLE_ADMIN','ROLE_ROOT')");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersRememberMe() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").rememberMe()
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersRememberMe() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").rememberMe().anyMessage()
|
||||
.denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("rememberMe");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("rememberMe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersAnonymous() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").anonymous()
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersAnonymous() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").anonymous().anyMessage()
|
||||
.denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("anonymous");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("anonymous");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersFullyAuthenticated() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").fullyAuthenticated()
|
||||
.anyMessage().denyAll();
|
||||
@Test
|
||||
public void simpDestMatchersFullyAuthenticated() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").fullyAuthenticated()
|
||||
.anyMessage().denyAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("fullyAuthenticated");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("fullyAuthenticated");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMatchersDenyAll() {
|
||||
messages
|
||||
.simpDestMatchers("admin/**","location/**").denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpDestMatchersDenyAll() {
|
||||
messages.simpDestMatchers("admin/**", "location/**").denyAll().anyMessage()
|
||||
.permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMessageMatchersNotMatch() {
|
||||
messages
|
||||
.simpMessageDestMatchers("admin/**").denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpDestMessageMatchersNotMatch() {
|
||||
messages.simpMessageDestMatchers("admin/**").denyAll().anyMessage().permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestMessageMatchersMatch() {
|
||||
messages
|
||||
.simpMessageDestMatchers("location/**").denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpDestMessageMatchersMatch() {
|
||||
messages.simpMessageDestMatchers("location/**").denyAll().anyMessage()
|
||||
.permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestSubscribeMatchersNotMatch() {
|
||||
messages
|
||||
.simpSubscribeDestMatchers("location/**").denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpDestSubscribeMatchersNotMatch() {
|
||||
messages.simpSubscribeDestMatchers("location/**").denyAll().anyMessage()
|
||||
.permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpDestSubscribeMatchersMatch() {
|
||||
message = MessageBuilder.fromMessage(message)
|
||||
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.SUBSCRIBE)
|
||||
.build();
|
||||
@Test
|
||||
public void simpDestSubscribeMatchersMatch() {
|
||||
message = MessageBuilder
|
||||
.fromMessage(message)
|
||||
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
|
||||
SimpMessageType.SUBSCRIBE).build();
|
||||
|
||||
messages
|
||||
.simpSubscribeDestMatchers("location/**").denyAll()
|
||||
.anyMessage().permitAll();
|
||||
messages.simpSubscribeDestMatchers("location/**").denyAll().anyMessage()
|
||||
.permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullDestMatcherNotMatches() {
|
||||
messages
|
||||
.nullDestMatcher().denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void nullDestMatcherNotMatches() {
|
||||
messages.nullDestMatcher().denyAll().anyMessage().permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void nullDestMatcherMatch() {
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER, SimpMessageType.CONNECT)
|
||||
.build();
|
||||
@Test
|
||||
public void nullDestMatcherMatch() {
|
||||
message = MessageBuilder
|
||||
.withPayload("Hi")
|
||||
.setHeader(SimpMessageHeaderAccessor.MESSAGE_TYPE_HEADER,
|
||||
SimpMessageType.CONNECT).build();
|
||||
|
||||
messages
|
||||
.nullDestMatcher().denyAll()
|
||||
.anyMessage().permitAll();
|
||||
messages.nullDestMatcher().denyAll().anyMessage().permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpTypeMatchersMatch() {
|
||||
messages
|
||||
.simpTypeMatchers(SimpMessageType.MESSAGE).denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpTypeMatchersMatch() {
|
||||
messages.simpTypeMatchers(SimpMessageType.MESSAGE).denyAll().anyMessage()
|
||||
.permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpTypeMatchersMatchMulti() {
|
||||
messages
|
||||
.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.MESSAGE).denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpTypeMatchersMatchMulti() {
|
||||
messages.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.MESSAGE)
|
||||
.denyAll().anyMessage().permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("denyAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpTypeMatchersNotMatch() {
|
||||
messages
|
||||
.simpTypeMatchers(SimpMessageType.CONNECT).denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpTypeMatchersNotMatch() {
|
||||
messages.simpTypeMatchers(SimpMessageType.CONNECT).denyAll().anyMessage()
|
||||
.permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpTypeMatchersNotMatchMulti() {
|
||||
messages
|
||||
.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.DISCONNECT).denyAll()
|
||||
.anyMessage().permitAll();
|
||||
@Test
|
||||
public void simpTypeMatchersNotMatchMulti() {
|
||||
messages.simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.DISCONNECT)
|
||||
.denyAll().anyMessage().permitAll();
|
||||
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
assertThat(getAttribute()).isEqualTo("permitAll");
|
||||
}
|
||||
|
||||
private String getAttribute() {
|
||||
MessageSecurityMetadataSource source = messages.createMetadataSource();
|
||||
Collection<ConfigAttribute> attrs = source.getAttributes(message);
|
||||
if(attrs == null) {
|
||||
return null;
|
||||
}
|
||||
assertThat(attrs.size()).isEqualTo(1);
|
||||
return attrs.iterator().next().toString();
|
||||
}
|
||||
private String getAttribute() {
|
||||
MessageSecurityMetadataSource source = messages.createMetadataSource();
|
||||
Collection<ConfigAttribute> attrs = source.getAttributes(message);
|
||||
if (attrs == null) {
|
||||
return null;
|
||||
}
|
||||
assertThat(attrs.size()).isEqualTo(1);
|
||||
return attrs.iterator().next().toString();
|
||||
}
|
||||
}
|
||||
@@ -68,124 +68,127 @@ import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class AbstractSecurityWebSocketMessageBrokerConfigurerDocTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
TestingAuthenticationToken messageUser;
|
||||
TestingAuthenticationToken messageUser;
|
||||
|
||||
CsrfToken token;
|
||||
CsrfToken token;
|
||||
|
||||
String sessionAttr;
|
||||
String sessionAttr;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
token = new DefaultCsrfToken("header", "param", "token");
|
||||
sessionAttr = "sessionAttr";
|
||||
messageUser = new TestingAuthenticationToken("user","pass","ROLE_USER");
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
token = new DefaultCsrfToken("header", "param", "token");
|
||||
sessionAttr = "sessionAttr";
|
||||
messageUser = new TestingAuthenticationToken("user", "pass", "ROLE_USER");
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void securityMappings() {
|
||||
loadConfig(WebSocketSecurityConfig.class);
|
||||
@Test
|
||||
public void securityMappings() {
|
||||
loadConfig(WebSocketSecurityConfig.class);
|
||||
|
||||
clientInboundChannel().send(message("/user/queue/errors",SimpMessageType.SUBSCRIBE));
|
||||
clientInboundChannel().send(
|
||||
message("/user/queue/errors", SimpMessageType.SUBSCRIBE));
|
||||
|
||||
try {
|
||||
clientInboundChannel().send(message("/denyAll", SimpMessageType.MESSAGE));
|
||||
fail("Expected Exception");
|
||||
} catch(MessageDeliveryException expected) {
|
||||
assertThat(expected.getCause()).isInstanceOf(AccessDeniedException.class);
|
||||
}
|
||||
}
|
||||
try {
|
||||
clientInboundChannel().send(message("/denyAll", SimpMessageType.MESSAGE));
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (MessageDeliveryException expected) {
|
||||
assertThat(expected.getCause()).isInstanceOf(AccessDeniedException.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.register(WebSocketConfig.class, SyncExecutorConfig.class);
|
||||
context.setServletConfig(new MockServletConfig());
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.register(WebSocketConfig.class,SyncExecutorConfig.class);
|
||||
context.setServletConfig(new MockServletConfig());
|
||||
context.refresh();
|
||||
}
|
||||
private MessageChannel clientInboundChannel() {
|
||||
return context.getBean("clientInboundChannel", MessageChannel.class);
|
||||
}
|
||||
|
||||
private MessageChannel clientInboundChannel() {
|
||||
return context.getBean("clientInboundChannel", MessageChannel.class);
|
||||
}
|
||||
private Message<String> message(String destination, SimpMessageType type) {
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type);
|
||||
return message(headers, destination);
|
||||
}
|
||||
|
||||
private Message<String> message(String destination, SimpMessageType type) {
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(type);
|
||||
return message(headers, destination);
|
||||
}
|
||||
private Message<String> message(SimpMessageHeaderAccessor headers, String destination) {
|
||||
headers.setSessionId("123");
|
||||
headers.setSessionAttributes(new HashMap<String, Object>());
|
||||
if (destination != null) {
|
||||
headers.setDestination(destination);
|
||||
}
|
||||
if (messageUser != null) {
|
||||
headers.setUser(messageUser);
|
||||
}
|
||||
return new GenericMessage<String>("hi", headers.getMessageHeaders());
|
||||
}
|
||||
|
||||
private Message<String> message(SimpMessageHeaderAccessor headers, String destination) {
|
||||
headers.setSessionId("123");
|
||||
headers.setSessionAttributes(new HashMap<String, Object>());
|
||||
if(destination != null) {
|
||||
headers.setDestination(destination);
|
||||
}
|
||||
if(messageUser != null) {
|
||||
headers.setUser(messageUser);
|
||||
}
|
||||
return new GenericMessage<String>("hi",headers.getMessageHeaders());
|
||||
}
|
||||
@Controller
|
||||
static class MyController {
|
||||
|
||||
@Controller
|
||||
static class MyController {
|
||||
@MessageMapping("/authentication")
|
||||
public void authentication(@AuthenticationPrincipal String un) {
|
||||
// ... do something ...
|
||||
}
|
||||
}
|
||||
|
||||
@MessageMapping("/authentication")
|
||||
public void authentication(@AuthenticationPrincipal String un) {
|
||||
// ... do something ...
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class WebSocketSecurityConfig extends
|
||||
AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Configuration
|
||||
static class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages.nullDestMatcher().authenticated()
|
||||
// <1>
|
||||
.simpSubscribeDestMatchers("/user/queue/errors").permitAll()
|
||||
// <2>
|
||||
.simpDestMatchers("/app/**").hasRole("USER")
|
||||
// <3>
|
||||
.simpSubscribeDestMatchers("/user/**", "/topic/friends/*")
|
||||
.hasRole("USER") // <4>
|
||||
.simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() // <5>
|
||||
.anyMessage().denyAll(); // <6>
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages
|
||||
.nullDestMatcher().authenticated() // <1>
|
||||
.simpSubscribeDestMatchers("/user/queue/errors").permitAll() // <2>
|
||||
.simpDestMatchers("/app/**").hasRole("USER") // <3>
|
||||
.simpSubscribeDestMatchers("/user/**", "/topic/friends/*").hasRole("USER") // <4>
|
||||
.simpTypeMatchers(MESSAGE, SUBSCRIBE).denyAll() // <5>
|
||||
.anyMessage().denyAll(); // <6>
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
static class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
static class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/chat").withSockJS();
|
||||
}
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry
|
||||
.addEndpoint("/chat")
|
||||
.withSockJS();
|
||||
}
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll");
|
||||
}
|
||||
@Bean
|
||||
public MyController myController() {
|
||||
return new MyController();
|
||||
}
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyController myController() {
|
||||
return new MyController();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SyncExecutorConfig {
|
||||
@Bean
|
||||
public static SyncExecutorSubscribableChannelPostProcessor postProcessor() {
|
||||
return new SyncExecutorSubscribableChannelPostProcessor();
|
||||
}
|
||||
}
|
||||
@Configuration
|
||||
static class SyncExecutorConfig {
|
||||
@Bean
|
||||
public static SyncExecutorSubscribableChannelPostProcessor postProcessor() {
|
||||
return new SyncExecutorSubscribableChannelPostProcessor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package org.springframework.security.config.annotation.web.socket;
|
||||
|
||||
|
||||
import org.junit.After;
|
||||
import org.junit.Before;
|
||||
|
||||
@@ -67,380 +66,387 @@ import static org.fest.assertions.Assertions.assertThat;
|
||||
import static org.junit.Assert.fail;
|
||||
|
||||
public class AbstractSecurityWebSocketMessageBrokerConfigurerTests {
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
TestingAuthenticationToken messageUser;
|
||||
|
||||
CsrfToken token;
|
||||
|
||||
String sessionAttr;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
token = new DefaultCsrfToken("header", "param", "token");
|
||||
sessionAttr = "sessionAttr";
|
||||
messageUser = new TestingAuthenticationToken("user","pass","ROLE_USER");
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleRegistryMappings() {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
clientInboundChannel().send(message("/permitAll"));
|
||||
|
||||
try {
|
||||
clientInboundChannel().send(message("/denyAll"));
|
||||
fail("Expected Exception");
|
||||
} catch(MessageDeliveryException expected) {
|
||||
assertThat(expected.getCause()).isInstanceOf(AccessDeniedException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annonymousSupported() {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
messageUser = null;
|
||||
clientInboundChannel().send(message("/permitAll"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsAuthenticationPrincipalResolver() throws InterruptedException {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
Message<String> message = message("/permitAll/authentication");
|
||||
messageChannel.send(message);
|
||||
|
||||
assertThat(context.getBean(MyController.class).authenticationPrincipal).isEqualTo((String) messageUser.getPrincipal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsAuthenticationPrincipalResolverWhenNoAuthorization() throws InterruptedException {
|
||||
loadConfig(NoInboundSecurityConfig.class);
|
||||
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
Message<String> message = message("/permitAll/authentication");
|
||||
messageChannel.send(message);
|
||||
|
||||
assertThat(context.getBean(MyController.class).authenticationPrincipal).isEqualTo((String) messageUser.getPrincipal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsCsrfProtectionWhenNoAuthorization() throws InterruptedException {
|
||||
loadConfig(NoInboundSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
|
||||
try {
|
||||
messageChannel.send(message);
|
||||
fail("Expected Exception");
|
||||
} catch(MessageDeliveryException success) {
|
||||
assertThat(success.getCause()).isInstanceOf(MissingCsrfTokenException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfProtectionForConnect() throws InterruptedException {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
|
||||
try {
|
||||
messageChannel.send(message);
|
||||
fail("Expected Exception");
|
||||
} catch(MessageDeliveryException success) {
|
||||
assertThat(success.getCause()).isInstanceOf(MissingCsrfTokenException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfProtectionDisabledForConnect() throws InterruptedException {
|
||||
loadConfig(CsrfDisabledSockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/permitAll/connect");
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
|
||||
messageChannel.send(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesConnectUseCsrfTokenHandshakeInterceptor() throws Exception {
|
||||
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MockHttpServletRequest request = sockjsHttpRequest("/chat");
|
||||
HttpRequestHandler handler = handler(request);
|
||||
|
||||
handler.handleRequest(request, new MockHttpServletResponse());
|
||||
|
||||
assertHandshake(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesConnectUseCsrfTokenHandshakeInterceptorMultipleMappings() throws Exception {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MockHttpServletRequest request = sockjsHttpRequest("/other");
|
||||
HttpRequestHandler handler = handler(request);
|
||||
|
||||
handler.handleRequest(request, new MockHttpServletResponse());
|
||||
|
||||
assertHandshake(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesConnectWebSocketUseCsrfTokenHandshakeInterceptor() throws Exception {
|
||||
loadConfig(WebSocketSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MockHttpServletRequest request = websocketHttpRequest("/websocket");
|
||||
HttpRequestHandler handler = handler(request);
|
||||
|
||||
handler.handleRequest(request, new MockHttpServletResponse());
|
||||
|
||||
assertHandshake(request);
|
||||
}
|
||||
|
||||
private void assertHandshake(HttpServletRequest request) {
|
||||
TestHandshakeHandler handshakeHandler = context.getBean(TestHandshakeHandler.class);
|
||||
assertThat(handshakeHandler.attributes.get(CsrfToken.class.getName())).isSameAs(token);
|
||||
assertThat(handshakeHandler.attributes.get(sessionAttr)).isEqualTo(request.getSession().getAttribute(sessionAttr));
|
||||
}
|
||||
|
||||
private HttpRequestHandler handler(HttpServletRequest request) throws Exception {
|
||||
HandlerMapping handlerMapping = context.getBean(HandlerMapping.class);
|
||||
return (HttpRequestHandler) handlerMapping.getHandler(request).getHandler();
|
||||
}
|
||||
|
||||
private MockHttpServletRequest websocketHttpRequest(String mapping) {
|
||||
MockHttpServletRequest request = sockjsHttpRequest(mapping);
|
||||
request.setRequestURI(mapping);
|
||||
return request;
|
||||
}
|
||||
|
||||
private MockHttpServletRequest sockjsHttpRequest(String mapping) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("GET");
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE, "/289/tpyx6mde/websocket");
|
||||
request.setRequestURI(mapping + "/289/tpyx6mde/websocket");
|
||||
request.getSession().setAttribute(sessionAttr,"sessionValue");
|
||||
|
||||
request.setAttribute(CsrfToken.class.getName(), token);
|
||||
return request;
|
||||
}
|
||||
|
||||
private Message<String> message(String destination) {
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create();
|
||||
return message(headers, destination);
|
||||
}
|
||||
|
||||
private Message<String> message(SimpMessageHeaderAccessor headers, String destination) {
|
||||
headers.setSessionId("123");
|
||||
headers.setSessionAttributes(new HashMap<String, Object>());
|
||||
if(destination != null) {
|
||||
headers.setDestination(destination);
|
||||
}
|
||||
if(messageUser != null) {
|
||||
headers.setUser(messageUser);
|
||||
}
|
||||
return new GenericMessage<String>("hi",headers.getMessageHeaders());
|
||||
}
|
||||
|
||||
private MessageChannel clientInboundChannel() {
|
||||
return context.getBean("clientInboundChannel", MessageChannel.class);
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.setServletConfig(new MockServletConfig());
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
|
||||
@Controller
|
||||
static class MyController {
|
||||
|
||||
String authenticationPrincipal;
|
||||
MyCustomArgument myCustomArgument;
|
||||
|
||||
|
||||
@MessageMapping("/authentication")
|
||||
public void authentication(@AuthenticationPrincipal String un) {
|
||||
this.authenticationPrincipal = un;
|
||||
}
|
||||
|
||||
@MessageMapping("/myCustom")
|
||||
public void myCustom(MyCustomArgument myCustomArgument) {
|
||||
this.myCustomArgument = myCustomArgument;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyCustomArgument {
|
||||
MyCustomArgument(String notDefaultConstr) {}
|
||||
}
|
||||
|
||||
static class MyCustomArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return parameter.getParameterType().isAssignableFrom(MyCustomArgument.class);
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter, Message<?> message) throws Exception {
|
||||
return new MyCustomArgument("");
|
||||
}
|
||||
}
|
||||
|
||||
static class TestHandshakeHandler implements HandshakeHandler {
|
||||
Map<String, Object> attributes;
|
||||
|
||||
public boolean doHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws HandshakeFailureException {
|
||||
this.attributes = attributes;
|
||||
if(wsHandler instanceof SockJsWebSocketHandler) {
|
||||
// work around SPR-12716
|
||||
SockJsWebSocketHandler sockJs = (SockJsWebSocketHandler) wsHandler;
|
||||
WebSocketServerSockJsSession session = (WebSocketServerSockJsSession) ReflectionTestUtils.getField(sockJs, "sockJsSession");
|
||||
this.attributes = session.getAttributes();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class SockJsSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry
|
||||
.addEndpoint("/other")
|
||||
.setHandshakeHandler(testHandshakeHandler())
|
||||
.withSockJS()
|
||||
.setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
|
||||
registry
|
||||
.addEndpoint("/chat")
|
||||
.setHandshakeHandler(testHandshakeHandler())
|
||||
.withSockJS()
|
||||
.setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages
|
||||
.simpDestMatchers("/permitAll/**").permitAll()
|
||||
.anyMessage().denyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyController myController() {
|
||||
return new MyController();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestHandshakeHandler testHandshakeHandler() {
|
||||
return new TestHandshakeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class NoInboundSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry
|
||||
.addEndpoint("/other")
|
||||
.withSockJS()
|
||||
.setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
|
||||
registry
|
||||
.addEndpoint("/chat")
|
||||
.withSockJS()
|
||||
.setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyController myController() {
|
||||
return new MyController();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CsrfDisabledSockJsSecurityConfig extends SockJsSecurityConfig {
|
||||
|
||||
@Override
|
||||
protected boolean sameOriginDisabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry
|
||||
.addEndpoint("/websocket")
|
||||
.setHandshakeHandler(testHandshakeHandler())
|
||||
.addInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages
|
||||
.simpDestMatchers("/permitAll/**").permitAll()
|
||||
.anyMessage().denyAll();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestHandshakeHandler testHandshakeHandler() {
|
||||
return new TestHandshakeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SyncExecutorConfig {
|
||||
@Bean
|
||||
public static SyncExecutorSubscribableChannelPostProcessor postProcessor() {
|
||||
return new SyncExecutorSubscribableChannelPostProcessor();
|
||||
}
|
||||
}
|
||||
AnnotationConfigWebApplicationContext context;
|
||||
|
||||
TestingAuthenticationToken messageUser;
|
||||
|
||||
CsrfToken token;
|
||||
|
||||
String sessionAttr;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
token = new DefaultCsrfToken("header", "param", "token");
|
||||
sessionAttr = "sessionAttr";
|
||||
messageUser = new TestingAuthenticationToken("user", "pass", "ROLE_USER");
|
||||
}
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void simpleRegistryMappings() {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
clientInboundChannel().send(message("/permitAll"));
|
||||
|
||||
try {
|
||||
clientInboundChannel().send(message("/denyAll"));
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (MessageDeliveryException expected) {
|
||||
assertThat(expected.getCause()).isInstanceOf(AccessDeniedException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void annonymousSupported() {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
messageUser = null;
|
||||
clientInboundChannel().send(message("/permitAll"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsAuthenticationPrincipalResolver() throws InterruptedException {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
Message<String> message = message("/permitAll/authentication");
|
||||
messageChannel.send(message);
|
||||
|
||||
assertThat(context.getBean(MyController.class).authenticationPrincipal)
|
||||
.isEqualTo((String) messageUser.getPrincipal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsAuthenticationPrincipalResolverWhenNoAuthorization()
|
||||
throws InterruptedException {
|
||||
loadConfig(NoInboundSecurityConfig.class);
|
||||
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
Message<String> message = message("/permitAll/authentication");
|
||||
messageChannel.send(message);
|
||||
|
||||
assertThat(context.getBean(MyController.class).authenticationPrincipal)
|
||||
.isEqualTo((String) messageUser.getPrincipal());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void addsCsrfProtectionWhenNoAuthorization() throws InterruptedException {
|
||||
loadConfig(NoInboundSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor
|
||||
.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
|
||||
try {
|
||||
messageChannel.send(message);
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (MessageDeliveryException success) {
|
||||
assertThat(success.getCause()).isInstanceOf(MissingCsrfTokenException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfProtectionForConnect() throws InterruptedException {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor
|
||||
.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
|
||||
try {
|
||||
messageChannel.send(message);
|
||||
fail("Expected Exception");
|
||||
}
|
||||
catch (MessageDeliveryException success) {
|
||||
assertThat(success.getCause()).isInstanceOf(MissingCsrfTokenException.class);
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void csrfProtectionDisabledForConnect() throws InterruptedException {
|
||||
loadConfig(CsrfDisabledSockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor
|
||||
.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/permitAll/connect");
|
||||
MessageChannel messageChannel = clientInboundChannel();
|
||||
|
||||
messageChannel.send(message);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesConnectUseCsrfTokenHandshakeInterceptor() throws Exception {
|
||||
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor
|
||||
.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MockHttpServletRequest request = sockjsHttpRequest("/chat");
|
||||
HttpRequestHandler handler = handler(request);
|
||||
|
||||
handler.handleRequest(request, new MockHttpServletResponse());
|
||||
|
||||
assertHandshake(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesConnectUseCsrfTokenHandshakeInterceptorMultipleMappings()
|
||||
throws Exception {
|
||||
loadConfig(SockJsSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor
|
||||
.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MockHttpServletRequest request = sockjsHttpRequest("/other");
|
||||
HttpRequestHandler handler = handler(request);
|
||||
|
||||
handler.handleRequest(request, new MockHttpServletResponse());
|
||||
|
||||
assertHandshake(request);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void messagesConnectWebSocketUseCsrfTokenHandshakeInterceptor()
|
||||
throws Exception {
|
||||
loadConfig(WebSocketSecurityConfig.class);
|
||||
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor
|
||||
.create(SimpMessageType.CONNECT);
|
||||
Message<?> message = message(headers, "/authentication");
|
||||
MockHttpServletRequest request = websocketHttpRequest("/websocket");
|
||||
HttpRequestHandler handler = handler(request);
|
||||
|
||||
handler.handleRequest(request, new MockHttpServletResponse());
|
||||
|
||||
assertHandshake(request);
|
||||
}
|
||||
|
||||
private void assertHandshake(HttpServletRequest request) {
|
||||
TestHandshakeHandler handshakeHandler = context
|
||||
.getBean(TestHandshakeHandler.class);
|
||||
assertThat(handshakeHandler.attributes.get(CsrfToken.class.getName())).isSameAs(
|
||||
token);
|
||||
assertThat(handshakeHandler.attributes.get(sessionAttr)).isEqualTo(
|
||||
request.getSession().getAttribute(sessionAttr));
|
||||
}
|
||||
|
||||
private HttpRequestHandler handler(HttpServletRequest request) throws Exception {
|
||||
HandlerMapping handlerMapping = context.getBean(HandlerMapping.class);
|
||||
return (HttpRequestHandler) handlerMapping.getHandler(request).getHandler();
|
||||
}
|
||||
|
||||
private MockHttpServletRequest websocketHttpRequest(String mapping) {
|
||||
MockHttpServletRequest request = sockjsHttpRequest(mapping);
|
||||
request.setRequestURI(mapping);
|
||||
return request;
|
||||
}
|
||||
|
||||
private MockHttpServletRequest sockjsHttpRequest(String mapping) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setMethod("GET");
|
||||
request.setAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE,
|
||||
"/289/tpyx6mde/websocket");
|
||||
request.setRequestURI(mapping + "/289/tpyx6mde/websocket");
|
||||
request.getSession().setAttribute(sessionAttr, "sessionValue");
|
||||
|
||||
request.setAttribute(CsrfToken.class.getName(), token);
|
||||
return request;
|
||||
}
|
||||
|
||||
private Message<String> message(String destination) {
|
||||
SimpMessageHeaderAccessor headers = SimpMessageHeaderAccessor.create();
|
||||
return message(headers, destination);
|
||||
}
|
||||
|
||||
private Message<String> message(SimpMessageHeaderAccessor headers, String destination) {
|
||||
headers.setSessionId("123");
|
||||
headers.setSessionAttributes(new HashMap<String, Object>());
|
||||
if (destination != null) {
|
||||
headers.setDestination(destination);
|
||||
}
|
||||
if (messageUser != null) {
|
||||
headers.setUser(messageUser);
|
||||
}
|
||||
return new GenericMessage<String>("hi", headers.getMessageHeaders());
|
||||
}
|
||||
|
||||
private MessageChannel clientInboundChannel() {
|
||||
return context.getBean("clientInboundChannel", MessageChannel.class);
|
||||
}
|
||||
|
||||
private void loadConfig(Class<?>... configs) {
|
||||
context = new AnnotationConfigWebApplicationContext();
|
||||
context.register(configs);
|
||||
context.setServletConfig(new MockServletConfig());
|
||||
context.refresh();
|
||||
}
|
||||
|
||||
@Controller
|
||||
static class MyController {
|
||||
|
||||
String authenticationPrincipal;
|
||||
MyCustomArgument myCustomArgument;
|
||||
|
||||
@MessageMapping("/authentication")
|
||||
public void authentication(@AuthenticationPrincipal String un) {
|
||||
this.authenticationPrincipal = un;
|
||||
}
|
||||
|
||||
@MessageMapping("/myCustom")
|
||||
public void myCustom(MyCustomArgument myCustomArgument) {
|
||||
this.myCustomArgument = myCustomArgument;
|
||||
}
|
||||
}
|
||||
|
||||
static class MyCustomArgument {
|
||||
MyCustomArgument(String notDefaultConstr) {
|
||||
}
|
||||
}
|
||||
|
||||
static class MyCustomArgumentResolver implements HandlerMethodArgumentResolver {
|
||||
|
||||
public boolean supportsParameter(MethodParameter parameter) {
|
||||
return parameter.getParameterType().isAssignableFrom(MyCustomArgument.class);
|
||||
}
|
||||
|
||||
public Object resolveArgument(MethodParameter parameter, Message<?> message)
|
||||
throws Exception {
|
||||
return new MyCustomArgument("");
|
||||
}
|
||||
}
|
||||
|
||||
static class TestHandshakeHandler implements HandshakeHandler {
|
||||
Map<String, Object> attributes;
|
||||
|
||||
public boolean doHandshake(ServerHttpRequest request,
|
||||
ServerHttpResponse response, WebSocketHandler wsHandler,
|
||||
Map<String, Object> attributes) throws HandshakeFailureException {
|
||||
this.attributes = attributes;
|
||||
if (wsHandler instanceof SockJsWebSocketHandler) {
|
||||
// work around SPR-12716
|
||||
SockJsWebSocketHandler sockJs = (SockJsWebSocketHandler) wsHandler;
|
||||
WebSocketServerSockJsSession session = (WebSocketServerSockJsSession) ReflectionTestUtils
|
||||
.getField(sockJs, "sockJsSession");
|
||||
this.attributes = session.getAttributes();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class SockJsSecurityConfig extends
|
||||
AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/other").setHandshakeHandler(testHandshakeHandler())
|
||||
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
|
||||
registry.addEndpoint("/chat").setHandshakeHandler(testHandshakeHandler())
|
||||
.withSockJS().setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages.simpDestMatchers("/permitAll/**").permitAll().anyMessage().denyAll();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyController myController() {
|
||||
return new MyController();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestHandshakeHandler testHandshakeHandler() {
|
||||
return new TestHandshakeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class NoInboundSecurityConfig extends
|
||||
AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/other").withSockJS()
|
||||
.setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
|
||||
registry.addEndpoint("/chat").withSockJS()
|
||||
.setInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configureMessageBroker(MessageBrokerRegistry registry) {
|
||||
registry.enableSimpleBroker("/queue/", "/topic/");
|
||||
registry.setApplicationDestinationPrefixes("/permitAll", "/denyAll");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyController myController() {
|
||||
return new MyController();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class CsrfDisabledSockJsSecurityConfig extends SockJsSecurityConfig {
|
||||
|
||||
@Override
|
||||
protected boolean sameOriginDisabled() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
@EnableWebSocketMessageBroker
|
||||
@Import(SyncExecutorConfig.class)
|
||||
static class WebSocketSecurityConfig extends
|
||||
AbstractSecurityWebSocketMessageBrokerConfigurer {
|
||||
|
||||
public void registerStompEndpoints(StompEndpointRegistry registry) {
|
||||
registry.addEndpoint("/websocket")
|
||||
.setHandshakeHandler(testHandshakeHandler())
|
||||
.addInterceptors(new HttpSessionHandshakeInterceptor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
|
||||
messages.simpDestMatchers("/permitAll/**").permitAll().anyMessage().denyAll();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public TestHandshakeHandler testHandshakeHandler() {
|
||||
return new TestHandshakeHandler();
|
||||
}
|
||||
}
|
||||
|
||||
@Configuration
|
||||
static class SyncExecutorConfig {
|
||||
@Bean
|
||||
public static SyncExecutorSubscribableChannelPostProcessor postProcessor() {
|
||||
return new SyncExecutorSubscribableChannelPostProcessor();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -24,17 +24,19 @@ import org.springframework.messaging.support.ExecutorSubscribableChannel;
|
||||
*/
|
||||
public class SyncExecutorSubscribableChannelPostProcessor implements BeanPostProcessor {
|
||||
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
if(bean instanceof ExecutorSubscribableChannel) {
|
||||
ExecutorSubscribableChannel original = (ExecutorSubscribableChannel) bean;
|
||||
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel();
|
||||
channel.setInterceptors(original.getInterceptors());
|
||||
return channel;
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (bean instanceof ExecutorSubscribableChannel) {
|
||||
ExecutorSubscribableChannel original = (ExecutorSubscribableChannel) bean;
|
||||
ExecutorSubscribableChannel channel = new ExecutorSubscribableChannel();
|
||||
channel.setInterceptors(original.getInterceptors());
|
||||
return channel;
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,61 +21,63 @@ import org.springframework.security.util.FieldUtils;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class AuthenticationManagerBeanDefinitionParserTests {
|
||||
private static final String CONTEXT =
|
||||
"<authentication-manager id='am'>" +
|
||||
" <authentication-provider>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>" +
|
||||
"</authentication-manager>";
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private static final String CONTEXT = "<authentication-manager id='am'>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_A,ROLE_B' />"
|
||||
+ " </user-service>" + " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@Test
|
||||
// SEC-1225
|
||||
public void providersAreRegisteredAsTopLevelBeans() throws Exception {
|
||||
setContext(CONTEXT);
|
||||
assertEquals(1, appContext.getBeansOfType(AuthenticationProvider.class).size());
|
||||
}
|
||||
@Test
|
||||
// SEC-1225
|
||||
public void providersAreRegisteredAsTopLevelBeans() throws Exception {
|
||||
setContext(CONTEXT);
|
||||
assertEquals(1, appContext.getBeansOfType(AuthenticationProvider.class).size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void eventsArePublishedByDefault() throws Exception {
|
||||
setContext(CONTEXT);
|
||||
AuthListener listener = new AuthListener();
|
||||
appContext.addApplicationListener(listener);
|
||||
@Test
|
||||
public void eventsArePublishedByDefault() throws Exception {
|
||||
setContext(CONTEXT);
|
||||
AuthListener listener = new AuthListener();
|
||||
appContext.addApplicationListener(listener);
|
||||
|
||||
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||
Object eventPublisher = FieldUtils.getFieldValue(pm, "eventPublisher");
|
||||
assertNotNull(eventPublisher);
|
||||
assertTrue(eventPublisher instanceof DefaultAuthenticationEventPublisher);
|
||||
ProviderManager pm = (ProviderManager) appContext
|
||||
.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||
Object eventPublisher = FieldUtils.getFieldValue(pm, "eventPublisher");
|
||||
assertNotNull(eventPublisher);
|
||||
assertTrue(eventPublisher instanceof DefaultAuthenticationEventPublisher);
|
||||
|
||||
pm.authenticate(new UsernamePasswordAuthenticationToken("bob", "bobspassword"));
|
||||
assertEquals(1, listener.events.size());
|
||||
}
|
||||
pm.authenticate(new UsernamePasswordAuthenticationToken("bob", "bobspassword"));
|
||||
assertEquals(1, listener.events.size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void credentialsAreClearedByDefault() throws Exception {
|
||||
setContext(CONTEXT);
|
||||
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||
assertTrue(pm.isEraseCredentialsAfterAuthentication());
|
||||
}
|
||||
@Test
|
||||
public void credentialsAreClearedByDefault() throws Exception {
|
||||
setContext(CONTEXT);
|
||||
ProviderManager pm = (ProviderManager) appContext
|
||||
.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||
assertTrue(pm.isEraseCredentialsAfterAuthentication());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void clearCredentialsPropertyIsRespected() throws Exception {
|
||||
setContext("<authentication-manager erase-credentials='false'/>");
|
||||
ProviderManager pm = (ProviderManager) appContext.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||
assertFalse(pm.isEraseCredentialsAfterAuthentication());
|
||||
}
|
||||
@Test
|
||||
public void clearCredentialsPropertyIsRespected() throws Exception {
|
||||
setContext("<authentication-manager erase-credentials='false'/>");
|
||||
ProviderManager pm = (ProviderManager) appContext
|
||||
.getBeansOfType(ProviderManager.class).values().toArray()[0];
|
||||
assertFalse(pm.isEraseCredentialsAfterAuthentication());
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
private static class AuthListener implements ApplicationListener<AbstractAuthenticationEvent> {
|
||||
List<AbstractAuthenticationEvent> events = new ArrayList<AbstractAuthenticationEvent>();
|
||||
private static class AuthListener implements
|
||||
ApplicationListener<AbstractAuthenticationEvent> {
|
||||
List<AbstractAuthenticationEvent> events = new ArrayList<AbstractAuthenticationEvent>();
|
||||
|
||||
public void onApplicationEvent(AbstractAuthenticationEvent event) {
|
||||
events.add(event);
|
||||
}
|
||||
}
|
||||
public void onApplicationEvent(AbstractAuthenticationEvent event) {
|
||||
events.add(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,166 +24,167 @@ import java.util.List;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class AuthenticationProviderBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob", "bobspassword");
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken(
|
||||
"bob", "bobspassword");
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worksWithEmbeddedUserService() {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
@Test
|
||||
public void worksWithEmbeddedUserService() {
|
||||
setContext(" <authentication-provider>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void externalUserServiceRefWorks() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
" <authentication-manager>" +
|
||||
" <authentication-provider user-service-ref='myUserService' />" +
|
||||
" </authentication-manager>" +
|
||||
" <user-service id='myUserService'>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_A' />" +
|
||||
" </user-service>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
@Test
|
||||
public void externalUserServiceRefWorks() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
" <authentication-manager>"
|
||||
+ " <authentication-provider user-service-ref='myUserService' />"
|
||||
+ " </authentication-manager>"
|
||||
+ " <user-service id='myUserService'>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_A' />"
|
||||
+ " </user-service>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void providerWithBCryptPasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='bcrypt'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
@Test
|
||||
public void providerWithBCryptPasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>"
|
||||
+ " <password-encoder hash='bcrypt'/>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>");
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void bCryptAndSaltSourceRaisesException() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext("" +
|
||||
" <authentication-manager>" +
|
||||
" <authentication-provider>" +
|
||||
" <password-encoder hash='bcrypt'>" +
|
||||
" <salt-source ref='saltSource'/>" +
|
||||
" </password-encoder>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>" +
|
||||
" </authentication-manager>" +
|
||||
" <b:bean id='saltSource' class='" + ReflectionSaltSource.class.getName() +"'>" +
|
||||
" <b:property name='userPropertyToUse' value='username'/>" +
|
||||
" </b:bean>");
|
||||
}
|
||||
@Test
|
||||
public void providerWithMd5PasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='md5'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='12b141f35d58b8b3a46eea65e6ac179e' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
public void bCryptAndSaltSourceRaisesException() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
""
|
||||
+ " <authentication-manager>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <password-encoder hash='bcrypt'>"
|
||||
+ " <salt-source ref='saltSource'/>"
|
||||
+ " </password-encoder>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='$2a$05$dRmjl1T05J7rvCPD2NgsHesCEJHww3pdmesUhjM3PD4m/gaEYyx/G' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>"
|
||||
+ " </authentication-manager>"
|
||||
+ " <b:bean id='saltSource' class='"
|
||||
+ ReflectionSaltSource.class.getName() + "'>"
|
||||
+ " <b:property name='userPropertyToUse' value='username'/>"
|
||||
+ " </b:bean>");
|
||||
}
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
@Test
|
||||
public void providerWithMd5PasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>"
|
||||
+ " <password-encoder hash='md5'/>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='12b141f35d58b8b3a46eea65e6ac179e' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>");
|
||||
|
||||
@Test
|
||||
public void providerWithShaPasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='{sha}'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='{SSHA}PpuEwfdj7M1rs0C2W4ssSM2XEN/Y6S5U' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
@Test
|
||||
public void providerWithShaPasswordEncoderWorks() throws Exception {
|
||||
setContext(" <authentication-provider>"
|
||||
+ " <password-encoder hash='{sha}'/>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='{SSHA}PpuEwfdj7M1rs0C2W4ssSM2XEN/Y6S5U' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>");
|
||||
|
||||
@Test
|
||||
public void providerWithSha256PasswordEncoderIsSupported() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='sha-256'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='notused' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
ShaPasswordEncoder encoder = (ShaPasswordEncoder) FieldUtils.getFieldValue(getProvider(), "passwordEncoder");
|
||||
assertEquals("SHA-256", encoder.getAlgorithm());
|
||||
}
|
||||
@Test
|
||||
public void providerWithSha256PasswordEncoderIsSupported() throws Exception {
|
||||
setContext(" <authentication-provider>"
|
||||
+ " <password-encoder hash='sha-256'/>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='notused' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>");
|
||||
|
||||
@Test
|
||||
public void passwordIsBase64EncodedWhenBase64IsEnabled() throws Exception {
|
||||
setContext(" <authentication-provider>" +
|
||||
" <password-encoder hash='md5' base64='true'/>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='ErFB811YuLOkbupl5qwXng==' authorities='ROLE_A' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>");
|
||||
ShaPasswordEncoder encoder = (ShaPasswordEncoder) FieldUtils.getFieldValue(
|
||||
getProvider(), "passwordEncoder");
|
||||
assertEquals("SHA-256", encoder.getAlgorithm());
|
||||
}
|
||||
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
@Test
|
||||
public void passwordIsBase64EncodedWhenBase64IsEnabled() throws Exception {
|
||||
setContext(" <authentication-provider>"
|
||||
+ " <password-encoder hash='md5' base64='true'/>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='ErFB811YuLOkbupl5qwXng==' authorities='ROLE_A' />"
|
||||
+ " </user-service>" + " </authentication-provider>");
|
||||
|
||||
@Test
|
||||
public void externalUserServicePasswordEncoderAndSaltSourceWork() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
" <authentication-manager>" +
|
||||
" <authentication-provider user-service-ref='customUserService'>" +
|
||||
" <password-encoder ref='customPasswordEncoder'>" +
|
||||
" <salt-source ref='saltSource'/>" +
|
||||
" </password-encoder>" +
|
||||
" </authentication-provider>" +
|
||||
" </authentication-manager>" +
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
" <b:bean id='customPasswordEncoder' " +
|
||||
"class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>" +
|
||||
" <b:bean id='saltSource' " +
|
||||
" class='" + ReflectionSaltSource.class.getName() +"'>" +
|
||||
" <b:property name='userPropertyToUse' value='username'/>" +
|
||||
" </b:bean>" +
|
||||
" <b:bean id='customUserService' " +
|
||||
" class='org.springframework.security.provisioning.InMemoryUserDetailsManager'>" +
|
||||
" <b:constructor-arg>" +
|
||||
" <b:props>" +
|
||||
" <b:prop key='bob'>f117f0862384e9497ff4f470e3522606,ROLE_A</b:prop>" +
|
||||
" </b:props>" +
|
||||
" </b:constructor-arg>" +
|
||||
" </b:bean>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
@Test
|
||||
public void externalUserServicePasswordEncoderAndSaltSourceWork() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
" <authentication-manager>"
|
||||
+ " <authentication-provider user-service-ref='customUserService'>"
|
||||
+ " <password-encoder ref='customPasswordEncoder'>"
|
||||
+ " <salt-source ref='saltSource'/>"
|
||||
+ " </password-encoder>"
|
||||
+ " </authentication-provider>"
|
||||
+ " </authentication-manager>"
|
||||
+
|
||||
|
||||
// SEC-1466
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void exernalProviderDoesNotSupportChildElements() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
" <authentication-manager>" +
|
||||
" <authentication-provider ref='aProvider'> " +
|
||||
" <password-encoder ref='customPasswordEncoder'/>" +
|
||||
" </authentication-provider>" +
|
||||
" </authentication-manager>" +
|
||||
" <b:bean id='aProvider' class='org.springframework.security.authentication.TestingAuthenticationProvider'/>" +
|
||||
" <b:bean id='customPasswordEncoder' " +
|
||||
" class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>");
|
||||
}
|
||||
" <b:bean id='customPasswordEncoder' "
|
||||
+ "class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>"
|
||||
+ " <b:bean id='saltSource' "
|
||||
+ " class='"
|
||||
+ ReflectionSaltSource.class.getName()
|
||||
+ "'>"
|
||||
+ " <b:property name='userPropertyToUse' value='username'/>"
|
||||
+ " </b:bean>"
|
||||
+ " <b:bean id='customUserService' "
|
||||
+ " class='org.springframework.security.provisioning.InMemoryUserDetailsManager'>"
|
||||
+ " <b:constructor-arg>"
|
||||
+ " <b:props>"
|
||||
+ " <b:prop key='bob'>f117f0862384e9497ff4f470e3522606,ROLE_A</b:prop>"
|
||||
+ " </b:props>" + " </b:constructor-arg>"
|
||||
+ " </b:bean>");
|
||||
getProvider().authenticate(bob);
|
||||
}
|
||||
|
||||
private AuthenticationProvider getProvider() {
|
||||
List<AuthenticationProvider> providers =
|
||||
((ProviderManager)appContext.getBean(BeanIds.AUTHENTICATION_MANAGER)).getProviders();
|
||||
// SEC-1466
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
public void exernalProviderDoesNotSupportChildElements() throws Exception {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
" <authentication-manager>"
|
||||
+ " <authentication-provider ref='aProvider'> "
|
||||
+ " <password-encoder ref='customPasswordEncoder'/>"
|
||||
+ " </authentication-provider>"
|
||||
+ " </authentication-manager>"
|
||||
+ " <b:bean id='aProvider' class='org.springframework.security.authentication.TestingAuthenticationProvider'/>"
|
||||
+ " <b:bean id='customPasswordEncoder' "
|
||||
+ " class='org.springframework.security.authentication.encoding.Md5PasswordEncoder'/>");
|
||||
}
|
||||
|
||||
return providers.get(0);
|
||||
}
|
||||
private AuthenticationProvider getProvider() {
|
||||
List<AuthenticationProvider> providers = ((ProviderManager) appContext
|
||||
.getBean(BeanIds.AUTHENTICATION_MANAGER)).getProviders();
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext("<authentication-manager>" + context + "</authentication-manager>");
|
||||
}
|
||||
return providers.get(0);
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext("<authentication-manager>"
|
||||
+ context + "</authentication-manager>");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,116 +25,127 @@ import org.w3c.dom.Element;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class JdbcUserServiceBeanDefinitionParserTests {
|
||||
private static String USER_CACHE_XML = "<b:bean id='userCache' class='org.springframework.security.authentication.dao.MockUserCache'/>";
|
||||
private static String USER_CACHE_XML = "<b:bean id='userCache' class='org.springframework.security.authentication.dao.MockUserCache'/>";
|
||||
|
||||
private static String DATA_SOURCE =
|
||||
" <b:bean id='populator' class='org.springframework.security.config.DataSourcePopulator'>" +
|
||||
" <b:property name='dataSource' ref='dataSource'/>" +
|
||||
" </b:bean>" +
|
||||
private static String DATA_SOURCE = " <b:bean id='populator' class='org.springframework.security.config.DataSourcePopulator'>"
|
||||
+ " <b:property name='dataSource' ref='dataSource'/>"
|
||||
+ " </b:bean>"
|
||||
+
|
||||
|
||||
" <b:bean id='dataSource' class='org.springframework.security.TestDataSource'>" +
|
||||
" <b:constructor-arg value='jdbcnamespaces'/>" +
|
||||
" </b:bean>";
|
||||
" <b:bean id='dataSource' class='org.springframework.security.TestDataSource'>"
|
||||
+ " <b:constructor-arg value='jdbcnamespaces'/>" + " </b:bean>";
|
||||
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanNameIsCorrect() throws Exception {
|
||||
assertEquals(JdbcUserDetailsManager.class.getName(), new JdbcUserServiceBeanDefinitionParser().getBeanClassName(mock(Element.class)));
|
||||
}
|
||||
@Test
|
||||
public void beanNameIsCorrect() throws Exception {
|
||||
assertEquals(JdbcUserDetailsManager.class.getName(),
|
||||
new JdbcUserServiceBeanDefinitionParser()
|
||||
.getBeanClassName(mock(Element.class)));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void validUsernameIsFound() {
|
||||
setContext("<jdbc-user-service data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean(BeanIds.USER_DETAILS_SERVICE);
|
||||
assertNotNull(mgr.loadUserByUsername("rod"));
|
||||
}
|
||||
@Test
|
||||
public void validUsernameIsFound() {
|
||||
setContext("<jdbc-user-service data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext
|
||||
.getBean(BeanIds.USER_DETAILS_SERVICE);
|
||||
assertNotNull(mgr.loadUserByUsername("rod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanIdIsParsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
assertTrue(appContext.getBean("myUserService") instanceof JdbcUserDetailsManager);
|
||||
}
|
||||
@Test
|
||||
public void beanIdIsParsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' data-source-ref='dataSource'/>"
|
||||
+ DATA_SOURCE);
|
||||
assertTrue(appContext.getBean("myUserService") instanceof JdbcUserDetailsManager);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
|
||||
String userQuery = "select username, password, true from users where username = ?";
|
||||
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
|
||||
setContext("<jdbc-user-service id='myUserService' " +
|
||||
"data-source-ref='dataSource' " +
|
||||
"users-by-username-query='"+ userQuery +"' " +
|
||||
"authorities-by-username-query='" + authoritiesQuery + "'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertEquals(userQuery, FieldUtils.getFieldValue(mgr, "usersByUsernameQuery"));
|
||||
assertEquals(authoritiesQuery, FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery"));
|
||||
assertTrue(mgr.loadUserByUsername("rod") != null);
|
||||
}
|
||||
@Test
|
||||
public void usernameAndAuthorityQueriesAreParsedCorrectly() throws Exception {
|
||||
String userQuery = "select username, password, true from users where username = ?";
|
||||
String authoritiesQuery = "select username, authority from authorities where username = ? and 1 = 1";
|
||||
setContext("<jdbc-user-service id='myUserService' "
|
||||
+ "data-source-ref='dataSource' " + "users-by-username-query='"
|
||||
+ userQuery + "' " + "authorities-by-username-query='" + authoritiesQuery
|
||||
+ "'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext
|
||||
.getBean("myUserService");
|
||||
assertEquals(userQuery, FieldUtils.getFieldValue(mgr, "usersByUsernameQuery"));
|
||||
assertEquals(authoritiesQuery,
|
||||
FieldUtils.getFieldValue(mgr, "authoritiesByUsernameQuery"));
|
||||
assertTrue(mgr.loadUserByUsername("rod") != null);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void groupQueryIsParsedCorrectly() throws Exception {
|
||||
setContext("<jdbc-user-service id='myUserService' " +
|
||||
"data-source-ref='dataSource' " +
|
||||
"group-authorities-by-username-query='blah blah'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
assertEquals("blah blah", FieldUtils.getFieldValue(mgr, "groupAuthoritiesByUsernameQuery"));
|
||||
assertTrue((Boolean)FieldUtils.getFieldValue(mgr, "enableGroups"));
|
||||
}
|
||||
@Test
|
||||
public void groupQueryIsParsedCorrectly() throws Exception {
|
||||
setContext("<jdbc-user-service id='myUserService' "
|
||||
+ "data-source-ref='dataSource' "
|
||||
+ "group-authorities-by-username-query='blah blah'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext
|
||||
.getBean("myUserService");
|
||||
assertEquals("blah blah",
|
||||
FieldUtils.getFieldValue(mgr, "groupAuthoritiesByUsernameQuery"));
|
||||
assertTrue((Boolean) FieldUtils.getFieldValue(mgr, "enableGroups"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheRefIsparsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' cache-ref='userCache' data-source-ref='dataSource'/>"
|
||||
+ DATA_SOURCE +USER_CACHE_XML);
|
||||
CachingUserDetailsService cachingUserService =
|
||||
(CachingUserDetailsService) appContext.getBean("myUserService" + AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX);
|
||||
assertSame(cachingUserService.getUserCache(), appContext.getBean("userCache"));
|
||||
assertNotNull(cachingUserService.loadUserByUsername("rod"));
|
||||
assertNotNull(cachingUserService.loadUserByUsername("rod"));
|
||||
}
|
||||
@Test
|
||||
public void cacheRefIsparsedCorrectly() {
|
||||
setContext("<jdbc-user-service id='myUserService' cache-ref='userCache' data-source-ref='dataSource'/>"
|
||||
+ DATA_SOURCE + USER_CACHE_XML);
|
||||
CachingUserDetailsService cachingUserService = (CachingUserDetailsService) appContext
|
||||
.getBean("myUserService"
|
||||
+ AbstractUserDetailsServiceBeanDefinitionParser.CACHING_SUFFIX);
|
||||
assertSame(cachingUserService.getUserCache(), appContext.getBean("userCache"));
|
||||
assertNotNull(cachingUserService.loadUserByUsername("rod"));
|
||||
assertNotNull(cachingUserService.loadUserByUsername("rod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void isSupportedByAuthenticationProviderElement() {
|
||||
setContext(
|
||||
"<authentication-manager>" +
|
||||
" <authentication-provider>" +
|
||||
" <jdbc-user-service data-source-ref='dataSource'/>" +
|
||||
" </authentication-provider>" +
|
||||
"</authentication-manager>" + DATA_SOURCE);
|
||||
AuthenticationManager mgr = (AuthenticationManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
|
||||
}
|
||||
@Test
|
||||
public void isSupportedByAuthenticationProviderElement() {
|
||||
setContext("<authentication-manager>" + " <authentication-provider>"
|
||||
+ " <jdbc-user-service data-source-ref='dataSource'/>"
|
||||
+ " </authentication-provider>" + "</authentication-manager>"
|
||||
+ DATA_SOURCE);
|
||||
AuthenticationManager mgr = (AuthenticationManager) appContext
|
||||
.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
mgr.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void cacheIsInjectedIntoAuthenticationProvider() {
|
||||
setContext(
|
||||
"<authentication-manager>" +
|
||||
" <authentication-provider>" +
|
||||
" <jdbc-user-service cache-ref='userCache' data-source-ref='dataSource'/>" +
|
||||
" </authentication-provider>" +
|
||||
"</authentication-manager>" + DATA_SOURCE + USER_CACHE_XML);
|
||||
ProviderManager mgr = (ProviderManager) appContext.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr.getProviders().get(0);
|
||||
assertSame(provider.getUserCache(), appContext.getBean("userCache"));
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("rod","koala"));
|
||||
assertNotNull("Cache should contain user after authentication", provider.getUserCache().getUserFromCache("rod"));
|
||||
}
|
||||
@Test
|
||||
public void cacheIsInjectedIntoAuthenticationProvider() {
|
||||
setContext("<authentication-manager>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <jdbc-user-service cache-ref='userCache' data-source-ref='dataSource'/>"
|
||||
+ " </authentication-provider>" + "</authentication-manager>"
|
||||
+ DATA_SOURCE + USER_CACHE_XML);
|
||||
ProviderManager mgr = (ProviderManager) appContext
|
||||
.getBean(BeanIds.AUTHENTICATION_MANAGER);
|
||||
DaoAuthenticationProvider provider = (DaoAuthenticationProvider) mgr
|
||||
.getProviders().get(0);
|
||||
assertSame(provider.getUserCache(), appContext.getBean("userCache"));
|
||||
provider.authenticate(new UsernamePasswordAuthenticationToken("rod", "koala"));
|
||||
assertNotNull("Cache should contain user after authentication", provider
|
||||
.getUserCache().getUserFromCache("rod"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void rolePrefixIsUsedWhenSet() {
|
||||
setContext("<jdbc-user-service id='myUserService' role-prefix='PREFIX_' data-source-ref='dataSource'/>" + DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext.getBean("myUserService");
|
||||
UserDetails rod = mgr.loadUserByUsername("rod");
|
||||
assertTrue(AuthorityUtils.authorityListToSet(rod.getAuthorities()).contains("PREFIX_ROLE_SUPERVISOR"));
|
||||
}
|
||||
@Test
|
||||
public void rolePrefixIsUsedWhenSet() {
|
||||
setContext("<jdbc-user-service id='myUserService' role-prefix='PREFIX_' data-source-ref='dataSource'/>"
|
||||
+ DATA_SOURCE);
|
||||
JdbcUserDetailsManager mgr = (JdbcUserDetailsManager) appContext
|
||||
.getBean("myUserService");
|
||||
UserDetails rod = mgr.loadUserByUsername("rod");
|
||||
assertTrue(AuthorityUtils.authorityListToSet(rod.getAuthorities()).contains(
|
||||
"PREFIX_ROLE_SUPERVISOR"));
|
||||
}
|
||||
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,115 +15,117 @@ import org.junit.After;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class UserServiceBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userServiceWithValidPropertiesFileWorksSuccessfully() {
|
||||
setContext(
|
||||
"<user-service id='service' " +
|
||||
"properties='classpath:org/springframework/security/config/users.properties'/>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
userService.loadUserByUsername("bob");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
@Test
|
||||
public void userServiceWithValidPropertiesFileWorksSuccessfully() {
|
||||
setContext("<user-service id='service' "
|
||||
+ "properties='classpath:org/springframework/security/config/users.properties'/>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
userService.loadUserByUsername("bob");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void userServiceWithEmbeddedUsersWorksSuccessfully() {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
@Test
|
||||
public void userServiceWithEmbeddedUsersWorksSuccessfully() {
|
||||
setContext("<user-service id='service'>"
|
||||
+ " <user name='joe' password='joespassword' authorities='ROLE_A'/>"
|
||||
+ "</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
userService.loadUserByUsername("joe");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void namePasswordAndAuthoritiesSupportPlaceholders() {
|
||||
System.setProperty("principal.name", "joe");
|
||||
System.setProperty("principal.pass", "joespassword");
|
||||
System.setProperty("principal.authorities", "ROLE_A,ROLE_B");
|
||||
setContext(
|
||||
"<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||
"<user-service id='service'>" +
|
||||
" <user name='${principal.name}' password='${principal.pass}' authorities='${principal.authorities}'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertEquals("joespassword", joe.getPassword());
|
||||
assertEquals(2, joe.getAuthorities().size());
|
||||
}
|
||||
@Test
|
||||
public void namePasswordAndAuthoritiesSupportPlaceholders() {
|
||||
System.setProperty("principal.name", "joe");
|
||||
System.setProperty("principal.pass", "joespassword");
|
||||
System.setProperty("principal.authorities", "ROLE_A,ROLE_B");
|
||||
setContext("<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>"
|
||||
+ "<user-service id='service'>"
|
||||
+ " <user name='${principal.name}' password='${principal.pass}' authorities='${principal.authorities}'/>"
|
||||
+ "</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertEquals("joespassword", joe.getPassword());
|
||||
assertEquals(2, joe.getAuthorities().size());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void embeddedUsersWithNoPasswordIsGivenGeneratedValue() {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <user name='joe' authorities='ROLE_A'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertTrue(joe.getPassword().length() > 0);
|
||||
Long.parseLong(joe.getPassword());
|
||||
}
|
||||
@Test
|
||||
public void embeddedUsersWithNoPasswordIsGivenGeneratedValue() {
|
||||
setContext("<user-service id='service'>"
|
||||
+ " <user name='joe' authorities='ROLE_A'/>" + "</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertTrue(joe.getPassword().length() > 0);
|
||||
Long.parseLong(joe.getPassword());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void worksWithOpenIDUrlsAsNames() {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <user name='http://joe.myopenid.com/' authorities='ROLE_A'/>" +
|
||||
" <user name='https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9' authorities='ROLE_A'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
assertEquals("http://joe.myopenid.com/", userService.loadUserByUsername("http://joe.myopenid.com/").getUsername());
|
||||
assertEquals("https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9",
|
||||
userService.loadUserByUsername("https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9").getUsername());
|
||||
}
|
||||
@Test
|
||||
public void worksWithOpenIDUrlsAsNames() {
|
||||
setContext("<user-service id='service'>"
|
||||
+ " <user name='http://joe.myopenid.com/' authorities='ROLE_A'/>"
|
||||
+ " <user name='https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9' authorities='ROLE_A'/>"
|
||||
+ "</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
assertEquals("http://joe.myopenid.com/",
|
||||
userService.loadUserByUsername("http://joe.myopenid.com/").getUsername());
|
||||
assertEquals(
|
||||
"https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9",
|
||||
userService.loadUserByUsername(
|
||||
"https://www.google.com/accounts/o8/id?id=MPtOaenBIk5yzW9n7n9")
|
||||
.getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void disabledAndEmbeddedFlagsAreSupported() {
|
||||
setContext(
|
||||
"<user-service id='service'>" +
|
||||
" <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>" +
|
||||
" <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertFalse(joe.isAccountNonLocked());
|
||||
// Check case-sensitive lookup SEC-1432
|
||||
UserDetails bob = userService.loadUserByUsername("Bob");
|
||||
assertFalse(bob.isEnabled());
|
||||
}
|
||||
@Test
|
||||
public void disabledAndEmbeddedFlagsAreSupported() {
|
||||
setContext("<user-service id='service'>"
|
||||
+ " <user name='joe' password='joespassword' authorities='ROLE_A' locked='true'/>"
|
||||
+ " <user name='Bob' password='bobspassword' authorities='ROLE_A' disabled='true'/>"
|
||||
+ "</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
UserDetails joe = userService.loadUserByUsername("joe");
|
||||
assertFalse(joe.isAccountNonLocked());
|
||||
// Check case-sensitive lookup SEC-1432
|
||||
UserDetails bob = userService.loadUserByUsername("Bob");
|
||||
assertFalse(bob.isEnabled());
|
||||
}
|
||||
|
||||
@Test(expected=FatalBeanException.class)
|
||||
public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
|
||||
setContext(
|
||||
"<user-service id='service' properties='doesntmatter.props'>" +
|
||||
" <user name='joe' password='joespassword' authorities='ROLE_A'/>" +
|
||||
"</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext.getBean("service");
|
||||
userService.loadUserByUsername("Joe");
|
||||
}
|
||||
@Test(expected = FatalBeanException.class)
|
||||
public void userWithBothPropertiesAndEmbeddedUsersThrowsException() {
|
||||
setContext("<user-service id='service' properties='doesntmatter.props'>"
|
||||
+ " <user name='joe' password='joespassword' authorities='ROLE_A'/>"
|
||||
+ "</user-service>");
|
||||
UserDetailsService userService = (UserDetailsService) appContext
|
||||
.getBean("service");
|
||||
userService.loadUserByUsername("Joe");
|
||||
}
|
||||
|
||||
@Test(expected= FatalBeanException.class)
|
||||
public void multipleTopLevelUseWithoutIdThrowsException() {
|
||||
setContext(
|
||||
"<user-service properties='classpath:org/springframework/security/config/users.properties'/>" +
|
||||
"<user-service properties='classpath:org/springframework/security/config/users.properties'/>");
|
||||
@Test(expected = FatalBeanException.class)
|
||||
public void multipleTopLevelUseWithoutIdThrowsException() {
|
||||
setContext("<user-service properties='classpath:org/springframework/security/config/users.properties'/>"
|
||||
+ "<user-service properties='classpath:org/springframework/security/config/users.properties'/>");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected= FatalBeanException.class)
|
||||
public void userServiceWithMissingPropertiesFileThrowsException() {
|
||||
setContext("<user-service id='service' properties='classpath:doesntexist.properties'/>");
|
||||
}
|
||||
@Test(expected = FatalBeanException.class)
|
||||
public void userServiceWithMissingPropertiesFileThrowsException() {
|
||||
setContext("<user-service id='service' properties='classpath:doesntexist.properties'/>");
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,49 +46,56 @@ import org.springframework.security.web.util.matcher.AnyRequestMatcher;
|
||||
*/
|
||||
@RunWith(MockitoJUnitRunner.class)
|
||||
public class DefaultFilterChainValidatorTests {
|
||||
private DefaultFilterChainValidator validator;
|
||||
private FilterChainProxy fcp;
|
||||
@Mock
|
||||
private Log logger;
|
||||
@Mock
|
||||
private DefaultFilterInvocationSecurityMetadataSource metadataSource;
|
||||
@Mock
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
private DefaultFilterChainValidator validator;
|
||||
private FilterChainProxy fcp;
|
||||
@Mock
|
||||
private Log logger;
|
||||
@Mock
|
||||
private DefaultFilterInvocationSecurityMetadataSource metadataSource;
|
||||
@Mock
|
||||
private AccessDecisionManager accessDecisionManager;
|
||||
|
||||
private FilterSecurityInterceptor fsi;
|
||||
private FilterSecurityInterceptor fsi;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
AnonymousAuthenticationFilter aaf = new AnonymousAuthenticationFilter("anonymous");
|
||||
fsi = new FilterSecurityInterceptor();
|
||||
fsi.setAccessDecisionManager(accessDecisionManager);
|
||||
fsi.setSecurityMetadataSource(metadataSource);
|
||||
AuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint("/login");
|
||||
ExceptionTranslationFilter etf = new ExceptionTranslationFilter(authenticationEntryPoint);
|
||||
DefaultSecurityFilterChain securityChain = new DefaultSecurityFilterChain(AnyRequestMatcher.INSTANCE, aaf, etf, fsi);
|
||||
fcp = new FilterChainProxy(securityChain);
|
||||
validator = new DefaultFilterChainValidator();
|
||||
Whitebox.setInternalState(validator, "logger", logger);
|
||||
}
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
AnonymousAuthenticationFilter aaf = new AnonymousAuthenticationFilter("anonymous");
|
||||
fsi = new FilterSecurityInterceptor();
|
||||
fsi.setAccessDecisionManager(accessDecisionManager);
|
||||
fsi.setSecurityMetadataSource(metadataSource);
|
||||
AuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint(
|
||||
"/login");
|
||||
ExceptionTranslationFilter etf = new ExceptionTranslationFilter(
|
||||
authenticationEntryPoint);
|
||||
DefaultSecurityFilterChain securityChain = new DefaultSecurityFilterChain(
|
||||
AnyRequestMatcher.INSTANCE, aaf, etf, fsi);
|
||||
fcp = new FilterChainProxy(securityChain);
|
||||
validator = new DefaultFilterChainValidator();
|
||||
Whitebox.setInternalState(validator, "logger", logger);
|
||||
}
|
||||
|
||||
// SEC-1878
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void validateCheckLoginPageIsntProtectedThrowsIllegalArgumentException() {
|
||||
IllegalArgumentException toBeThrown = new IllegalArgumentException("failed to eval expression");
|
||||
doThrow(toBeThrown).when(accessDecisionManager).decide(any(Authentication.class), anyObject(), any(Collection.class));
|
||||
validator.validate(fcp);
|
||||
verify(logger).info("Unable to check access to the login page to determine if anonymous access is allowed. This might be an error, but can happen under normal circumstances.", toBeThrown);
|
||||
}
|
||||
// SEC-1878
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void validateCheckLoginPageIsntProtectedThrowsIllegalArgumentException() {
|
||||
IllegalArgumentException toBeThrown = new IllegalArgumentException(
|
||||
"failed to eval expression");
|
||||
doThrow(toBeThrown).when(accessDecisionManager).decide(any(Authentication.class),
|
||||
anyObject(), any(Collection.class));
|
||||
validator.validate(fcp);
|
||||
verify(logger)
|
||||
.info("Unable to check access to the login page to determine if anonymous access is allowed. This might be an error, but can happen under normal circumstances.",
|
||||
toBeThrown);
|
||||
}
|
||||
|
||||
// SEC-1957
|
||||
@Test
|
||||
public void validateCustomMetadataSource() {
|
||||
FilterInvocationSecurityMetadataSource customMetaDataSource = mock(FilterInvocationSecurityMetadataSource.class);
|
||||
fsi.setSecurityMetadataSource(customMetaDataSource);
|
||||
// SEC-1957
|
||||
@Test
|
||||
public void validateCustomMetadataSource() {
|
||||
FilterInvocationSecurityMetadataSource customMetaDataSource = mock(FilterInvocationSecurityMetadataSource.class);
|
||||
fsi.setSecurityMetadataSource(customMetaDataSource);
|
||||
|
||||
validator.validate(fcp);
|
||||
validator.validate(fcp);
|
||||
|
||||
verify(customMetaDataSource).getAttributes(any());
|
||||
}
|
||||
verify(customMetaDataSource).getAttributes(any());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -26,87 +26,89 @@ import org.springframework.security.web.access.intercept.DefaultFilterInvocation
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class FilterSecurityMetadataSourceBeanDefinitionParserTests {
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsingMinimalConfigurationIsSuccessful() {
|
||||
setContext("<filter-security-metadata-source id='fids' use-expressions='false'>"
|
||||
+ " <intercept-url pattern='/**' access='ROLE_A'/>"
|
||||
+ "</filter-security-metadata-source>");
|
||||
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext
|
||||
.getBean("fids");
|
||||
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation(
|
||||
"/anything", "GET"));
|
||||
assertNotNull(cad);
|
||||
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsingMinimalConfigurationIsSuccessful() {
|
||||
setContext(
|
||||
"<filter-security-metadata-source id='fids' use-expressions='false'>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_A'/>" +
|
||||
"</filter-security-metadata-source>");
|
||||
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext.getBean("fids");
|
||||
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/anything", "GET"));
|
||||
assertNotNull(cad);
|
||||
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
|
||||
}
|
||||
@Test
|
||||
public void expressionsAreSupported() {
|
||||
setContext("<filter-security-metadata-source id='fids'>"
|
||||
+ " <intercept-url pattern='/**' access=\"hasRole('ROLE_A')\" />"
|
||||
+ "</filter-security-metadata-source>");
|
||||
|
||||
@Test
|
||||
public void expressionsAreSupported() {
|
||||
setContext(
|
||||
"<filter-security-metadata-source id='fids'>" +
|
||||
" <intercept-url pattern='/**' access=\"hasRole('ROLE_A')\" />" +
|
||||
"</filter-security-metadata-source>");
|
||||
ExpressionBasedFilterInvocationSecurityMetadataSource fids = (ExpressionBasedFilterInvocationSecurityMetadataSource) appContext
|
||||
.getBean("fids");
|
||||
ConfigAttribute[] cad = fids.getAttributes(
|
||||
createFilterInvocation("/anything", "GET")).toArray(
|
||||
new ConfigAttribute[0]);
|
||||
assertEquals(1, cad.length);
|
||||
assertEquals("hasRole('ROLE_A')", cad[0].toString());
|
||||
}
|
||||
|
||||
ExpressionBasedFilterInvocationSecurityMetadataSource fids =
|
||||
(ExpressionBasedFilterInvocationSecurityMetadataSource) appContext.getBean("fids");
|
||||
ConfigAttribute[] cad = fids.getAttributes(createFilterInvocation("/anything", "GET")).toArray(new ConfigAttribute[0]);
|
||||
assertEquals(1, cad.length);
|
||||
assertEquals("hasRole('ROLE_A')", cad[0].toString());
|
||||
}
|
||||
// SEC-1201
|
||||
@Test
|
||||
public void interceptUrlsSupportPropertyPlaceholders() {
|
||||
System.setProperty("secure.url", "/secure");
|
||||
System.setProperty("secure.role", "ROLE_A");
|
||||
setContext("<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>"
|
||||
+ "<filter-security-metadata-source id='fids' use-expressions='false'>"
|
||||
+ " <intercept-url pattern='${secure.url}' access='${secure.role}'/>"
|
||||
+ "</filter-security-metadata-source>");
|
||||
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext
|
||||
.getBean("fids");
|
||||
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation(
|
||||
"/secure", "GET"));
|
||||
assertNotNull(cad);
|
||||
assertEquals(1, cad.size());
|
||||
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
|
||||
}
|
||||
|
||||
// SEC-1201
|
||||
@Test
|
||||
public void interceptUrlsSupportPropertyPlaceholders() {
|
||||
System.setProperty("secure.url", "/secure");
|
||||
System.setProperty("secure.role", "ROLE_A");
|
||||
setContext(
|
||||
"<b:bean class='org.springframework.beans.factory.config.PropertyPlaceholderConfigurer'/>" +
|
||||
"<filter-security-metadata-source id='fids' use-expressions='false'>" +
|
||||
" <intercept-url pattern='${secure.url}' access='${secure.role}'/>" +
|
||||
"</filter-security-metadata-source>");
|
||||
DefaultFilterInvocationSecurityMetadataSource fids = (DefaultFilterInvocationSecurityMetadataSource) appContext.getBean("fids");
|
||||
Collection<ConfigAttribute> cad = fids.getAttributes(createFilterInvocation("/secure", "GET"));
|
||||
assertNotNull(cad);
|
||||
assertEquals(1, cad.size());
|
||||
assertTrue(cad.contains(new SecurityConfig("ROLE_A")));
|
||||
}
|
||||
@Test
|
||||
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
|
||||
setContext("<http auto-config='true' use-expressions='false'/>"
|
||||
+ "<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>"
|
||||
+ " <b:property name='securityMetadataSource'>"
|
||||
+ " <filter-security-metadata-source use-expressions='false'>"
|
||||
+ " <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>"
|
||||
+ " <intercept-url pattern='/secure/**' access='ROLE_USER'/>"
|
||||
+ " <intercept-url pattern='/**' access='ROLE_USER'/>"
|
||||
+ " </filter-security-metadata-source>" + " </b:property>"
|
||||
+ " <b:property name='authenticationManager' ref='"
|
||||
+ BeanIds.AUTHENTICATION_MANAGER + "'/>" + "</b:bean>"
|
||||
+ ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void parsingWithinFilterSecurityInterceptorIsSuccessful() {
|
||||
setContext(
|
||||
"<http auto-config='true' use-expressions='false'/>" +
|
||||
"<b:bean id='fsi' class='org.springframework.security.web.access.intercept.FilterSecurityInterceptor' autowire='byType'>" +
|
||||
" <b:property name='securityMetadataSource'>" +
|
||||
" <filter-security-metadata-source use-expressions='false'>" +
|
||||
" <intercept-url pattern='/secure/extreme/**' access='ROLE_SUPERVISOR'/>" +
|
||||
" <intercept-url pattern='/secure/**' access='ROLE_USER'/>" +
|
||||
" <intercept-url pattern='/**' access='ROLE_USER'/>" +
|
||||
" </filter-security-metadata-source>" +
|
||||
" </b:property>" +
|
||||
" <b:property name='authenticationManager' ref='" + BeanIds.AUTHENTICATION_MANAGER +"'/>"+
|
||||
"</b:bean>" + ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
}
|
||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(null);
|
||||
request.setMethod(method);
|
||||
|
||||
private FilterInvocation createFilterInvocation(String path, String method) {
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.setRequestURI(null);
|
||||
request.setMethod(method);
|
||||
request.setServletPath(path);
|
||||
|
||||
request.setServletPath(path);
|
||||
|
||||
return new FilterInvocation(request, new MockHttpServletResponse(), new MockFilterChain());
|
||||
}
|
||||
return new FilterInvocation(request, new MockHttpServletResponse(),
|
||||
new MockFilterChain());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,105 +56,102 @@ import org.springframework.util.ReflectionUtils;
|
||||
*
|
||||
*/
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareForTest({ReflectionUtils.class, Method.class})
|
||||
@PrepareForTest({ ReflectionUtils.class, Method.class })
|
||||
public class SessionManagementConfigServlet31Tests {
|
||||
private static final String XML_AUTHENTICATION_MANAGER =
|
||||
"<authentication-manager>"+
|
||||
" <authentication-provider>"+
|
||||
" <user-service>"+
|
||||
" <user name='user' password='password' authorities='ROLE_USER' />" +
|
||||
" </user-service>"+
|
||||
" </authentication-provider>"+
|
||||
"</authentication-manager>";
|
||||
private static final String XML_AUTHENTICATION_MANAGER = "<authentication-manager>"
|
||||
+ " <authentication-provider>" + " <user-service>"
|
||||
+ " <user name='user' password='password' authorities='ROLE_USER' />"
|
||||
+ " </user-service>" + " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
|
||||
@Mock
|
||||
Method method;
|
||||
@Mock
|
||||
Method method;
|
||||
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
MockHttpServletRequest request;
|
||||
MockHttpServletResponse response;
|
||||
MockFilterChain chain;
|
||||
|
||||
ConfigurableApplicationContext context;
|
||||
ConfigurableApplicationContext context;
|
||||
|
||||
Filter springSecurityFilterChain;
|
||||
Filter springSecurityFilterChain;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
@Before
|
||||
public void setup() {
|
||||
request = new MockHttpServletRequest();
|
||||
response = new MockHttpServletResponse();
|
||||
chain = new MockFilterChain();
|
||||
}
|
||||
|
||||
@After
|
||||
public void teardown() {
|
||||
if(context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void teardown() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
@Test
|
||||
public void changeSessionIdDefaultsInServlet31Plus() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId"))
|
||||
.thenReturn(method);
|
||||
|
||||
loadContext("<http>\n" +
|
||||
" <form-login/>\n" +
|
||||
" <session-management/>\n" +
|
||||
" <csrf disabled='true'/>\n" +
|
||||
" </http>" +
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
loadContext("<http>\n" + " <form-login/>\n"
|
||||
+ " <session-management/>\n" + " <csrf disabled='true'/>\n"
|
||||
+ " </http>" + XML_AUTHENTICATION_MANAGER);
|
||||
|
||||
springSecurityFilterChain.doFilter(request,response,chain);
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void changeSessionId() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId"))
|
||||
.thenReturn(method);
|
||||
|
||||
@Test
|
||||
public void changeSessionId() throws Exception {
|
||||
spy(ReflectionUtils.class);
|
||||
Method method = mock(Method.class);
|
||||
MockHttpServletRequest request = new MockHttpServletRequest();
|
||||
request.getSession();
|
||||
request.setServletPath("/login");
|
||||
request.setMethod("POST");
|
||||
request.setParameter("username", "user");
|
||||
request.setParameter("password", "password");
|
||||
when(ReflectionUtils.findMethod(HttpServletRequest.class, "changeSessionId")).thenReturn(method);
|
||||
loadContext("<http>\n"
|
||||
+ " <form-login/>\n"
|
||||
+ " <session-management session-fixation-protection='changeSessionId'/>\n"
|
||||
+ " <csrf disabled='true'/>\n" + " </http>"
|
||||
+ XML_AUTHENTICATION_MANAGER);
|
||||
|
||||
loadContext("<http>\n" +
|
||||
" <form-login/>\n" +
|
||||
" <session-management session-fixation-protection='changeSessionId'/>\n" +
|
||||
" <csrf disabled='true'/>\n" +
|
||||
" </http>" +
|
||||
XML_AUTHENTICATION_MANAGER);
|
||||
springSecurityFilterChain.doFilter(request, response, chain);
|
||||
|
||||
springSecurityFilterChain.doFilter(request,response,chain);
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
|
||||
verifyStatic();
|
||||
ReflectionUtils.invokeMethod(same(method), any(HttpServletRequest.class));
|
||||
}
|
||||
private void loadContext(String context) {
|
||||
this.context = new InMemoryXmlApplicationContext(context);
|
||||
this.springSecurityFilterChain = this.context.getBean(
|
||||
"springSecurityFilterChain", Filter.class);
|
||||
}
|
||||
|
||||
private void loadContext(String context) {
|
||||
this.context = new InMemoryXmlApplicationContext(context);
|
||||
this.springSecurityFilterChain = this.context.getBean("springSecurityFilterChain",Filter.class);
|
||||
}
|
||||
private void login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(
|
||||
request, response);
|
||||
repo.loadContext(requestResponseHolder);
|
||||
|
||||
private void login(Authentication auth) {
|
||||
HttpSessionSecurityContextRepository repo = new HttpSessionSecurityContextRepository();
|
||||
HttpRequestResponseHolder requestResponseHolder = new HttpRequestResponseHolder(request, response);
|
||||
repo.loadContext(requestResponseHolder);
|
||||
|
||||
SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(auth);
|
||||
repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(), requestResponseHolder.getResponse());
|
||||
}
|
||||
SecurityContextImpl securityContextImpl = new SecurityContextImpl();
|
||||
securityContextImpl.setAuthentication(auth);
|
||||
repo.saveContext(securityContextImpl, requestResponseHolder.getRequest(),
|
||||
requestResponseHolder.getResponse());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,19 +24,20 @@ import org.powermock.core.classloader.annotations.PrepareOnlyThisForTest;
|
||||
import org.powermock.modules.junit4.PowerMockRunner;
|
||||
import org.springframework.beans.factory.xml.ParserContext;
|
||||
|
||||
|
||||
@RunWith(PowerMockRunner.class)
|
||||
@PrepareOnlyThisForTest(ParserContext.class)
|
||||
public class WebConfigUtilsTest {
|
||||
public final static String URL = "/url";
|
||||
public final static String URL = "/url";
|
||||
|
||||
@Mock
|
||||
private ParserContext parserContext;
|
||||
@Mock
|
||||
private ParserContext parserContext;
|
||||
|
||||
// SEC-1980
|
||||
@Test
|
||||
public void validateHttpRedirectSpELNoParserWarning() {
|
||||
WebConfigUtils.validateHttpRedirect("#{T(org.springframework.security.config.http.WebConfigUtilsTest).URL}", parserContext, "fakeSource");
|
||||
verifyZeroInteractions(parserContext);
|
||||
}
|
||||
// SEC-1980
|
||||
@Test
|
||||
public void validateHttpRedirectSpELNoParserWarning() {
|
||||
WebConfigUtils.validateHttpRedirect(
|
||||
"#{T(org.springframework.security.config.http.WebConfigUtilsTest).URL}",
|
||||
parserContext, "fakeSource");
|
||||
verifyZeroInteractions(parserContext);
|
||||
}
|
||||
}
|
||||
@@ -49,391 +49,406 @@ import org.springframework.security.util.FieldUtils;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class GlobalMethodSecurityBeanDefinitionParserTests {
|
||||
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken("bob","bobspassword");
|
||||
private final UsernamePasswordAuthenticationToken bob = new UsernamePasswordAuthenticationToken(
|
||||
"bob", "bobspassword");
|
||||
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
private BusinessService target;
|
||||
|
||||
public void loadContext() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security order='1001' proxy-target-class='false' >" +
|
||||
" <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>" +
|
||||
" <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
public void loadContext() {
|
||||
setContext("<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
|
||||
+ "<global-method-security order='1001' proxy-target-class='false' >"
|
||||
+ " <protect-pointcut expression='execution(* *.someUser*(..))' access='ROLE_USER'/>"
|
||||
+ " <protect-pointcut expression='execution(* *.someAdmin*(..))' access='ROLE_ADMIN'/>"
|
||||
+ "</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
target = null;
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
target = null;
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
loadContext();
|
||||
|
||||
target.someUserMethod1();
|
||||
}
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("user", "password");
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
loadContext();
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"user", "password");
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
target.someUserMethod1();
|
||||
|
||||
// SEC-1213. Check the order
|
||||
Advisor[] advisors = ((Advised)target).getAdvisors();
|
||||
assertEquals(1, advisors.length);
|
||||
assertEquals(1001, ((MethodSecurityMetadataSourceAdvisor)advisors[0]).getOrder());
|
||||
}
|
||||
// SEC-1213. Check the order
|
||||
Advisor[] advisors = ((Advised) target).getAdvisors();
|
||||
assertEquals(1, advisors.length);
|
||||
assertEquals(1001, ((MethodSecurityMetadataSourceAdvisor) advisors[0]).getOrder());
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("Test", "Password", "ROLE_SOMEOTHERROLE");
|
||||
token.setAuthenticated(true);
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
loadContext();
|
||||
TestingAuthenticationToken token = new TestingAuthenticationToken("Test",
|
||||
"Password", "ROLE_SOMEOTHERROLE");
|
||||
token.setAuthenticated(true);
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void doesntInterfereWithBeanPostProcessing() {
|
||||
setContext(
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<global-method-security />" +
|
||||
"<authentication-manager>" +
|
||||
" <authentication-provider user-service-ref='myUserService'/>" +
|
||||
"</authentication-manager>" +
|
||||
"<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>"
|
||||
);
|
||||
@Test
|
||||
public void doesntInterfereWithBeanPostProcessing() {
|
||||
setContext("<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>"
|
||||
+ "<global-method-security />"
|
||||
+ "<authentication-manager>"
|
||||
+ " <authentication-provider user-service-ref='myUserService'/>"
|
||||
+ "</authentication-manager>"
|
||||
+ "<b:bean id='beanPostProcessor' class='org.springframework.security.config.MockUserServiceBeanPostProcessor'/>");
|
||||
|
||||
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService)appContext.getBean("myUserService");
|
||||
PostProcessedMockUserDetailsService service = (PostProcessedMockUserDetailsService) appContext
|
||||
.getBean("myUserService");
|
||||
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
assertEquals("Hello from the post processor!", service.getPostProcessorWasHere());
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithAspectJAutoproxy() {
|
||||
setContext(
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'" +
|
||||
" access='ROLE_SOMETHING' />" +
|
||||
"</global-method-security>" +
|
||||
"<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>" +
|
||||
"<aop:aspectj-autoproxy />" +
|
||||
"<authentication-manager>" +
|
||||
" <authentication-provider user-service-ref='myUserService'/>" +
|
||||
"</authentication-manager>"
|
||||
);
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void worksWithAspectJAutoproxy() {
|
||||
setContext("<global-method-security>"
|
||||
+ " <protect-pointcut expression='execution(* org.springframework.security.config.*Service.*(..))'"
|
||||
+ " access='ROLE_SOMETHING' />"
|
||||
+ "</global-method-security>"
|
||||
+ "<b:bean id='myUserService' class='org.springframework.security.config.PostProcessedMockUserDetailsService'/>"
|
||||
+ "<aop:aspectj-autoproxy />" + "<authentication-manager>"
|
||||
+ " <authentication-provider user-service-ref='myUserService'/>"
|
||||
+ "</authentication-manager>");
|
||||
|
||||
UserDetailsService service = (UserDetailsService) appContext.getBean("myUserService");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
UserDetailsService service = (UserDetailsService) appContext
|
||||
.getBean("myUserService");
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
service.loadUserByUsername("notused");
|
||||
}
|
||||
service.loadUserByUsername("notused");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsMethodArgumentsInPointcut() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.access.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>" +
|
||||
" <protect-pointcut expression='execution(* org.springframework.security.access.annotation.BusinessService.*(..))' access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// someOther(int) should not be matched by someOther(String), but should require ROLE_USER
|
||||
target.someOther(0);
|
||||
@Test
|
||||
public void supportsMethodArgumentsInPointcut() {
|
||||
setContext("<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
|
||||
+ "<global-method-security>"
|
||||
+ " <protect-pointcut expression='execution(* org.springframework.security.access.annotation.BusinessService.someOther(String))' access='ROLE_ADMIN'/>"
|
||||
+ " <protect-pointcut expression='execution(* org.springframework.security.access.annotation.BusinessService.*(..))' access='ROLE_USER'/>"
|
||||
+ "</global-method-security>" + ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// someOther(int) should not be matched by someOther(String), but should require
|
||||
// ROLE_USER
|
||||
target.someOther(0);
|
||||
|
||||
try {
|
||||
// String version should required admin role
|
||||
target.someOther("somestring");
|
||||
fail("Expected AccessDeniedException");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
try {
|
||||
// String version should required admin role
|
||||
target.someOther("somestring");
|
||||
fail("Expected AccessDeniedException");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsBooleanPointcutExpressions() {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression=" +
|
||||
" 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) " +
|
||||
" and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' " +
|
||||
" access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// String method should not be protected
|
||||
target.someOther("somestring");
|
||||
@Test
|
||||
public void supportsBooleanPointcutExpressions() {
|
||||
setContext("<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
|
||||
+ "<global-method-security>"
|
||||
+ " <protect-pointcut expression="
|
||||
+ " 'execution(* org.springframework.security.access.annotation.BusinessService.*(..)) "
|
||||
+ " and not execution(* org.springframework.security.access.annotation.BusinessService.someOther(String)))' "
|
||||
+ " access='ROLE_USER'/>"
|
||||
+ "</global-method-security>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
// String method should not be protected
|
||||
target.someOther("somestring");
|
||||
|
||||
// All others should require ROLE_USER
|
||||
try {
|
||||
target.someOther(0);
|
||||
fail("Expected AuthenticationCredentialsNotFoundException");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
// All others should require ROLE_USER
|
||||
try {
|
||||
target.someOther(0);
|
||||
fail("Expected AuthenticationCredentialsNotFoundException");
|
||||
}
|
||||
catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target.someOther(0);
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken("user", "password"));
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
@Test(expected=BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext(
|
||||
"<global-method-security />" +
|
||||
"<global-method-security />"
|
||||
);
|
||||
}
|
||||
@Test(expected = BeanDefinitionParsingException.class)
|
||||
public void duplicateElementCausesError() {
|
||||
setContext("<global-method-security />" + "<global-method-security />");
|
||||
}
|
||||
|
||||
// SEC-936
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void worksWithoutTargetOrClass() {
|
||||
setContext(
|
||||
"<global-method-security secured-annotations='enabled'/>" +
|
||||
"<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>" +
|
||||
" <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>" +
|
||||
" <b:property name='serviceInterface' value='org.springframework.security.access.annotation.BusinessService'/>" +
|
||||
"</b:bean>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
// SEC-936
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void worksWithoutTargetOrClass() {
|
||||
setContext("<global-method-security secured-annotations='enabled'/>"
|
||||
+ "<b:bean id='businessService' class='org.springframework.remoting.httpinvoker.HttpInvokerProxyFactoryBean'>"
|
||||
+ " <b:property name='serviceUrl' value='http://localhost:8080/SomeService'/>"
|
||||
+ " <b:property name='serviceInterface' value='org.springframework.security.access.annotation.BusinessService'/>"
|
||||
+ "</b:bean>" + AUTH_PROVIDER_XML);
|
||||
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
target = (BusinessService) appContext.getBean("businessService");
|
||||
target.someUserMethod1();
|
||||
}
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
target = (BusinessService) appContext.getBean("businessService");
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
// Expression configuration tests
|
||||
// Expression configuration tests
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void expressionVoterAndAfterInvocationProviderUseSameExpressionHandlerInstance() throws Exception {
|
||||
setContext("<global-method-security pre-post-annotations='enabled'/>" + AUTH_PROVIDER_XML);
|
||||
AffirmativeBased adm = (AffirmativeBased) appContext.getBeansOfType(AffirmativeBased.class).values().toArray()[0];
|
||||
List voters = (List) FieldUtils.getFieldValue(adm, "decisionVoters");
|
||||
PreInvocationAuthorizationAdviceVoter mev = (PreInvocationAuthorizationAdviceVoter) voters.get(0);
|
||||
MethodSecurityMetadataSourceAdvisor msi = (MethodSecurityMetadataSourceAdvisor)
|
||||
appContext.getBeansOfType(MethodSecurityMetadataSourceAdvisor.class).values().toArray()[0];
|
||||
AfterInvocationProviderManager pm = (AfterInvocationProviderManager) ((MethodSecurityInterceptor)msi.getAdvice()).getAfterInvocationManager();
|
||||
PostInvocationAdviceProvider aip = (PostInvocationAdviceProvider) pm.getProviders().get(0);
|
||||
assertTrue(FieldUtils.getFieldValue(mev, "preAdvice.expressionHandler") == FieldUtils.getFieldValue(aip, "postAdvice.expressionHandler"));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
@Test
|
||||
public void expressionVoterAndAfterInvocationProviderUseSameExpressionHandlerInstance()
|
||||
throws Exception {
|
||||
setContext("<global-method-security pre-post-annotations='enabled'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
AffirmativeBased adm = (AffirmativeBased) appContext
|
||||
.getBeansOfType(AffirmativeBased.class).values().toArray()[0];
|
||||
List voters = (List) FieldUtils.getFieldValue(adm, "decisionVoters");
|
||||
PreInvocationAuthorizationAdviceVoter mev = (PreInvocationAuthorizationAdviceVoter) voters
|
||||
.get(0);
|
||||
MethodSecurityMetadataSourceAdvisor msi = (MethodSecurityMetadataSourceAdvisor) appContext
|
||||
.getBeansOfType(MethodSecurityMetadataSourceAdvisor.class).values()
|
||||
.toArray()[0];
|
||||
AfterInvocationProviderManager pm = (AfterInvocationProviderManager) ((MethodSecurityInterceptor) msi
|
||||
.getAdvice()).getAfterInvocationManager();
|
||||
PostInvocationAdviceProvider aip = (PostInvocationAdviceProvider) pm
|
||||
.getProviders().get(0);
|
||||
assertTrue(FieldUtils.getFieldValue(mev, "preAdvice.expressionHandler") == FieldUtils
|
||||
.getFieldValue(aip, "postAdvice.expressionHandler"));
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void accessIsDeniedForHasRoleExpression() {
|
||||
setContext(
|
||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
target.someAdminMethod();
|
||||
}
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void accessIsDeniedForHasRoleExpression() {
|
||||
setContext("<global-method-security pre-post-annotations='enabled'/>"
|
||||
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void beanNameExpressionPropertyIsSupported() {
|
||||
setContext(
|
||||
"<global-method-security pre-post-annotations='enabled' proxy-target-class='true'/>" +
|
||||
"<b:bean id='number' class='java.lang.Integer'>" +
|
||||
" <b:constructor-arg value='1294'/>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
ExpressionProtectedBusinessServiceImpl target = (ExpressionProtectedBusinessServiceImpl) appContext.getBean("target");
|
||||
target.methodWithBeanNamePropertyAccessExpression("x");
|
||||
}
|
||||
@Test
|
||||
public void beanNameExpressionPropertyIsSupported() {
|
||||
setContext("<global-method-security pre-post-annotations='enabled' proxy-target-class='true'/>"
|
||||
+ "<b:bean id='number' class='java.lang.Integer'>"
|
||||
+ " <b:constructor-arg value='1294'/>"
|
||||
+ "</b:bean>"
|
||||
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
ExpressionProtectedBusinessServiceImpl target = (ExpressionProtectedBusinessServiceImpl) appContext
|
||||
.getBean("target");
|
||||
target.methodWithBeanNamePropertyAccessExpression("x");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void preAndPostFilterAnnotationsWorkWithLists() {
|
||||
setContext(
|
||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
List<String> arg = new ArrayList<String>();
|
||||
arg.add("joe");
|
||||
arg.add("bob");
|
||||
arg.add("sam");
|
||||
List<?> result = target.methodReturningAList(arg);
|
||||
// Expression is (filterObject == name or filterObject == 'sam'), so "joe" should be gone after pre-filter
|
||||
// PostFilter should remove sam from the return object
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("bob", result.get(0));
|
||||
}
|
||||
@Test
|
||||
public void preAndPostFilterAnnotationsWorkWithLists() {
|
||||
setContext("<global-method-security pre-post-annotations='enabled'/>"
|
||||
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
List<String> arg = new ArrayList<String>();
|
||||
arg.add("joe");
|
||||
arg.add("bob");
|
||||
arg.add("sam");
|
||||
List<?> result = target.methodReturningAList(arg);
|
||||
// Expression is (filterObject == name or filterObject == 'sam'), so "joe" should
|
||||
// be gone after pre-filter
|
||||
// PostFilter should remove sam from the return object
|
||||
assertEquals(1, result.size());
|
||||
assertEquals("bob", result.get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void prePostFilterAnnotationWorksWithArrays() {
|
||||
setContext(
|
||||
"<global-method-security pre-post-annotations='enabled'/>" +
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
Object[] arg = new String[] {"joe", "bob", "sam"};
|
||||
Object[] result = target.methodReturningAnArray(arg);
|
||||
assertEquals(1, result.length);
|
||||
assertEquals("bob", result[0]);
|
||||
}
|
||||
@Test
|
||||
public void prePostFilterAnnotationWorksWithArrays() {
|
||||
setContext("<global-method-security pre-post-annotations='enabled'/>"
|
||||
+ "<b:bean id='target' class='org.springframework.security.access.annotation.ExpressionProtectedBusinessServiceImpl'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
Object[] arg = new String[] { "joe", "bob", "sam" };
|
||||
Object[] result = target.methodReturningAnArray(arg);
|
||||
assertEquals(1, result.length);
|
||||
assertEquals("bob", result[0]);
|
||||
}
|
||||
|
||||
// SEC-1392
|
||||
@Test
|
||||
public void customPermissionEvaluatorIsSupported() throws Exception {
|
||||
setContext(
|
||||
"<global-method-security pre-post-annotations='enabled'>" +
|
||||
" <expression-handler ref='expressionHandler'/>" +
|
||||
"</global-method-security>" +
|
||||
"<b:bean id='expressionHandler' class='org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler'>" +
|
||||
" <b:property name='permissionEvaluator' ref='myPermissionEvaluator'/>" +
|
||||
"</b:bean>" +
|
||||
"<b:bean id='myPermissionEvaluator' class='org.springframework.security.config.method.TestPermissionEvaluator'/>" +
|
||||
AUTH_PROVIDER_XML);
|
||||
}
|
||||
// SEC-1392
|
||||
@Test
|
||||
public void customPermissionEvaluatorIsSupported() throws Exception {
|
||||
setContext("<global-method-security pre-post-annotations='enabled'>"
|
||||
+ " <expression-handler ref='expressionHandler'/>"
|
||||
+ "</global-method-security>"
|
||||
+ "<b:bean id='expressionHandler' class='org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler'>"
|
||||
+ " <b:property name='permissionEvaluator' ref='myPermissionEvaluator'/>"
|
||||
+ "</b:bean>"
|
||||
+ "<b:bean id='myPermissionEvaluator' class='org.springframework.security.config.method.TestPermissionEvaluator'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
}
|
||||
|
||||
// SEC-1450
|
||||
@Test(expected=AuthenticationException.class)
|
||||
@SuppressWarnings("unchecked")
|
||||
public void genericsAreMatchedByProtectPointcut() throws Exception {
|
||||
setContext(
|
||||
"<b:bean id='target' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$ConcreteFoo'/>" +
|
||||
"<global-method-security>" +
|
||||
" <protect-pointcut expression='execution(* org..*Foo.foo(..))' access='ROLE_USER'/>" +
|
||||
"</global-method-security>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
// SEC-1450
|
||||
@Test(expected = AuthenticationException.class)
|
||||
@SuppressWarnings("unchecked")
|
||||
public void genericsAreMatchedByProtectPointcut() throws Exception {
|
||||
setContext("<b:bean id='target' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$ConcreteFoo'/>"
|
||||
+ "<global-method-security>"
|
||||
+ " <protect-pointcut expression='execution(* org..*Foo.foo(..))' access='ROLE_USER'/>"
|
||||
+ "</global-method-security>" + AUTH_PROVIDER_XML);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
|
||||
// SEC-1448
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void genericsMethodArgumentNamesAreResolved() throws Exception {
|
||||
setContext(
|
||||
"<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>" +
|
||||
"<global-method-security pre-post-annotations='enabled'/>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
// SEC-1448
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void genericsMethodArgumentNamesAreResolved() throws Exception {
|
||||
setContext("<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>"
|
||||
+ "<global-method-security pre-post-annotations='enabled'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void runAsManagerIsSetCorrectly() throws Exception {
|
||||
StaticApplicationContext parent = new StaticApplicationContext();
|
||||
MutablePropertyValues props = new MutablePropertyValues();
|
||||
props.addPropertyValue("key", "blah");
|
||||
parent.registerSingleton("runAsMgr", RunAsManagerImpl.class, props);
|
||||
parent.refresh();
|
||||
@Test
|
||||
public void runAsManagerIsSetCorrectly() throws Exception {
|
||||
StaticApplicationContext parent = new StaticApplicationContext();
|
||||
MutablePropertyValues props = new MutablePropertyValues();
|
||||
props.addPropertyValue("key", "blah");
|
||||
parent.registerSingleton("runAsMgr", RunAsManagerImpl.class, props);
|
||||
parent.refresh();
|
||||
|
||||
setContext("<global-method-security run-as-manager-ref='runAsMgr'/>" + AUTH_PROVIDER_XML, parent);
|
||||
RunAsManagerImpl ram = (RunAsManagerImpl) appContext.getBean("runAsMgr");
|
||||
MethodSecurityMetadataSourceAdvisor msi = (MethodSecurityMetadataSourceAdvisor)
|
||||
appContext.getBeansOfType(MethodSecurityMetadataSourceAdvisor.class).values().toArray()[0];
|
||||
assertSame(ram, FieldUtils.getFieldValue(msi.getAdvice(), "runAsManager"));
|
||||
}
|
||||
setContext("<global-method-security run-as-manager-ref='runAsMgr'/>"
|
||||
+ AUTH_PROVIDER_XML, parent);
|
||||
RunAsManagerImpl ram = (RunAsManagerImpl) appContext.getBean("runAsMgr");
|
||||
MethodSecurityMetadataSourceAdvisor msi = (MethodSecurityMetadataSourceAdvisor) appContext
|
||||
.getBeansOfType(MethodSecurityMetadataSourceAdvisor.class).values()
|
||||
.toArray()[0];
|
||||
assertSame(ram, FieldUtils.getFieldValue(msi.getAdvice(), "runAsManager"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void supportsExternalMetadataSource() throws Exception {
|
||||
setContext(
|
||||
"<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>" +
|
||||
"<method-security-metadata-source id='mds'>" +
|
||||
" <protect method='"+ Foo.class.getName() + ".foo' access='ROLE_ADMIN'/>" +
|
||||
"</method-security-metadata-source>" +
|
||||
"<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds'/>" + AUTH_PROVIDER_XML
|
||||
);
|
||||
// External MDS should take precedence over PreAuthorize
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
try {
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
fail("Bob can't invoke admin methods");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("admin", "password"));
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
@Test
|
||||
@SuppressWarnings("unchecked")
|
||||
public void supportsExternalMetadataSource() throws Exception {
|
||||
setContext("<b:bean id='target' class='"
|
||||
+ ConcreteFoo.class.getName()
|
||||
+ "'/>"
|
||||
+ "<method-security-metadata-source id='mds'>"
|
||||
+ " <protect method='"
|
||||
+ Foo.class.getName()
|
||||
+ ".foo' access='ROLE_ADMIN'/>"
|
||||
+ "</method-security-metadata-source>"
|
||||
+ "<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds'/>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
// External MDS should take precedence over PreAuthorize
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
try {
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
fail("Bob can't invoke admin methods");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken("admin", "password"));
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void supportsCustomAuthenticationManager() throws Exception {
|
||||
setContext(
|
||||
"<b:bean id='target' class='" + ConcreteFoo.class.getName() + "'/>" +
|
||||
"<method-security-metadata-source id='mds'>" +
|
||||
" <protect method='"+ Foo.class.getName() + ".foo' access='ROLE_ADMIN'/>" +
|
||||
"</method-security-metadata-source>" +
|
||||
"<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds' authentication-manager-ref='customAuthMgr'/>" +
|
||||
"<b:bean id='customAuthMgr' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$CustomAuthManager'>" +
|
||||
" <b:constructor-arg value='authManager'/>" +
|
||||
"</b:bean>" +
|
||||
AUTH_PROVIDER_XML
|
||||
);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
try {
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
fail("Bob can't invoke admin methods");
|
||||
} catch (AccessDeniedException expected) {
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(new UsernamePasswordAuthenticationToken("admin", "password"));
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
@Test
|
||||
public void supportsCustomAuthenticationManager() throws Exception {
|
||||
setContext("<b:bean id='target' class='"
|
||||
+ ConcreteFoo.class.getName()
|
||||
+ "'/>"
|
||||
+ "<method-security-metadata-source id='mds'>"
|
||||
+ " <protect method='"
|
||||
+ Foo.class.getName()
|
||||
+ ".foo' access='ROLE_ADMIN'/>"
|
||||
+ "</method-security-metadata-source>"
|
||||
+ "<global-method-security pre-post-annotations='enabled' metadata-source-ref='mds' authentication-manager-ref='customAuthMgr'/>"
|
||||
+ "<b:bean id='customAuthMgr' class='org.springframework.security.config.method.GlobalMethodSecurityBeanDefinitionParserTests$CustomAuthManager'>"
|
||||
+ " <b:constructor-arg value='authManager'/>" + "</b:bean>"
|
||||
+ AUTH_PROVIDER_XML);
|
||||
SecurityContextHolder.getContext().setAuthentication(bob);
|
||||
Foo foo = (Foo) appContext.getBean("target");
|
||||
try {
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
fail("Bob can't invoke admin methods");
|
||||
}
|
||||
catch (AccessDeniedException expected) {
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new UsernamePasswordAuthenticationToken("admin", "password"));
|
||||
foo.foo(new SecurityConfig("A"));
|
||||
}
|
||||
|
||||
static class CustomAuthManager implements AuthenticationManager, ApplicationContextAware {
|
||||
private String beanName;
|
||||
private AuthenticationManager authenticationManager;
|
||||
static class CustomAuthManager implements AuthenticationManager,
|
||||
ApplicationContextAware {
|
||||
private String beanName;
|
||||
private AuthenticationManager authenticationManager;
|
||||
|
||||
CustomAuthManager(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
CustomAuthManager(String beanName) {
|
||||
this.beanName = beanName;
|
||||
}
|
||||
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return authenticationManager.authenticate(authentication);
|
||||
}
|
||||
public Authentication authenticate(Authentication authentication)
|
||||
throws AuthenticationException {
|
||||
return authenticationManager.authenticate(authentication);
|
||||
}
|
||||
|
||||
/* (non-Javadoc)
|
||||
* @see org.springframework.context.ApplicationContextAware#setApplicationContext(org.springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.authenticationManager = applicationContext.getBean(beanName,AuthenticationManager.class);
|
||||
}
|
||||
}
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.context.ApplicationContextAware#setApplicationContext(org
|
||||
* .springframework.context.ApplicationContext)
|
||||
*/
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.authenticationManager = applicationContext.getBean(beanName,
|
||||
AuthenticationManager.class);
|
||||
}
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
private void setContext(String context, ApplicationContext parent) {
|
||||
appContext = new InMemoryXmlApplicationContext(context, parent);
|
||||
}
|
||||
private void setContext(String context, ApplicationContext parent) {
|
||||
appContext = new InMemoryXmlApplicationContext(context, parent);
|
||||
}
|
||||
|
||||
interface Foo<T extends ConfigAttribute> {
|
||||
void foo(T action);
|
||||
}
|
||||
interface Foo<T extends ConfigAttribute> {
|
||||
void foo(T action);
|
||||
}
|
||||
|
||||
public static class ConcreteFoo implements Foo<SecurityConfig> {
|
||||
@PreAuthorize("#action.attribute == 'A'")
|
||||
public void foo(SecurityConfig action) {
|
||||
}
|
||||
}
|
||||
public static class ConcreteFoo implements Foo<SecurityConfig> {
|
||||
@PreAuthorize("#action.attribute == 'A'")
|
||||
public void foo(SecurityConfig action) {
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,69 +27,73 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
*/
|
||||
@RunWith(SpringJUnit4ClassRunner.class)
|
||||
@ContextConfiguration(locations = "classpath:org/springframework/security/config/method-security.xml")
|
||||
public class InterceptMethodsBeanDefinitionDecoratorTests implements ApplicationContextAware {
|
||||
@Autowired
|
||||
@Qualifier("target")
|
||||
private TestBusinessBean target;
|
||||
@Autowired
|
||||
@Qualifier("transactionalTarget")
|
||||
private TestBusinessBean transactionalTarget;
|
||||
private ApplicationContext appContext;
|
||||
public class InterceptMethodsBeanDefinitionDecoratorTests implements
|
||||
ApplicationContextAware {
|
||||
@Autowired
|
||||
@Qualifier("target")
|
||||
private TestBusinessBean target;
|
||||
@Autowired
|
||||
@Qualifier("transactionalTarget")
|
||||
private TestBusinessBean transactionalTarget;
|
||||
private ApplicationContext appContext;
|
||||
|
||||
@BeforeClass
|
||||
public static void loadContext() {
|
||||
// Set value for placeholder
|
||||
System.setProperty("admin.role", "ROLE_ADMIN");
|
||||
}
|
||||
@BeforeClass
|
||||
public static void loadContext() {
|
||||
// Set value for placeholder
|
||||
System.setProperty("admin.role", "ROLE_ADMIN");
|
||||
}
|
||||
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
@After
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetDoesntLoseApplicationListenerInterface() {
|
||||
assertEquals(1, appContext.getBeansOfType(ApplicationListener.class).size());
|
||||
assertEquals(1, appContext.getBeanNamesForType(ApplicationListener.class).length);
|
||||
appContext.publishEvent(new AuthenticationSuccessEvent(new TestingAuthenticationToken("user", "")));
|
||||
@Test
|
||||
public void targetDoesntLoseApplicationListenerInterface() {
|
||||
assertEquals(1, appContext.getBeansOfType(ApplicationListener.class).size());
|
||||
assertEquals(1, appContext.getBeanNamesForType(ApplicationListener.class).length);
|
||||
appContext.publishEvent(new AuthenticationSuccessEvent(
|
||||
new TestingAuthenticationToken("user", "")));
|
||||
|
||||
assertTrue(target instanceof ApplicationListener<?>);
|
||||
}
|
||||
assertTrue(target instanceof ApplicationListener<?>);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowUnprotectedMethodInvocationWithNoContext() {
|
||||
target.unprotected();
|
||||
}
|
||||
@Test
|
||||
public void targetShouldAllowUnprotectedMethodInvocationWithNoContext() {
|
||||
target.unprotected();
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.doSomething();
|
||||
}
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.doSomething();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.doSomething();
|
||||
}
|
||||
target.doSomething();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.doSomething();
|
||||
}
|
||||
target.doSomething();
|
||||
}
|
||||
|
||||
@Test(expected = AuthenticationException.class)
|
||||
public void transactionalMethodsShouldBeSecured() throws Exception {
|
||||
transactionalTarget.doSomething();
|
||||
}
|
||||
@Test(expected = AuthenticationException.class)
|
||||
public void transactionalMethodsShouldBeSecured() throws Exception {
|
||||
transactionalTarget.doSomething();
|
||||
}
|
||||
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
this.appContext = applicationContext;
|
||||
}
|
||||
public void setApplicationContext(ApplicationContext applicationContext)
|
||||
throws BeansException {
|
||||
this.appContext = applicationContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,66 +16,66 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class Jsr250AnnotationDrivenBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.Jsr250BusinessServiceImpl'/>" +
|
||||
"<global-method-security jsr250-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
@Before
|
||||
public void loadContext() {
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.Jsr250BusinessServiceImpl'/>"
|
||||
+ "<global-method-security jsr250-annotations='enabled'/>"
|
||||
+ ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.someUserMethod1();
|
||||
}
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void permitAllShouldBeDefaultAttribute() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test
|
||||
public void permitAllShouldBeDefaultAttribute() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someOther(0);
|
||||
}
|
||||
target.someOther(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
}
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHERROLE"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void hasAnyRoleAddsDefaultPrefix() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
@Test
|
||||
public void hasAnyRoleAddsDefaultPrefix() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.rolesAllowedUser();
|
||||
}
|
||||
target.rolesAllowedUser();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,50 +30,50 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
*/
|
||||
public class Sec2196Tests {
|
||||
|
||||
private ConfigurableApplicationContext context;
|
||||
private ConfigurableApplicationContext context;
|
||||
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void genericMethodsProtected() {
|
||||
loadContext("<global-method-security secured-annotations=\"enabled\" pre-post-annotations=\"enabled\"/>"
|
||||
+ "<b:bean class='" + Service.class.getName() + "'/>");
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void genericMethodsProtected() {
|
||||
loadContext("<global-method-security secured-annotations=\"enabled\" pre-post-annotations=\"enabled\"/>"
|
||||
+ "<b:bean class='" + Service.class.getName() + "'/>");
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("test", "pass", "ROLE_USER"));
|
||||
Service service = context.getBean(Service.class);
|
||||
service.save(new User());
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("test", "pass", "ROLE_USER"));
|
||||
Service service = context.getBean(Service.class);
|
||||
service.save(new User());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void genericMethodsAllowed() {
|
||||
loadContext("<global-method-security secured-annotations=\"enabled\" pre-post-annotations=\"enabled\"/>"
|
||||
+ "<b:bean class='" + Service.class.getName() + "'/>");
|
||||
@Test
|
||||
public void genericMethodsAllowed() {
|
||||
loadContext("<global-method-security secured-annotations=\"enabled\" pre-post-annotations=\"enabled\"/>"
|
||||
+ "<b:bean class='" + Service.class.getName() + "'/>");
|
||||
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("test", "pass", "saveUsers"));
|
||||
Service service = context.getBean(Service.class);
|
||||
service.save(new User());
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("test", "pass", "saveUsers"));
|
||||
Service service = context.getBean(Service.class);
|
||||
service.save(new User());
|
||||
}
|
||||
|
||||
private void loadContext(String context) {
|
||||
this.context = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void loadContext(String context) {
|
||||
this.context = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
context = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (context != null) {
|
||||
context.close();
|
||||
context = null;
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
public static class Service {
|
||||
@PreAuthorize("hasAuthority('saveUsers')")
|
||||
public <T extends User> T save(T dto) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
public static class Service {
|
||||
@PreAuthorize("hasAuthority('saveUsers')")
|
||||
public <T extends User> T save(T dto) {
|
||||
return dto;
|
||||
}
|
||||
}
|
||||
|
||||
static class User {
|
||||
}
|
||||
static class User {
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,83 +23,86 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class SecuredAnnotationDrivenBeanDefinitionParserTests {
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
private InMemoryXmlApplicationContext appContext;
|
||||
|
||||
private BusinessService target;
|
||||
private BusinessService target;
|
||||
|
||||
@Before
|
||||
public void loadContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>" +
|
||||
"<global-method-security secured-annotations='enabled'/>" + ConfigTestUtils.AUTH_PROVIDER_XML
|
||||
);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
@Before
|
||||
public void loadContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
appContext = new InMemoryXmlApplicationContext(
|
||||
"<b:bean id='target' class='org.springframework.security.access.annotation.BusinessServiceImpl'/>"
|
||||
+ "<global-method-security secured-annotations='enabled'/>"
|
||||
+ ConfigTestUtils.AUTH_PROVIDER_XML);
|
||||
target = (BusinessService) appContext.getBean("target");
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
}
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.someUserMethod1();
|
||||
}
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithNoContext() {
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test
|
||||
public void targetShouldAllowProtectedMethodInvocationWithCorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password", AuthorityUtils.createAuthorityList("ROLE_USER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someUserMethod1();
|
||||
}
|
||||
target.someUserMethod1();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken("Test", "Password",
|
||||
AuthorityUtils.createAuthorityList("ROLE_SOMEOTHER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void targetShouldPreventProtectedMethodInvocationWithIncorrectRole() {
|
||||
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
|
||||
"Test", "Password", AuthorityUtils.createAuthorityList("ROLE_SOMEOTHER"));
|
||||
SecurityContextHolder.getContext().setAuthentication(token);
|
||||
|
||||
target.someAdminMethod();
|
||||
}
|
||||
target.someAdminMethod();
|
||||
}
|
||||
|
||||
// SEC-1387
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetIsSerializableBeforeUse() throws Exception {
|
||||
BusinessService chompedTarget = (BusinessService) serializeAndDeserialize(target);
|
||||
chompedTarget.someAdminMethod();
|
||||
}
|
||||
// SEC-1387
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void targetIsSerializableBeforeUse() throws Exception {
|
||||
BusinessService chompedTarget = (BusinessService) serializeAndDeserialize(target);
|
||||
chompedTarget.someAdminMethod();
|
||||
}
|
||||
|
||||
@Test(expected=AccessDeniedException.class)
|
||||
public void targetIsSerializableAfterUse() throws Exception {
|
||||
try {
|
||||
target.someAdminMethod();
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(new TestingAuthenticationToken("u","p","ROLE_A"));
|
||||
@Test(expected = AccessDeniedException.class)
|
||||
public void targetIsSerializableAfterUse() throws Exception {
|
||||
try {
|
||||
target.someAdminMethod();
|
||||
}
|
||||
catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
SecurityContextHolder.getContext().setAuthentication(
|
||||
new TestingAuthenticationToken("u", "p", "ROLE_A"));
|
||||
|
||||
BusinessService chompedTarget = (BusinessService) serializeAndDeserialize(target);
|
||||
chompedTarget.someAdminMethod();
|
||||
}
|
||||
BusinessService chompedTarget = (BusinessService) serializeAndDeserialize(target);
|
||||
chompedTarget.someAdminMethod();
|
||||
}
|
||||
|
||||
private Object serializeAndDeserialize(Object o) throws IOException, ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
oos.flush();
|
||||
baos.flush();
|
||||
byte[] bytes = baos.toByteArray();
|
||||
private Object serializeAndDeserialize(Object o) throws IOException,
|
||||
ClassNotFoundException {
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ObjectOutputStream oos = new ObjectOutputStream(baos);
|
||||
oos.writeObject(o);
|
||||
oos.flush();
|
||||
baos.flush();
|
||||
byte[] bytes = baos.toByteArray();
|
||||
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Object o2 = ois.readObject();
|
||||
ByteArrayInputStream is = new ByteArrayInputStream(bytes);
|
||||
ObjectInputStream ois = new ObjectInputStream(is);
|
||||
Object o2 = ois.readObject();
|
||||
|
||||
return o2;
|
||||
}
|
||||
return o2;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,13 +7,14 @@ import org.springframework.security.core.Authentication;
|
||||
|
||||
public class TestPermissionEvaluator implements PermissionEvaluator {
|
||||
|
||||
public boolean hasPermission(Authentication authentication, Object targetDomainObject, Object permission) {
|
||||
return false;
|
||||
}
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Object targetDomainObject, Object permission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId, String targetType,
|
||||
Object permission) {
|
||||
return false;
|
||||
}
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId,
|
||||
String targetType, Object permission) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -29,20 +29,20 @@ import org.springframework.security.core.Authentication;
|
||||
*
|
||||
*/
|
||||
public class JpaPermissionEvaluator implements PermissionEvaluator {
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
@Autowired
|
||||
private EntityManager entityManager;
|
||||
|
||||
public JpaPermissionEvaluator() {
|
||||
System.out.println("initializing "+this);
|
||||
}
|
||||
public JpaPermissionEvaluator() {
|
||||
System.out.println("initializing " + this);
|
||||
}
|
||||
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Object targetDomainObject, Object permission) {
|
||||
return true;
|
||||
}
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Object targetDomainObject, Object permission) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean hasPermission(Authentication authentication,
|
||||
Serializable targetId, String targetType, Object permission) {
|
||||
return true;
|
||||
}
|
||||
public boolean hasPermission(Authentication authentication, Serializable targetId,
|
||||
String targetType, Object permission) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,8 +29,8 @@ import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
|
||||
@ContextConfiguration("sec2136.xml")
|
||||
public class Sec2136Tests {
|
||||
|
||||
@Test
|
||||
public void configurationLoads() {
|
||||
@Test
|
||||
public void configurationLoads() {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,26 +25,27 @@ import org.springframework.context.support.GenericXmlApplicationContext;
|
||||
*
|
||||
*/
|
||||
public class Sec2499Tests {
|
||||
private GenericXmlApplicationContext parent;
|
||||
private GenericXmlApplicationContext parent;
|
||||
|
||||
private GenericXmlApplicationContext child;
|
||||
private GenericXmlApplicationContext child;
|
||||
|
||||
@After
|
||||
public void cleanup() {
|
||||
if(parent != null) {
|
||||
parent.close();
|
||||
}
|
||||
if(child != null) {
|
||||
child.close();
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void cleanup() {
|
||||
if (parent != null) {
|
||||
parent.close();
|
||||
}
|
||||
if (child != null) {
|
||||
child.close();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void methodExpressionHandlerInParentContextLoads() {
|
||||
parent = new GenericXmlApplicationContext("org/springframework/security/config/method/sec2499/parent.xml");
|
||||
child = new GenericXmlApplicationContext();
|
||||
child.load("org/springframework/security/config/method/sec2499/child.xml");
|
||||
child.setParent(parent);
|
||||
child.refresh();
|
||||
}
|
||||
@Test
|
||||
public void methodExpressionHandlerInParentContextLoads() {
|
||||
parent = new GenericXmlApplicationContext(
|
||||
"org/springframework/security/config/method/sec2499/parent.xml");
|
||||
child = new GenericXmlApplicationContext();
|
||||
child.load("org/springframework/security/config/method/sec2499/child.xml");
|
||||
child.setParent(parent);
|
||||
child.refresh();
|
||||
}
|
||||
}
|
||||
@@ -25,49 +25,49 @@ import org.springframework.security.util.InMemoryResource;
|
||||
* @author Luke Taylor
|
||||
*/
|
||||
public class InMemoryXmlApplicationContext extends AbstractXmlApplicationContext {
|
||||
private static final String BEANS_OPENING =
|
||||
"<b:beans xmlns='http://www.springframework.org/schema/security'\n" +
|
||||
" xmlns:context='http://www.springframework.org/schema/context'\n" +
|
||||
" xmlns:b='http://www.springframework.org/schema/beans'\n" +
|
||||
" xmlns:aop='http://www.springframework.org/schema/aop'\n" +
|
||||
" xmlns:websocket='http://www.springframework.org/schema/websocket'\n" +
|
||||
" xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n" +
|
||||
" xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd\n" +
|
||||
"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\n" +
|
||||
"http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
|
||||
private static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
private static final String BEANS_OPENING = "<b:beans xmlns='http://www.springframework.org/schema/security'\n"
|
||||
+ " xmlns:context='http://www.springframework.org/schema/context'\n"
|
||||
+ " xmlns:b='http://www.springframework.org/schema/beans'\n"
|
||||
+ " xmlns:aop='http://www.springframework.org/schema/aop'\n"
|
||||
+ " xmlns:websocket='http://www.springframework.org/schema/websocket'\n"
|
||||
+ " xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'\n"
|
||||
+ " xsi:schemaLocation='http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd\n"
|
||||
+ "http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd\n"
|
||||
+ "http://www.springframework.org/schema/websocket http://www.springframework.org/schema/websocket/spring-websocket.xsd\n"
|
||||
+ "http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd\n"
|
||||
+ "http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-";
|
||||
private static final String BEANS_CLOSE = "</b:beans>\n";
|
||||
|
||||
Resource inMemoryXml;
|
||||
Resource inMemoryXml;
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml) {
|
||||
this(xml, "4.0", null);
|
||||
}
|
||||
public InMemoryXmlApplicationContext(String xml) {
|
||||
this(xml, "4.0", null);
|
||||
}
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
||||
this(xml, "4.0", parent);
|
||||
}
|
||||
public InMemoryXmlApplicationContext(String xml, ApplicationContext parent) {
|
||||
this(xml, "4.0", parent);
|
||||
}
|
||||
|
||||
public InMemoryXmlApplicationContext(String xml, String secVersion, ApplicationContext parent) {
|
||||
String fullXml = BEANS_OPENING + secVersion + ".xsd'>\n" + xml + BEANS_CLOSE;
|
||||
inMemoryXml = new InMemoryResource(fullXml);
|
||||
setAllowBeanDefinitionOverriding(true);
|
||||
setParent(parent);
|
||||
refresh();
|
||||
}
|
||||
public InMemoryXmlApplicationContext(String xml, String secVersion,
|
||||
ApplicationContext parent) {
|
||||
String fullXml = BEANS_OPENING + secVersion + ".xsd'>\n" + xml + BEANS_CLOSE;
|
||||
inMemoryXml = new InMemoryResource(fullXml);
|
||||
setAllowBeanDefinitionOverriding(true);
|
||||
setParent(parent);
|
||||
refresh();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected DefaultListableBeanFactory createBeanFactory() {
|
||||
return new DefaultListableBeanFactory(getInternalParentBeanFactory()) {
|
||||
@Override
|
||||
protected boolean allowAliasOverriding() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
@Override
|
||||
protected DefaultListableBeanFactory createBeanFactory() {
|
||||
return new DefaultListableBeanFactory(getInternalParentBeanFactory()) {
|
||||
@Override
|
||||
protected boolean allowAliasOverriding() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected Resource[] getConfigResources() {
|
||||
return new Resource[] {inMemoryXml};
|
||||
}
|
||||
protected Resource[] getConfigResources() {
|
||||
return new Resource[] { inMemoryXml };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,105 +18,98 @@ import org.springframework.security.core.context.SecurityContextHolder;
|
||||
* @author Ben Alex
|
||||
*/
|
||||
public class MethodSecurityInterceptorWithAopConfigTests {
|
||||
static final String AUTH_PROVIDER_XML =
|
||||
"<authentication-manager>" +
|
||||
" <authentication-provider>" +
|
||||
" <user-service>" +
|
||||
" <user name='bob' password='bobspassword' authorities='ROLE_USER,ROLE_ADMIN' />" +
|
||||
" <user name='bill' password='billspassword' authorities='ROLE_USER' />" +
|
||||
" </user-service>" +
|
||||
" </authentication-provider>" +
|
||||
"</authentication-manager>";
|
||||
static final String AUTH_PROVIDER_XML = "<authentication-manager>"
|
||||
+ " <authentication-provider>"
|
||||
+ " <user-service>"
|
||||
+ " <user name='bob' password='bobspassword' authorities='ROLE_USER,ROLE_ADMIN' />"
|
||||
+ " <user name='bill' password='billspassword' authorities='ROLE_USER' />"
|
||||
+ " </user-service>" + " </authentication-provider>"
|
||||
+ "</authentication-manager>";
|
||||
|
||||
static final String ACCESS_MANAGER_XML =
|
||||
"<b:bean id='accessDecisionManager' class='org.springframework.security.access.vote.AffirmativeBased'>" +
|
||||
" <b:constructor-arg>" +
|
||||
" <b:list><b:bean class='org.springframework.security.access.vote.RoleVoter'/></b:list>" +
|
||||
" </b:constructor-arg>" +
|
||||
"</b:bean>";
|
||||
static final String ACCESS_MANAGER_XML = "<b:bean id='accessDecisionManager' class='org.springframework.security.access.vote.AffirmativeBased'>"
|
||||
+ " <b:constructor-arg>"
|
||||
+ " <b:list><b:bean class='org.springframework.security.access.vote.RoleVoter'/></b:list>"
|
||||
+ " </b:constructor-arg>" + "</b:bean>";
|
||||
|
||||
static final String TARGET_BEAN_AND_INTERCEPTOR =
|
||||
"<b:bean id='target' class='org.springframework.security.TargetObject'/>" +
|
||||
"<b:bean id='securityInterceptor' class='org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor' autowire='byType' >" +
|
||||
" <b:property name='securityMetadataSource'>" +
|
||||
" <method-security-metadata-source>" +
|
||||
" <protect method='org.springframework.security.ITargetObject.makeLower*' access='ROLE_A'/>" +
|
||||
" <protect method='org.springframework.security.ITargetObject.makeUpper*' access='ROLE_A'/>" +
|
||||
" <protect method='org.springframework.security.ITargetObject.computeHashCode*' access='ROLE_B'/>" +
|
||||
" </method-security-metadata-source>" +
|
||||
" </b:property>" +
|
||||
"</b:bean>";
|
||||
static final String TARGET_BEAN_AND_INTERCEPTOR = "<b:bean id='target' class='org.springframework.security.TargetObject'/>"
|
||||
+ "<b:bean id='securityInterceptor' class='org.springframework.security.access.intercept.aopalliance.MethodSecurityInterceptor' autowire='byType' >"
|
||||
+ " <b:property name='securityMetadataSource'>"
|
||||
+ " <method-security-metadata-source>"
|
||||
+ " <protect method='org.springframework.security.ITargetObject.makeLower*' access='ROLE_A'/>"
|
||||
+ " <protect method='org.springframework.security.ITargetObject.makeUpper*' access='ROLE_A'/>"
|
||||
+ " <protect method='org.springframework.security.ITargetObject.computeHashCode*' access='ROLE_B'/>"
|
||||
+ " </method-security-metadata-source>"
|
||||
+ " </b:property>"
|
||||
+ "</b:bean>";
|
||||
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
private AbstractXmlApplicationContext appContext;
|
||||
|
||||
@Before
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
@Before
|
||||
public void clearContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
}
|
||||
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
@After
|
||||
public void closeAppContext() {
|
||||
SecurityContextHolder.clearContext();
|
||||
if (appContext != null) {
|
||||
appContext.close();
|
||||
appContext = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void securityInterceptorIsAppliedWhenUsedWithAopConfig() {
|
||||
setContext(
|
||||
"<aop:config>" +
|
||||
" <aop:pointcut id='targetMethods' expression='execution(* org.springframework.security.TargetObject.*(..))'/>" +
|
||||
" <aop:advisor advice-ref='securityInterceptor' pointcut-ref='targetMethods' />" +
|
||||
"</aop:config>" +
|
||||
TARGET_BEAN_AND_INTERCEPTOR +
|
||||
AUTH_PROVIDER_XML + ACCESS_MANAGER_XML);
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void securityInterceptorIsAppliedWhenUsedWithAopConfig() {
|
||||
setContext("<aop:config>"
|
||||
+ " <aop:pointcut id='targetMethods' expression='execution(* org.springframework.security.TargetObject.*(..))'/>"
|
||||
+ " <aop:advisor advice-ref='securityInterceptor' pointcut-ref='targetMethods' />"
|
||||
+ "</aop:config>" + TARGET_BEAN_AND_INTERCEPTOR + AUTH_PROVIDER_XML
|
||||
+ ACCESS_MANAGER_XML);
|
||||
|
||||
ITargetObject target = (ITargetObject) appContext.getBean("target");
|
||||
ITargetObject target = (ITargetObject) appContext.getBean("target");
|
||||
|
||||
// Check both against interface and class
|
||||
try {
|
||||
target.makeLowerCase("TEST");
|
||||
fail("AuthenticationCredentialsNotFoundException expected");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
// Check both against interface and class
|
||||
try {
|
||||
target.makeLowerCase("TEST");
|
||||
fail("AuthenticationCredentialsNotFoundException expected");
|
||||
}
|
||||
catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
|
||||
target.makeUpperCase("test");
|
||||
}
|
||||
target.makeUpperCase("test");
|
||||
}
|
||||
|
||||
@Test(expected=AuthenticationCredentialsNotFoundException.class)
|
||||
public void securityInterceptorIsAppliedWhenUsedWithBeanNameAutoProxyCreator() {
|
||||
setContext(
|
||||
"<b:bean id='autoProxyCreator' class='org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator'>" +
|
||||
" <b:property name='interceptorNames'>" +
|
||||
" <b:list>" +
|
||||
" <b:value>securityInterceptor</b:value>" +
|
||||
" </b:list>" +
|
||||
" </b:property>" +
|
||||
" <b:property name='beanNames'>" +
|
||||
" <b:list>" +
|
||||
" <b:value>target</b:value>" +
|
||||
" </b:list>" +
|
||||
" </b:property>" +
|
||||
" <b:property name='proxyTargetClass' value='false'/>" +
|
||||
"</b:bean>" +
|
||||
TARGET_BEAN_AND_INTERCEPTOR +
|
||||
AUTH_PROVIDER_XML + ACCESS_MANAGER_XML);
|
||||
@Test(expected = AuthenticationCredentialsNotFoundException.class)
|
||||
public void securityInterceptorIsAppliedWhenUsedWithBeanNameAutoProxyCreator() {
|
||||
setContext("<b:bean id='autoProxyCreator' class='org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator'>"
|
||||
+ " <b:property name='interceptorNames'>"
|
||||
+ " <b:list>"
|
||||
+ " <b:value>securityInterceptor</b:value>"
|
||||
+ " </b:list>"
|
||||
+ " </b:property>"
|
||||
+ " <b:property name='beanNames'>"
|
||||
+ " <b:list>"
|
||||
+ " <b:value>target</b:value>"
|
||||
+ " </b:list>"
|
||||
+ " </b:property>"
|
||||
+ " <b:property name='proxyTargetClass' value='false'/>"
|
||||
+ "</b:bean>"
|
||||
+ TARGET_BEAN_AND_INTERCEPTOR + AUTH_PROVIDER_XML + ACCESS_MANAGER_XML);
|
||||
|
||||
ITargetObject target = (ITargetObject) appContext.getBean("target");
|
||||
ITargetObject target = (ITargetObject) appContext.getBean("target");
|
||||
|
||||
try {
|
||||
target.makeLowerCase("TEST");
|
||||
fail("AuthenticationCredentialsNotFoundException expected");
|
||||
} catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
try {
|
||||
target.makeLowerCase("TEST");
|
||||
fail("AuthenticationCredentialsNotFoundException expected");
|
||||
}
|
||||
catch (AuthenticationCredentialsNotFoundException expected) {
|
||||
}
|
||||
|
||||
target.makeUpperCase("test");
|
||||
target.makeUpperCase("test");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
private void setContext(String context) {
|
||||
appContext = new InMemoryXmlApplicationContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user