I have custom authentication filter which creates PreAuthenticatedAuthenticationToken and stores it in security context. The filter works fine, it creates the token with the appropriate granted authorities "ROLE_user" and "ROLE_adminuser". Here's my config:
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
X509AuthenticationFilter filter = new X509AuthenticationFilter()
filter.setAuthenticationManager(authenticationManager())
http.addFilterAfter(filter, SecurityContextPersistenceFilter.class)
http.authorizeRequests().anyRequest().permitAll()
}
@Bean
public FilterRegistrationBean filterRegistrationBean() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean()
X509AuthenticationFilter filter = new X509AuthenticationFilter()
filter.setAuthenticationManager(authenticationManager())
registrationBean.setFilter(filter)
registrationBean.setEnabled(false)
return registrationBean
}
I'm inserting the Filter before the SecurityContextPersistenceFilter as mentioned in: Spring security and custom AuthenticationFilter with Spring boot.
This seems to work fine, however, when I attempt to add a PreAuthorize annotation to my controller method, like so:
@Controller
@RequestMapping("/security")
class SecurityController {
@RequestMapping("/authenticate")
@PreAuthorize("hasRole('ROLE_user')")
@ResponseBody
ResponseEntity<String> authenticate(HttpServletRequest request, Principal principal) {
println "authenticate: " + SecurityContextHolder.getContext().getAuthentication()
return new ResponseEntity<String>(getPreAuthenticatedPrincipal(request), HttpStatus.OK)
}
I get a 404 error. If I comment out the PreAuthorize annotation the method call works and you can see that I print out the authentication information and the authenticated user has ROLE_user and ROLE_adminuser for its granted authorities. I'm not sure what I'm doing wrong.
Here's the print out of the authentication object in the principal when "PreAuthorize" is commented out:
authenticate: org.springframework.security.web.authentication.preauth.PreAuthenticatedAuthenticationToken@817a0240: Principal: org.springframework.security.ldap.userdetails.LdapUserDetailsImpl@c279eab8: Dn: uid=1,ou=people,dc=cdpe,dc=mil; Username: [email protected]; Password: [PROTECTED]; Enabled: true; AccountNonExpired: true; CredentialsNonExpired: true; AccountNonLocked: true; Granted Authorities: ROLE_adminuser, ROLE_user; Credentials: [PROTECTED]; Authenticated: true; Details: org.springframework.security.web.authentication.WebAuthenticationDetails@957e: RemoteIpAddress: 127.0.0.1; SessionId: null; Granted Authorities: ROLE_adminuser, ROLE_user authorities: [ROLE_adminuser, ROLE_user]
Update: I've made a little progress. I added the proxyTargetClass to the following annotation:
@EnableGlobalMethodSecurity(prePostEnabled = true, proxyTargetClass = true)
Now I'm getting 403 Forbidden returns when I call my method. I have no idea what that is doing.
Method-level security is implemented by placing the @PreAuthorize annotation on controller methods (actually one of a set of annotations available, but the most commonly used). This annotation contains a Spring Expression Language (SpEL) snippet that is assessed to determine if the request should be authenticated.
The real difference is that @PreAuthorize can work with Spring Expression Language (SpEL). You can: Access methods and properties of SecurityExpressionRoot . (Advanced feature) Add your own methods (override MethodSecurityExpressionHandler and set it as <global-method-security><expression-handler ... /></...> ).
Spring Security has always been tedious to configure, and the only foolproof ways are:
For the configuration of an X509AuthenticationFilter
, HttpSecurity
javadoc gives the method x509
with following example (adapted to your config - see javadoc for original one) :
@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests().anyRequest().permitAll()
// Example x509() configuration
.x509();
}
}
with following indication: method returns the X509Configurer
for further customizations.
Unless you have a good reason to do differently (and if it is the case please say it) I strongly advise you to stick to that method.
But it is really a bad idea to use pre-post annotation on a controller, for what could be done directly in HttpSecurity
configuration. It forced you to use proxyTargetClass = true
.
Pre and post annotation are normally applied to methods of service layer what do not require proxyTargetClass=true
since services are normally wired to controller through interfaces allowing JDK proxying.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With