Reputation: 1741
I would like to use @PreAuthorize annotations to secure methods in Spring REST controller, using method parameters, e.g.
@RequestMapping("/something/{myParam}")
@PreAuthorize("@security.check(#myParam)")
public String getSomething(@PathVariable("myParam") Integer myParam) {
//...
}
Spring Security needs a way to discover param names in runtime. When there is no debugging symbols in the compiled class, it is necessary to add a special annotation @P or Spring Data's @Param. So, the method would look like this:
@RequestMapping("/something/{myParam}")
@PreAuthorize("@security.check(#myParam)")
public String getSomething(@PathVariable("myParam") @P("myParam) Integer myParam) {
//...
}
Is it possible to somehow hint Spring Security to use @PathVariable instead and avoid additional annotations like @P?
According to the documentation reading parameter names from annotations is done by AnnotationParameterNameDiscoverer
which can be customized to support the value attribute of any specified annotation. However, I could not find any information on how to customize it.
BTW, I'm using Java 7 and Spring Security 3.2.9.
Upvotes: 9
Views: 6631
Reputation: 2167
Following configuration was not tested, but based on research of sources of spring security, so try to change your Spring Security configuration xml as follows
<security:global-method-security pre-post-annotations="enabled">
<security:expression-handler ref="expressionHandler"/>
</security:global-method-security>
<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">
<property name="parameterNameDiscoverer" ref="parameterNameDiscoverer"/>
</bean>
<bean id="parameterNameDiscoverer" class="org.springframework.security.core.parameters.AnnotationParameterNameDiscoverer">
<constructor-arg>
<list>
<value>org.springframework.web.bind.annotation.PathVariable</value>
</list>
</constructor-arg>
</bean>
Upvotes: 2
Reputation: 10404
From the official Spring security docs GlobalMethodSecurityConfiguration
Sometimes you may need to perform operations that are more complicated than are possible with the
@EnableGlobalMethodSecurity
annotation allow. For these instances, you can extend theGlobalMethodSecurityConfiguration
ensuring that the@EnableGlobalMethodSecurity
annotation is present on your subclass. For example, if you wanted to provide a customMethodSecurityExpressionHandler
, you could use the following configuration:
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
// ... create and return custom MethodSecurityExpressionHandler ...
return expressionHandler;
}
}
As in the above example you can write your custom MethodSecurityExpressionHandler
or use the DefaultMethodSecurityExpressionHandler
and set your custom ParameterNameDiscoverer extending the DefaultSecurityParameterNameDiscoverer (or not)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler expressionHandler = new DefaultMethodSecurityExpressionHandler();
expressionHandler.setParameterNameDiscoverer(new CustomParameterNameDiscoverer());
return expressionHandler;
}
}
One more example Spring Security Java Config Preview: Custom Method Security
Hope this helps.
Upvotes: 3
Reputation: 3601
From Spring security official documentation the requested usecase can be achieved . But to use you need to upgrade to spring 4.1.0, I didn't tried by looks like this is achievable
Upvotes: 0
Reputation: 416
In short, you need to override creating of SecurityExpressionHandler
in the method GlobalMethodSecurityConfiguration#createExpressionHandler
so that set your own ParameterNameDiscoverer
in custom GlobalMethodSecurityConfiguration
.
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MethodSecurityConfiguration extends GlobalMethodSecurityConfiguration {
@Autowired
private ApplicationContext context;
@Override
protected MethodSecurityExpressionHandler createExpressionHandler() {
DefaultMethodSecurityExpressionHandler result = new DefaultMethodSecurityExpressionHandler();
result.setApplicationContext(this.context);
result.setParameterNameDiscoverer(new AnnotationParameterNameDiscoverer(PathVariable.class.getName()));
return result;
}
}
In the sample project you can see result in console output something like this
2016-06-06 17:09:01.635 INFO 2871 --- [nio-8080-exec-4] c.s.so.q37435824.SecurityService: myParam value from PathVariable equals 1
Best regards
Upvotes: 5