Created
January 19, 2012 21:15
-
-
Save bmchild/1642655 to your computer and use it in GitHub Desktop.
Custom regex lookup access Expression with Spring Security 3.1. The lookup, hasRegexRole, is available on the JSP or on the method.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!-- | |
Enable class- and method-level security via annotations | |
--> | |
<sec:global-method-security pre-post-annotations="enabled" secured-annotations="enabled"> | |
<sec:expression-handler ref="expressionHandler"/> | |
</sec:global-method-security> | |
<!-- | |
WebSecurityExpressHandler for Spring Security JSP tags | |
--> | |
<bean id="webSecurityExpressionHandler" class="com.bmchild.security.access.expression.CustomWebSecurityExpressionHandler"/> | |
<!-- Custom Expression Handler --> | |
<bean id="expressionHandler" class="com.bmchild.security.access.expression.CustomMethodSecurityExpressionHandler" /> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.bmchild.security.access.expression; | |
import org.aopalliance.intercept.MethodInvocation; | |
import org.apache.log4j.Logger; | |
import org.springframework.security.access.expression.SecurityExpressionRoot; | |
import org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler; | |
import org.springframework.security.core.Authentication; | |
/** | |
* @author bchild | |
* | |
*/ | |
public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler { | |
Logger LOGGER = Logger.getLogger(CustomMethodSecurityExpressionHandler.class); | |
public CustomMethodSecurityExpressionHandler() { | |
super(); | |
} | |
/* (non-Javadoc) | |
* @see org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler#createSecurityExpressionRoot(org.springframework.security.core.Authentication, org.aopalliance.intercept.MethodInvocation) | |
*/ | |
@Override | |
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, MethodInvocation invocation) { | |
CustomSecurityExpressionRoot root = new CustomSecurityExpressionRoot(authentication); | |
root.setPermissionEvaluator(getPermissionEvaluator()); | |
return root; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.bmchild.security.access.expression; | |
import java.util.Collection; | |
import java.util.HashSet; | |
import java.util.Set; | |
import javax.servlet.http.HttpServletRequest; | |
import org.apache.log4j.Logger; | |
import org.springframework.security.access.expression.SecurityExpressionRoot; | |
import org.springframework.security.core.Authentication; | |
import org.springframework.security.core.GrantedAuthority; | |
import org.springframework.security.core.authority.AuthorityUtils; | |
import org.springframework.security.web.FilterInvocation; | |
import org.springframework.security.web.util.IpAddressMatcher; | |
/** | |
* | |
* Security Expression evaluator for wildcard use | |
* | |
* @author bchild | |
* | |
*/ | |
public class CustomSecurityExpressionRoot extends SecurityExpressionRoot { | |
Logger LOGGER = Logger.getLogger(CustomSecurityExpressionRoot.class); | |
private Set<String> userRoles; | |
/* | |
* This is for emulating WebSecurityExpressionRoot | |
*/ | |
public HttpServletRequest request; | |
/** | |
* @param a | |
*/ | |
public CustomSecurityExpressionRoot(Authentication a) { | |
super(a); | |
} | |
public CustomSecurityExpressionRoot(Authentication a, FilterInvocation fi) { | |
super(a); | |
this.request = fi.getRequest(); | |
} | |
/** | |
* Checks given roles against the given regex expression | |
* | |
* @param regex | |
* to match agains roles | |
* @return true if at least 1 authority matches the regex, otherwise false | |
*/ | |
public boolean hasRegexRole(String regex) { | |
if (LOGGER.isDebugEnabled()) { | |
LOGGER.debug("hasRegexRole: " + regex); | |
} | |
boolean found = false; | |
Set<String> authorities = getCustomAuthoritySet(); | |
for (String authority : authorities) { | |
if (authority.matches(regex)) { | |
found = true; | |
break; | |
} | |
} | |
if (LOGGER.isDebugEnabled()) { | |
LOGGER.debug("hasRegexRole returns " + found); | |
} | |
return found; | |
} | |
/** | |
* | |
* @see org.springframework.security.web.access.expression. | |
* WebSecurityExpressionRoot.hasIpAddress(String) Takes a specific IP | |
* address or a range using the IP/Netmask (e.g. 192.168.1.0/24 or | |
* 202.24.0.0/14). | |
* | |
* @param ipAddress | |
* the address or range of addresses from which the request must | |
* come. | |
* @return true if the IP address of the current request is in the required | |
* range. | |
*/ | |
public boolean hasIpAddress(String ipAddress) { | |
return (new IpAddressMatcher(ipAddress).matches(request)); | |
} | |
/** | |
* Note: this does not return hierchacal roles like | |
* org.springframework.security | |
* .access.expression.SecurityExpressionRoot.getAuthoritySet() | |
* | |
* @return set of authorities | |
*/ | |
private Set<String> getCustomAuthoritySet() { | |
if (userRoles == null) { | |
userRoles = new HashSet<String>(); | |
Collection<? extends GrantedAuthority> userAuthorities = authentication.getAuthorities(); | |
userRoles = AuthorityUtils.authorityListToSet(userAuthorities); | |
} | |
return userRoles; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.bmchild.security.access.expression; | |
import static org.junit.Assert.assertFalse; | |
import static org.junit.Assert.assertTrue; | |
import static org.mockito.Mockito.mock; | |
import static org.mockito.Mockito.verify; | |
import static org.mockito.Mockito.when; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import org.junit.Before; | |
import org.junit.Test; | |
import org.junit.runner.RunWith; | |
import org.mockito.invocation.InvocationOnMock; | |
import org.mockito.runners.MockitoJUnitRunner; | |
import org.mockito.stubbing.Answer; | |
import org.springframework.security.core.Authentication; | |
import org.springframework.security.core.GrantedAuthority; | |
import org.springframework.security.core.authority.SimpleGrantedAuthority; | |
/** | |
* @author bchild | |
* | |
*/ | |
@RunWith(MockitoJUnitRunner.class) | |
public class CustomSecurityExpressionRootTest { | |
private CustomSecurityExpressionRoot expression; | |
private Authentication auth; | |
@Before | |
public void before() { | |
auth = mock(Authentication.class); | |
expression = new CustomSecurityExpressionRoot(auth); | |
} | |
/** | |
* Test method for {@link com.crengland.security.access.expression.CustomSecurityExpressionRoot#hasRegexRole(java.lang.String)}. | |
*/ | |
@Test | |
public void testHasRegexRole() { | |
// Mock | |
final Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>(); | |
authorities.add( new SimpleGrantedAuthority("ROLE_1_ADMIN") ); | |
authorities.add( new SimpleGrantedAuthority("ROLE_2_ADMIN") ); | |
authorities.add( new SimpleGrantedAuthority("ROLE_3_ADMIN") ); | |
authorities.add( new SimpleGrantedAuthority("ROLE_1_NONADMIN") ); | |
when(auth.getAuthorities()).thenAnswer( new Answer<Collection<GrantedAuthority>>() { | |
@Override | |
public Collection<GrantedAuthority> answer(InvocationOnMock invocation) throws Throwable { | |
return authorities; | |
} | |
}); | |
// Test | |
assertTrue( expression.hasRegexRole("ROLE_1_ADMIN") ); | |
assertTrue( expression.hasRegexRole("ROLE_.+_ADMIN") ); | |
assertFalse( expression.hasRegexRole("ROLE__ADMIN") ); | |
assertTrue( expression.hasRegexRole("ROLE_[\\d]+_NONADMIN") ); | |
// Verify | |
verify(auth).getAuthorities(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.bmchild.security.access.expression; | |
import org.springframework.security.access.expression.SecurityExpressionRoot; | |
import org.springframework.security.core.Authentication; | |
import org.springframework.security.web.FilterInvocation; | |
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler; | |
/** | |
* @author bchild | |
* | |
*/ | |
public class CustomWebSecurityExpressionHandler extends DefaultWebSecurityExpressionHandler { | |
@Override | |
protected SecurityExpressionRoot createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) { | |
CustomSecurityExpressionRoot root = new CustomSecurityExpressionRoot(authentication, fi); | |
root.setPermissionEvaluator(getPermissionEvaluator()); | |
return root; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
@configuration
@EnableWebSecurity
@order(2)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
}
@component
public class BasePermissionEvaluator implements PermissionEvaluator {
}