Reputation: 1137
I want to apply specific security rules to 2 URLs on my Spring Boot app.
I want to use AccessDecisionVoter feature to manage that.
All works good... event too good.
My new rules apply, on my 2 specific URL, but unfortunately on all my URLs.
My AccessDecisionManager declaration:
@Bean
public AccessDecisionManager playerResourceDecisionManager() {
List<AccessDecisionVoter<? extends Object>> decisionVoters = Arrays.asList(
new AuthenticatedVoter(),
hashSerialSecurityVoter
);
return new UnanimousBased(decisionVoters);
}
Here is my SecurityConfig main code
http.csrf()
.disable().cors().and().exceptionHandling()
// All Login Stuff
.authenticationEntryPoint(new Http403ForbiddenEntryPoint() {})
.and().authenticationProvider(getProvider())
.formLogin().loginProcessingUrl("/login")
.successHandler(new AuthentificationLoginSuccessHandler())
.failureHandler(new SimpleUrlAuthenticationFailureHandler())
.and().logout().logoutUrl("/logout")
.logoutSuccessHandler(new AuthentificationLogoutSuccessHandler())
.invalidateHttpSession(true).and().authorizeRequests()
...
// Spring boot actuator - App Status
.antMatchers("/actuator/*").permitAll()
// Static Token end points
.antMatchers("/my-filtered-url1", "/sub/my-filtered-url2/*")
.permitAll()
.accessDecisionManager(playerResourceDecisionManager())
/* Here is the problem :
* I want this accessDescisionManager apply only on my antMatchers
* (2 specific URLs),
* But it runs on every app calls.
*/
.antMatchers(HttpMethod.POST, "/log/*").permitAll()
/* Login */
.antMatchers("/login").permitAll()
.antMatchers("/auth/**").permitAll()
.antMatchers(HttpMethod.POST,"/user/lost-password").permitAll()
.antMatchers("/user").hasAuthority("ADMIN")
.anyRequest().authenticated();
I'd rather not putting specific code in my hashSerialSecurityVoter class with URL declaration. How can I do that ?
Regards.
Upvotes: 0
Views: 872
Reputation: 159185
The security config setup works like this:
http
is a builder (type HttpSecurity
).
When you call authorizeRequests()
, it gives you a 2nd builder (ExpressionInterceptUrlRegistry
).
When you call antMatchers()
, it gives you a 3rd builder (AuthorizedUrl
).
When you call permitAll()
, it returns you to the 2nd builder.
Which means you're calling accessDecisionManager()
on the *Registry
builder, not the AuthorizedUrl
builder, i.e. the call is global, unrelated to the matcher.
Your indentations are wrong and that's why you're confused:
.antMatchers("/my-filtered-url1", "/sub/my-filtered-url2/*")
.permitAll()
.accessDecisionManager(playerResourceDecisionManager())
The access manager and its underlying voters are not responsible for specifying which access rules should be applied to a particular URL, that is the job of access expression applied to the AuthorizedUrl
, e.g.
permitAll()
- Short for access("permitAll")
authenticated()
- Short for access("authenticated")
hasRole("ADMIN")
- Short for access("hasRole('ROLE_ADMIN')")
hasAuthority("HASHSERIAL")
- Short for access("hasAuthority('HASHSERIAL')")
. . .
So, if you want a custom AccessDecisionVoter
to vote on particular URLs, then you implement the supports(ConfigAttribute attribute)
method of the voter to recognize a particular attribute, you register the voter globally, and then specify that the particular URLs requires it:
.antMatchers("/my-filtered-url1", "/sub/my-filtered-url2/*")
.hasAuthority("HASHSERIAL")
class HashSerialSecurityVoter implements AccessDecisionVoter<Object> {
public boolean supports(ConfigAttribute attribute) {
if ((attribute.getAttribute() != null)
&& attribute.getAttribute().equals("HASHSERIAL")) {
return true;
}
else {
return false;
}
}
public boolean supports(Class<?> clazz) {
return true;
}
public int vote(Authentication authentication, Object object,
Collection<ConfigAttribute> attributes) {
// Your logic here
}
}
Upvotes: 1