Question

(Sorry if this is a duplicate, but the question is very search-engine-unfriendly.)

I want to know how to evaluate Spring EL inside EL (with all the functions, variables, context, etc. passed through).

Specifically, I want to dynamically evaluate a Spring Security expression (which is just EL plus some functions and contexts) loaded from a database entity inside a hard-coded EL in @PreAuthorize.

I.e. something like @PreAuthorize("eval(argument.securityExpr)").

Was it helpful?

Solution

You can extend Springs MethodSecurityExpressionRoot (and create it in your own MethodSecurityExpressionHandler) and add an eval method which excepts a String and let the SpringExpressionParser evaluate the String. Should work...

Edit:

A little code:

public class MySpringSecurityRoot extends MethodSecurityExpressionRoot {
  private MyMethodSecurityExpressionHandler handler; // to be injected in the handler

  public boolean eval(String expression) {
    Expression expression = handler.getExpressionParser().parseExpression(expression);
    return ExpressionUtils.evaluateAsBoolean(
       handler.getExpressionParser().parseExpression(expression), 
         handler.createEvaluationContext(authentification, methodInvocation));
  }
}

your handler must be set as the default method security expression handler:

  <security:global-method-security pre-post-annotations="enabled">
    <security:expression-handler ref="myHandler"/>
  </security:global-method-security>

now your eval function is accessible in every method security expression

BUT: You must be aware of the fact that the person who describes your security rule, can access all beans inside the current spring context! Might be a security leak.

OTHER TIPS

If you use a simpleparametername discover with @ to evaluate permissions you can do virtually anything you want, without enabling debug mode.

@PreAuthorize("@mySecurityService.hasPermission(#arg0)")
public String getSpecial(final String special) {
        return "authorized";
}

mySecurityService can be any bean/method returning a boolean, with this wired up for arg1

 public class SimpleParameterNameDiscoverer implements ParameterNameDiscoverer {

        public String[] getParameterNames(Method m) {
            return getParameterNames(m.getParameterTypes().length);
        }

        public String[] getParameterNames(Constructor c) {
            return getParameterNames(c.getParameterTypes().length);
        }

        protected String[] getParameterNames(int length) {
            String[] names = new String[length];

            for (int i = 0; i < length; i++)
                names[i] = "arg" + i;

            return names;
        }


    }

and context :

<bean id="methodSecurityExpressionHandler"
          class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
        <property name="parameterNameDiscoverer">
            <bean class="your.path.SimpleParameterNameDiscoverer"/>
        </property>
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top