I'm writing a small application that has an authentication linked to a database, this authentication will be managed by the Oauth2 aspect (Classes annotated by @EnableAuthorizationServer and @EnableResourceServer). There's another authentication in the same application for an administration page that will be linked to another different database and will use the normal form-based authentication.
I've written the following Web Security configuration class for this specific purpose:
@Configuration
@EnableWebSecurity
public class WebSecurityConfig{
@Configuration
@Order(5)
public static class AdminSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.logout().logoutRequestMatcher(new AntPathRequestMatcher("/admin_logout"))
.invalidateHttpSession(true).logoutSuccessUrl("/admin/login.html");
http.authorizeRequests()
.antMatchers("/admin/login.html").permitAll().antMatchers("/admin/protected.html")
.hasRole("ADMIN")
.and().formLogin().loginPage("/admin/login.html")
.loginProcessingUrl("/admin_login").defaultSuccessUrl("/admin/protected.html");
}
@Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
//Data source for form based auth
auth.inMemoryAuthentication().withUser("adminuser").password("adminpassword").roles("ADMIN");
}
}
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
//Data source for Oauth
auth.inMemoryAuthentication().withUser("myuser").password("mypassword").roles("USER").and().withUser("test")
.password("testpassword").roles("USER");
}
}
Other relevant components are:
Authorization Server configuration:
@Configuration
@EnableAuthorizationServer
public class AuthorizationServerConfiguration extends AuthorizationServerConfigurerAdapter{
@Autowired
AuthenticationManager authenticationManager;
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).tokenEnhancer(tokenEnhancer())
.tokenStore(tokenStore());
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients
.inMemory()
.withClient("client")
.secret("secret")
.authorizedGrantTypes("password", "refresh_token")
.scopes("read", "write")
.resourceIds("resource").accessTokenValiditySeconds(60);
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception
{
oauthServer.checkTokenAccess("isAuthenticated()");
}
@Bean
public TokenEnhancer tokenEnhancer() {
return new CustomTokenEnhancer();
}
@Bean
public TokenStore tokenStore() {
return new InMemoryTokenStore();
}
}
Resource server configuration:
@Configuration
@EnableResourceServer
@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER-1)
public class ResourceServerConfiguration extends ResourceServerConfigurerAdapter{
@Autowired
TokenStore tokenStore;
@Override
public void configure(ResourceServerSecurityConfigurer resources) {
resources.resourceId("resource").tokenStore(tokenStore);
}
@Override
public void configure(final HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/api/**").authenticated();
}
}
You can also checkout the code here: https://github.com/cenobyte321/spring-oauth2-tokenenhancer-test/tree/webspeciallogin (Branch: webspeciallogin)
The problem is that everything in the AdminSecurityConfig class is ignored, I can go into the protected.html page without logging myself in and the login and logout processing urls specified aren't created.
The Oauth2 based login on the other hand works without a problem. I haven't also figured out how to specify in Oauth2 an AuthenticationManagerBuilder, most of online resources suggest to use the configureGlobal injected method which is read by Oauth appropriately, that's why it's setup like that in the code above.
How can I configure two authentication sources independent of one another in a single Oauth2-enabled application?
Regards.
You need two things:
AdminSecurityConfig
has a higher priority than your ResourceServerConfiguration
. While the @EnableResourceServer
annotation's documentation says it will register a WebSecurityConfigurerAdapter
with a hard-coded Order 3, it's actually overridden in ResourceServerOrderProcessor
with an order of -10. So make sure your AdminSecurityConfig
has an order lower than -10.Make sure you limit your configuration of HttpSecurity
in AdminSecurityConfig
with request matchers to the URLs associated with your admin server, like this:
http.requestMatchers().antMatchers("/admin/**", "/admin_login", "/admin_logout")
.and()
.authorizeRequests()
.antMatchers("/admin/protected.html").hasRole("ADMIN")
.antMatchers("/admin/login.html").permitAll()
.and()
.formLogin().loginPage("/admin/login.html")
.loginProcessingUrl("/admin_login")
.defaultSuccessUrl("/admin/protected.html")
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/admin_logout"))
.invalidateHttpSession(true).logoutSuccessUrl("/admin/login.html")
;
Note the first line of the embedded code with http.requestMatchers().antMatchers("/admin/**", "/admin_login", "/admin_logout")
.
See Dave Syer's (one of Spring Security authors) answer on a similar question for reference.
I made a pull request with the above fixes for your example project on github.
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