I need to dynamically create/remove roles and AntMatcherPattern for these roles.
Imagine that the ADMIN of the application wants to create a new role like “Accountant junior” and give to this role these access:
GET – “/accounts”
POST – “/accounts”
The ADMIN do that and then see that the “Accountant Junior” cannot create new accounts, so the ADMIN need to be able to remove the:
POST – “/accounts”.
I currently have the Authority.java:
@Entity
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class Authority implements GrantedAuthority {
@Id
@JsonProperty(access = JsonProperty.Access.READ_ONLY)
@GeneratedValue(strategy = GenerationType.UUID)
private UUID id;
private String pattern;
private String role;
@Override
public String getAuthority() {
return this.role;
}
}
This is my SecurityFilterChain
configuration:
@EnableWebSecurity
public class AuthConfig {
private final JwtAuthenticationFilter jwtAuthFilter;
private final AuthenticationProvider authenticationProvider;
@Bean
@Order(Ordered.HIGHEST_PRECEDENCE + 1)
public SecurityFilterChain securityFilterChain(HttpSecurity http, AccessRuleAuthorizationManager access) throws Exception {
http
.csrf(AbstractHttpConfigurer::disable)
.headers(headers -> headers.frameOptions(HeadersConfigurer.FrameOptionsConfig::sameOrigin))
.authorizeHttpRequests(requests -> {
requests.requestMatchers("/auth/authenticate").permitAll()
.anyRequest().access(access);
})
.sessionManagement( session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
.authenticationProvider(authenticationProvider)
.addFilterBefore(jwtAuthFilter, UsernamePasswordAuthenticationFilter.class);
return http.build();
}
}
As you can see, I have the AccessRuleAuthorizationManager.java
class:
@Component
@RequiredArgsConstructor
public class AccessRuleAuthorizationManager implements AuthorizationManager<RequestAuthorizationContext> {
private final AuthorityRepository rules;
private RequestMatcherDelegatingAuthorizationManager delegate;
@Override
public AuthorizationDecision check(Supplier<Authentication> authentication, RequestAuthorizationContext object) {
return this.delegate.check(authentication, object.getRequest());
}
@EventListener
void applyRules(ApplicationReadyEvent event) {
RequestMatcherDelegatingAuthorizationManager.Builder builder = builder();
for (Authority rule : this.rules.findAll()) {
builder.add(
new AntPathRequestMatcher(rule.getPattern()),
AuthorityAuthorizationManager.hasAuthority(rule.getRole())
);
}
this.delegate = builder.build();
}
}
The problem here is that these rules are applied only on Application Ready Event
.
I could create an Http endpoint that call this method, or even add an @PostPersist
listener on Authority.java
… but doesn’t seems right.
Is there a native solution? Or do you have an elegant solution for that?