How do I restrict access to a URL using Spring security and a property from the spring security object?
Asked Answered
O

2

6

I'm using Spring 5.1 and Spring security 4.2. I'm configured access rules using an XML file. My question is, how do I write an intercept rule (access control to a URL) based on a property in the Spring security context? That is, I have a variable

productList

in the security context that is of type java.util.ArrayList. I would like to restrict access to a URL if this list is empty or null. How do I write this? I have

<http name="defaultSecurity" security-context-repository-ref="myContextRepository"
    auto-config="false" use-expressions="true" authentication-manager-ref="authenticationManager"
    entry-point-ref="loginUrlAuthenticationEntryPoint">
    ...
    <intercept-url pattern="/myurl" access="length(principal.productList) > 0" />
    ...
</http>

but of course, teh above

length(principal.productList) > 0   

expression is completely wrong. Is there a right way to write it?

Ostracize answered 6/9, 2018 at 20:52 Comment(3)
Try to read this how to write custom security expressionPeregrine
This link talks about customizing security using Java but I would like an option that only relies on an XML configuration file and no Java coding.Ostracize
This will be not possible since you do not have length method in the class that will evaluate the parts of expression out of the box and and in addition getProductList is not defined in common Principal class. See: documentation and javadoc WebSecurityExpressionRootPeregrine
A
2

Security related expressions have quite limited set of operations in Spring. You can extend this set by providing custom implementation of org.springframework.security.access.expression.SecurityExpressionOperations interface. Here is a brief guide how to do it:

  1. Create wrapper over SecurityExpressionOperations and implement desired operations:
class MySecurityExpressionOperations implements SecurityExpressionOperations {
    private SecurityExpressionOperations delegate;

    public MySecurityExpressionOperations(SecurityExpressionOperations delegate) {
        this.delegate = delegate;
    }

    public boolean hasProducts() {
        MyUser user = (MyUser) delegate.getAuthentication().getPrincipal();
        return !user.getProductList().isEmpty();
    }

    // Other methods
}
  1. Extend org.springframework.security.web.access.expression.WebExpressionVoter and replace standard expression handler:
class MyWebExpressionVoter extends WebExpressionVoter {
    public MyWebExpressionVoter() {
        setExpressionHandler(new DefaultWebSecurityExpressionHandler() {
            @Override
            protected SecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication, FilterInvocation fi) {
                SecurityExpressionOperations delegate = super.createSecurityExpressionRoot(authentication, fi);
                return new MySecurityExpressionOperations(delegate);
            }
        });
    }
 }
  1. Provide custom access decision manager:
<bean id="affirmativeBased" class="org.springframework.security.access.vote.AffirmativeBased">
    <constructor-arg>
        <list>
            <bean class="my.company.MyWebExpressionVoter"/>
        </list>
    </constructor-arg>
</bean>
  1. Apply custom access decision manager:
<http pattern="/**" use-expressions="true" access-decision-manager-ref="affirmativeBased">
    <!-- ... -->
</http>
  1. Protect one of URLs with additional security operation:
<intercept-url pattern="/products" access="hasProducts()"/>
Almswoman answered 9/9, 2018 at 19:28 Comment(0)
R
0

if you are looking a to check the number of elements in productList here is a workaround for that :

 <intercept-url pattern="/myurl" access="principal.productList.size() > 0" />
Repetend answered 9/9, 2018 at 18:18 Comment(2)
Gave this a go but no dice.Ostracize
don't suppose (T(your.pkg.Principal)principal).productList.size() > 0 wants to work?Superorganic

© 2022 - 2024 — McMap. All rights reserved.