I am trying to configure security for 2 end points /api and /admin.
For /api i want to secure with jwt token based mechanism which is stateless and for /admin i want to have form based login.
following others already found on Spring security oauth2 and form login configuration i tried to configure it.
which leads me to either my /admin is secured or /api is secure based on @Order i set for my config.
Some how the ordering has no effect with integer value. Had to set it with org.springframework.core.Ordered then only the resource server config get priority
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.core.Ordered;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.DefaultTokenServices;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JdbcTokenStore;
@EnableWebSecurity
public class MultiHttpSecurityConfig {
@Autowired
private CustomUserDetailsService userDetailsService;
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Autowired
public void configAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
}
@Configuration
@EnableWebSecurity
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
Logger logger = LoggerFactory.getLogger(ApiWebSecurityConfigurationAdapter.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("\n---------\n m here ApiWebSecurityConfigurationAdapter\n---------\n");
http.authorizeRequests().antMatchers("/api/**").hasRole("USER").and().formLogin();
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
@Order(1)
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
Logger logger = LoggerFactory.getLogger(FormLoginWebSecurityConfigurerAdapter.class);
@Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("\n---------\n m here FormLoginWebSecurityConfigurerAdapter\n---------\n");
http.csrf().disable().authorizeRequests().antMatchers("/admin/**")
.hasAnyAuthority("admin", "ADMIN_USER").and().formLogin().permitAll().and().logout().permitAll();
}
}
@Configuration
@EnableResourceServer
@Order(2)
public class CustomResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {
Logger logger = LoggerFactory.getLogger(CustomResourceServerConfigurerAdapter.class);
@Autowired
private JdbcTemplate jdbcTemplate;
@Bean
public TokenStore tokenStore() {
return new JdbcTokenStore(jdbcTemplate.getDataSource());
}
@Bean
@Primary
//Making this primary to avoid any accidental duplication with another token service instance of the same name
public DefaultTokenServices tokenServices() {
DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
defaultTokenServices.setTokenStore(tokenStore());
defaultTokenServices.setSupportRefreshToken(true);
return defaultTokenServices;
}
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.tokenServices(tokenServices());
}
@Override
public void configure(HttpSecurity http) throws Exception {
logger.info("\n---------\n m here CustomResourceServerConfigurerAdapter\n---------\n");
http.authorizeRequests()
.and()
.anonymous().disable()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and().httpBasic()
.and()
.authorizeRequests()
.antMatchers("/api/**").fullyAuthenticated();
}
}
}
and my OAuth2Configuration
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.oauth2.config.annotation.configurers.ClientDetailsServiceConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configuration.AuthorizationServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableAuthorizationServer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerEndpointsConfigurer;
import org.springframework.security.oauth2.config.annotation.web.configurers.AuthorizationServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter;
@Configuration
@EnableAuthorizationServer
public class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {
@Autowired
private AuthenticationManager authenticationManager;
@Autowired
private JdbcTemplate jdbcTemplate;
@Autowired
private CustomUserDetailsService userDetailsService;
@Autowired
private TokenStore tokenStore;
@Bean
public JwtAccessTokenConverter accessTokenConverter() {
return new JwtAccessTokenConverter();
}
@Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
oauthServer.tokenKeyAccess("hasAuthority('ROLE_TRUSTED_CLIENT')")
.checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");
}
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints
.tokenStore(tokenStore)
.reuseRefreshTokens(false)
.authenticationManager(authenticationManager)
.accessTokenConverter(accessTokenConverter())
.userDetailsService(userDetailsService);
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
clients.jdbc(jdbcTemplate.getDataSource());
}
}
I expect securing both endpoint i.e /api with jwt token and /admin with form based login. I don't want to implement 2 different project for Rest API and for UI
Edit
thanks @dur that was eye opening
i was able to secure my rest api with
@Override
public void configure(HttpSecurity http) throws Exception {
logger.info("\n---------\n m here CustomResourceServerConfigurerAdapter\n---------\n");
http
.antMatcher("/api/**")
.authorizeRequests()
.antMatchers("/api/**" ).authenticated();
}
but i am unable to secure my /admin except with httpBasic
Would be very helpfull if anyone can tell me how to configure form login
@Override
protected void configure(HttpSecurity http) throws Exception {
logger.info("\n---------\n m here FormLoginWebSecurityConfigurerAdapter\n---------\n");
http
.antMatcher("/admin/**")
.authorizeRequests()
.anyRequest().hasAnyAuthority("ADMIN_USER")
.and()
.httpBasic();
}
I tried
http.antMatcher("/admin/**").authorizeRequests()
.antMatchers("/admin/**").hasAnyAuthority("ADMIN_USER")
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
But it didn't work
Edit 2
finally got it
http
.antMatcher("/admin/**")
.authorizeRequests()
.anyRequest().hasAnyAuthority("ADMIN_USER")
.and()
.formLogin()
.loginPage("/admin/login")
.permitAll()
.and()
.logout()
.logoutUrl("/admin/logout")
.invalidateHttpSession(true)
.permitAll();
http.csrf().disable();