Spring Resource Server Multi-tenancy with BasicAuth - spring

So I tried Resource Server Multi-tenancy using Spring docs and
everything works fine, I can pass two different token to access my resource. My question is how do I add BasicAuth functionality to this. I want my resource to be accessible by either of the oauth2 tokens or BasicAuth. I have individual solutions but I am not able to combine both for some reason.
Working solution -> Resource server Multi-tenancy
#EnableWebSecurity
#Order(1)
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.httpBasic()
.disable()
.authorizeRequests(auth -> auth
.anyRequest().authenticated()
).oauth2ResourceServer(oauth2ResourceServer -> {
oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
});
}
//...
Working Solution -> Oauth and BasicAuth both to access same resource
I came across this solution which does this
https://stackoverflow.com/a/36243650/2188126
#EnableWebSecurity
#Order(1)
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatcher(new BasicRequestMatcher())
.authorizeRequests().anyRequest().authenticated()
.and()
.httpBasic()
.authenticationEntryPoint(new OAuth2AuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
//...
Here's what I have tried(and few other variations) but doesn't work. -> Multi-tenancy + Basic Auth
#EnableWebSecurity
#Order(1)
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.requestMatcher(new BasicRequestMatcher())
.authorizeRequests().anyRequest().authenticated()
.and()
.oauth2ResourceServer(oauth2ResourceServer -> {
oauth2ResourceServer.authenticationManagerResolver(this.authenticationManagerResolver);
})
.httpBasic()
.authenticationEntryPoint(new OAuth2AuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
//...
Here's my resource server config file
#Configuration
#EnableResourceServer
public class Oauth2SecurityConfiguration extends ResourceServerConfigurerAdapter {
#Override
public void configure(HttpSecurity http) throws Exception {
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers(AUTH_WHITELIST).permitAll()
.antMatchers(HttpMethod.OPTIONS, "/**").permitAll()
.anyRequest().authenticated();
}
}

Related

Hww to bind two SecurityFilterChain respectively? [duplicate]

I am trying to use Spring Security and I have a use case where I want different login pages and different set of URLs to be secured.
Here is my configuration:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
.formLogin()
.loginPage("/admin/login").permitAll()
.defaultSuccessUrl("/admin/home")
.failureUrl("/admin/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and()
.csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
#Configuration
#Order(2)
public static class ConsumerSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/consumer/login").permitAll()
.antMatchers("/consumer/**").access("hasRole('BASE_USER')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/consumer/login").permitAll()
.defaultSuccessUrl("/consumer/home")
.failureUrl("/consumer/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and().csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
These classes are inner classes of another class MultipleHttpSecurityConfig that has annotation #EnableWebSecurity.
The security for admin/** is working fine, but none of the consumer/** pages are secured, no redirection is happening for login page. I've searched for other answers but none worked.
Look at the Spring Security Reference:
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { 1
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Configuration
#Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration 4
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
1 Configure Authentication as normal
2 Create an instance of WebSecurityConfigurerAdapter that contains #Order to specify which WebSecurityConfigurerAdapter should be considered first.
3 The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /api/
4 Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This configuration is considered after ApiWebSecurityConfigurationAdapter since it has an #Order value after 1 (no #Order defaults to last).
Your second configuration is not used, because your first configuration matches /** (no antMatcher configured). And your first configuration restricts only /admin/**, all other URLs are permitted by default.
Your first WebSecurityConfigurerAdapter's
http
.authorizeRequests()
matches all the URLs, limit it to only URLs start with /admin by using antMatcher:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.authorizeRequests()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
...

Multiple authentication methods for one endpoint? [duplicate]

I am trying to use Spring Security and I have a use case where I want different login pages and different set of URLs to be secured.
Here is my configuration:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
.formLogin()
.loginPage("/admin/login").permitAll()
.defaultSuccessUrl("/admin/home")
.failureUrl("/admin/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and()
.csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
#Configuration
#Order(2)
public static class ConsumerSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/consumer/login").permitAll()
.antMatchers("/consumer/**").access("hasRole('BASE_USER')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/consumer/login").permitAll()
.defaultSuccessUrl("/consumer/home")
.failureUrl("/consumer/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and().csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
These classes are inner classes of another class MultipleHttpSecurityConfig that has annotation #EnableWebSecurity.
The security for admin/** is working fine, but none of the consumer/** pages are secured, no redirection is happening for login page. I've searched for other answers but none worked.
Look at the Spring Security Reference:
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { 1
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Configuration
#Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration 4
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
1 Configure Authentication as normal
2 Create an instance of WebSecurityConfigurerAdapter that contains #Order to specify which WebSecurityConfigurerAdapter should be considered first.
3 The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /api/
4 Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This configuration is considered after ApiWebSecurityConfigurationAdapter since it has an #Order value after 1 (no #Order defaults to last).
Your second configuration is not used, because your first configuration matches /** (no antMatcher configured). And your first configuration restricts only /admin/**, all other URLs are permitted by default.
Your first WebSecurityConfigurerAdapter's
http
.authorizeRequests()
matches all the URLs, limit it to only URLs start with /admin by using antMatcher:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.authorizeRequests()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
...

Spring multiple authentication methods for different api endpoints

I want to check for different authentication methods for different endpoints. Methods i want to use are x509 and jwt. I need to use only x509 for certain endpoint and use JWT for all other requests.
Here's my web security configuration:
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/api/transaction/testf").authenticated().and()
.x509()
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(new X509UserDetailsService())
;
}
}
#Configuration
#Order(2)
public static class ApiTokenSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/oauth/token", "/api/dealer/login").permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
;
}
}
}
This configuration only checks /api/transaction/testf endpoint for x509 certificate and allows all other endpoints to respond. I need other endpoints to return 503 without a jwt token.
You have two filter chains. Neither of them have an entry point pattern properly configured http.antMatcher. That means they are configured to use /** as their entry point pattern.
For example
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().fullyAuthenticated()
is the same thing as saying:
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**")
.authorizeRequests()
.anyRequest().fullyAuthenticated()
What we are saying here is
http - the security filter chain
http.antMatcher - the entry point to the security filter chain
http.authorizeRequests - start of my endpoint access restrictions
http.authorizeRequests.antMatchers - list of URLs with specific access
So what you need to do is change your #Order(1) filter chain to narrow down the pattern. For example: http.antMatcher("/api/transaction/**")
Your configuration will now look like
#Configuration
#Order(1)
public static class ApiWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/transaction/**") //customized entry point
.authorizeRequests()
.antMatchers("/api/transaction/testf").authenticated().and()
.x509()
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(new X509UserDetailsService())
;
}
}
#Configuration
#Order(2)
public static class ApiTokenSecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/**") //this is default
.authorizeRequests()
.antMatchers("/oauth/token", "/api/dealer/login").permitAll()
.and()
.authorizeRequests()
.anyRequest()
.authenticated()
;
}
With your existing configuration the filter chain named ApiWebSecurityConfig will trap all calls. The other filter chain, ApiTokenSecurityConfig, is never used.
Since WebSecurityConfigurerAdapter is #Deprecated, preferable use multiple SecurityFilterChain (see updated Multiple HttpSecurity):
#Bean
#Order(1)
public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeHttpRequests(authorize -> authorize
.anyRequest().hasRole("ADMIN")
)
.httpBasic(withDefaults());
return http.build();
}
#Bean
public SecurityFilterChain formLoginFilterChain(HttpSecurity http) throws Exception {
http
.authorizeHttpRequests(authorize -> authorize
.anyRequest().authenticated()
)
.formLogin(withDefaults());
return http.build();
}

multiple entry points in spring security

I have a spring boot application that should allow form based authentication against database and SSO CAS based authentication.
I have followed the example from here (https://www.baeldung.com/spring-security-multiple-entry-points) and seems to me that Order is not working as expected. it is always using the one that is annotated as Order(1) as entry point.
here is my code,
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Configuration
#Order(2)
public static class WebSecurityCASConfig extends WebSecurityConfigurerAdapter {
public WebSecurityCASConfig() {
super();
}
#Autowired
private AuthenticationEntryPoint authenticationEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/js/**",
"/css/**",
"/images/**").permitAll()
.regexMatchers("/login1")
.authenticated()
.and()
.authorizeRequests()
.and()
.httpBasic()
.authenticationEntryPoint(authenticationEntryPoint);
}
}
//second
#Configuration
#Order(1)
public static class WebSecurityDatabaseConfig extends WebSecurityConfigurerAdapter {
public WebSecurityDatabaseConfig() {
super();
}
#Autowired
UserDetailServiceImpl userDetailsService;
#Autowired
BCryptPasswordEncoder passwordEncoder;
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService)
.passwordEncoder(passwordEncoder);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers(
"/js/**",
"/css/**",
"/images/**").permitAll()
//.antMatchers("/catalog").access("hasAnyRole('ROLE_USER', 'ROLE_ADMIN')")
////.antMatchers("/login1").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login")
.defaultSuccessUrl("/catalog", true)
.permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and()
.logout()
.permitAll()
.logoutUrl("/logout").logoutSuccessUrl("/logout")
.and().exceptionHandling().accessDeniedPage("/403");
}
}
}
I want both configurations work based on url pattern. Any solutions/help/suggestions would be highly appreciated. Thanks.
I found a solution for this. I just simply followed what the spring document says in 5.9 (https://docs.spring.io/spring-security/site/docs/5.0.0.RELEASE/reference/htmlsingle/) and also another question on stackoverflow, Spring Security : Multiple HTTP Config not working

Configuring Spring Security for Form Login AND RESTful API [duplicate]

I am trying to use Spring Security and I have a use case where I want different login pages and different set of URLs to be secured.
Here is my configuration:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
.formLogin()
.loginPage("/admin/login").permitAll()
.defaultSuccessUrl("/admin/home")
.failureUrl("/admin/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and()
.csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
#Configuration
#Order(2)
public static class ConsumerSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/consumer/login").permitAll()
.antMatchers("/consumer/**").access("hasRole('BASE_USER')")
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/consumer/login").permitAll()
.defaultSuccessUrl("/consumer/home")
.failureUrl("/consumer/login?error=true").permitAll()
.usernameParameter("username")
.passwordParameter("password")
.and().csrf()
.and()
.exceptionHandling().accessDeniedPage("/Access_Denied");
}
}
These classes are inner classes of another class MultipleHttpSecurityConfig that has annotation #EnableWebSecurity.
The security for admin/** is working fine, but none of the consumer/** pages are secured, no redirection is happening for login page. I've searched for other answers but none worked.
Look at the Spring Security Reference:
#EnableWebSecurity
public class MultiHttpSecurityConfig {
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) { 1
auth
.inMemoryAuthentication()
.withUser("user").password("password").roles("USER").and()
.withUser("admin").password("password").roles("USER", "ADMIN");
}
#Configuration
#Order(1) 2
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**") 3
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration 4
public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.formLogin();
}
}
}
1 Configure Authentication as normal
2 Create an instance of WebSecurityConfigurerAdapter that contains #Order to specify which WebSecurityConfigurerAdapter should be considered first.
3 The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /api/
4 Create another instance of WebSecurityConfigurerAdapter. If the URL does not start with /api/ this configuration will be used. This configuration is considered after ApiWebSecurityConfigurationAdapter since it has an #Order value after 1 (no #Order defaults to last).
Your second configuration is not used, because your first configuration matches /** (no antMatcher configured). And your first configuration restricts only /admin/**, all other URLs are permitted by default.
Your first WebSecurityConfigurerAdapter's
http
.authorizeRequests()
matches all the URLs, limit it to only URLs start with /admin by using antMatcher:
#Configuration
#Order(1)
public static class ProviderSecurity extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/admin/**")
.authorizeRequests()
.antMatchers("/admin/login").permitAll()
.antMatchers("/admin/**").access("hasRole('BASE_USER')")
.and()
...

Resources