I am looking for a way to secure methods with the @Secured
annotation of Spring Boot. For about 10-15 users, I wouldn't want to connect to a database and obtain the users and their authorities/roles from there but rather store them locally in the profile-specific application.yml
file. Is there a concept in Spring Boot supporting this idea? All I could find so far works with the basic security actuator ('org.springframework.boot:spring-boot-starter-security'
) and looks like this:
security:
basic:
enabled: true
user:
name: admin
password: admin
role: EXAMPLE
However, I'm still able to access a method annotated with @RolesAllowed("READ")
even though I would assume that user admin shouldn't have access to said method. My SecurityConfiguration looks like this:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(jsr250Enabled = true)
@Profile("secure")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.anyRequest()
.fullyAuthenticated()
.and()
.httpBasic();
http.sessionManagement()
.sessionFixation()
.newSession();
http.csrf().disable();
http.headers().frameOptions().disable();
}
}
Eventually this might be a different issue but maybe it's important for my own understanding.
I'm wondering how I could specify multiple users with different passwords and different roles in my application.yml
and annotate methods to ensure only authorized users can access the methods.
It can be achieved with custom ConfigurationProperties
:
@ConfigurationProperties("application")
public class ApplicationClients {
private final List<ApplicationClient> clients = new ArrayList<>();
public List<ApplicationClient> getClients() {
return this.clients;
}
}
@Getter
@Setter
public class ApplicationClient {
private String username;
private String password;
private String[] roles;
}
@Configuration
@EnableConfigurationProperties(ApplicationClients.class)
public class AuthenticationManagerConfig extends
GlobalAuthenticationConfigurerAdapter {
@Autowired
ApplicationClients application;
@Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
for (ApplicationClient client : application.getClients()) {
auth.inMemoryAuthentication()
.withUser(client.getUsername()).password(client.getPassword()).roles(client.getRoles());
}
}
}
and then you can specify the users in your application.yml
:
application:
clients:
- username: rw
password: rw
roles: READ,WRITE
- username: r
password: r
roles: READ
- username: w
password: w
roles: WRITE
don't forget to add spring-boot-configuration-processor
to your build.gradle
:
compile 'org.springframework.boot:spring-boot-configuration-processor'
For Spring Boot 2.0, I use the following class:
@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableWebSecurity
@ConditionalOnWebApplication
@EnableConfigurationProperties(ApplicationClients.class)
@RequiredArgsConstructor
@Slf4j
public class SecurityConfig extends WebSecurityConfigurerAdapter {
private final ApplicationClients application;
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.authorizeRequests()
.requestMatchers(EndpointRequest.to("health")).permitAll()
.requestMatchers(EndpointRequest.toAnyEndpoint()).hasRole("ACTUATOR")
.antMatchers("/rest/**").authenticated()
.antMatchers("/soap/**").authenticated()
.and()
.cors()
.and()
.httpBasic();
}
@Bean
public InMemoryUserDetailsManager inMemoryUserDetailsManager() {
final InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
log.info("Importing {} clients:", application.getClients().size());
application.getClients().forEach(client -> {
manager.createUser(User.withDefaultPasswordEncoder()
.username(client.getUsername())
.password(client.getPassword())
.roles(client.getRoles())
.build());
log.info("Imported client {}", client.toString());
});
return manager;
}
}
Please keep in mind that User.withDefaultPasswordEncoder()
is marked deprecated because of security-concerns.