Reputation: 43
I have a many @RestController
s with methods like:
@PreAuthorize("@myBean.myMethod(#param1, #param2)")
public void foo(String param1, Long param2) {}
And somewhere
@Component
public class MyBean {
public boolean myMethod(String param1, Long param2) {
return importantSecurityCheck();
}
}
It works very well, but I want to avoid possible stupid bugs after refactoring (because as far as I know spring doesn't detect error until method is invoked), so my idea was to write test which will check if expression is valid (e.g. parameters have same type and names are valid).
I tried to do something like this:
@Test
public void checkSecurityExpressions() {
Map<String, Object> beansWithAnnotation = applicationContext.getBeansWithAnnotation(RestController.class);
beansWithAnnotation.forEach((name, bean) -> {
Method[] methods = AopUtils.getTargetClass(bean).getMethods();
for (Method method : methods) {
PreAuthorize annotation = method.getAnnotation(PreAuthorize.class);
if (annotation != null) {
String securityExpression = annotation.value();
System.out.println(securityExpression);
}
}
});
}
Which finds expressions nicely, but all ExpressionParser
examples which I found work with simpler expressions (without security context, even without @
at the beginning).
How to check it's correctness? Or maybe there are better solutions for this problem?
Upvotes: 1
Views: 1547
Reputation: 174729
I had to write a test case like this recently to answer another stack overflow question.
Given:
public class Foo {
public boolean isOk(String param) {
return "good".equals(param);
}
@PreAuthorize("@foo.isOk(#param1)")
public String bar(String param1) {
return "authOk";
}
}
and a test @Configuration
class that extends GlobalAuthenticationConfigurerAdapter
:
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("foo").password("bar").roles("admin");
}
then:
@Autowired
private Foo foo;
@Test
public void test() {
SecurityContext ctx = SecurityContextHolder.createEmptyContext();
ctx.setAuthentication(new UsernamePasswordAuthenticationToken("foo", "bar"));
SecurityContextHolder.setContext(ctx);
assertThat(foo.bar("good")).isEqualTo("authOk");
try {
foo.bar("bad");
fail("Expected AccessDeniedException");
}
catch (AccessDeniedException e) {
// expected
}
}
Will validate your @PreAuthorize
SpEL.
Upvotes: 0