Configuring Multiple Spring Security [duplicate] - spring-security

This question already has answers here:
Spring Security : Multiple HTTP Config not working
(2 answers)
Closed 1 year ago.
I have the following configuration:
#Configuration
#EnableWebSecurity
public class SecurityConfig {
#Configuration
#Order(1)
public static class SamlConfig extends WebSecurityConfigurerAdapter {
#Value("${enable_csrf}")
private Boolean enableCsrf;
#Autowired
private SamlUserService samlUserService;
public SamlWebSecurityConfig() {
super();
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/sso").permitAll()
.antMatchers("/saml/**").permitAll()
.anyRequest().authenticated()
.and()
.apply(saml())
.userDetailsService(samlUserService)
.serviceProvider()
.keyStore()
.storeFilePath("path")
.password("password")
.keyname("alias")
.keyPassword("password")
.and()
.protocol("https")
.hostname(String.format("%s:%s","localhost", "8080"))
.basePath("/")
.and()
.identityProvider()
.metadataFilePath("metadata");
if (!enableCsrf) {
http.csrf().disable();
}
}
}
#Configuration
#Order(2)
public static class BasicConfig extends WebSecurityConfigurerAdapter {
public BasicWebSecurityConfig() {
super();
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/basic").permitAll()
.anyRequest().authenticated();
if (!enableCsrf) {
http.csrf().disable();
}
}
}
This works for the SAML, but the basic login returns an error: 403 forbidden.
I modified the BasicConfig with this, and SAML doesn't work anymore but basic authentication works. All the endpoints are for both SAML and basic authentication, just different login page.
public static class BasicConfig extends WebSecurityConfigurerAdapter {
public BasicWebSecurityConfig() {
super();
}
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/secure/basic").permitAll()
.antMatchers("/**").permitAll()
.anyRequest().authenticated();
if (!enableCsrf) {
http.csrf().disable();
}
}
}
For some reasons sometimes it works, sometimes not. I also tried to modify the #Order and still not working.

In Spring Security, there are two things that are alike but do things completely differently, requestMatchers().antMatchers() and authorizeRequests().antMatchers().
The requestMatchers tells HttpSecurity to only invoke the SecurityFilterChain if the provided RequestMatcher was matched.
The authorizeRequests allows restricting access based upon the HttpServletRequest using RequestMatcher implementations.
In your case, you have two SecurityFilterChains. But only the one with the highest priority is being invoked, this happens because you did not give any requestMatchers to it, therefore it will match every request. And only one SecurityFilterChain is called per request, thus it will not invoke the next one.
So, you should inform the requestMatchers for your configurations, like so:
http
.requestMatchers((requests) -> requests
.antMatchers("/secure/sso", "/saml/**")
)
.authorizeRequests()
.antMatchers("/secure/sso").permitAll()
.antMatchers("/saml/**").permitAll()
.anyRequest().authenticated()
...
http
.requestMatchers((requests) -> requests
.antMatchers("/secure/basic", "/**")
)
.authorizeRequests()
.antMatchers("/secure/basic").permitAll()
.anyRequest().authenticated();

Related

Spring security SSO + Basic Authentication

I would like to able security like this in my application:
Protected by OAuth2 SSO:
/app/** ,/VAADIN/** ,/vaadinServlet/**
Protected by Basic Authentication:
/intergration/**
And the rest of resources are opened.
#Component
#EnableOAuth2Sso
public class SingleSignOnSecurity extends OAuth2SsoConfigurerAdapter {
#Override
public void match(RequestMatchers matchers) {
matchers.antMatchers("/app/**", "/VAADIN/**", "/vaadinServlet/**");
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable().logout().permitAll();
http.authorizeRequests().antMatchers("/app/**", "/VAADIN/**", "/vaadinServlet/**").authenticated();
}
}
#Component
public class HardCodedSecurity extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/integration/**").authenticated()
.and()
.httpBasic()
.and()
.csrf().disable()
.logout().permitAll();
}
}
If I put #Order on HardCodedSecurity class to be (SecurityProperties.ACCESS_OVERRIDE_ORDER + 1), then the SSO works, but not the Basic Auth. (SecurityProperties.ACCESS_OVERRIDE_ORDER - 1), then the Basic Auth works, but not the SSO. I can't get both of them to work as described.
I would be thankful if you can help me to the right path here. Thanks !

Can Spring Boot application have separate security for REST APIs?

We would like to apply Oauth2 based security for the Rest Controllers while the rest of the application will have Spring Security. Will that be possible? Can you provide any examples please?
It seems like WebSecurityConfigurerAdapter and ResourceServerConfigurerAdapter conflicting when both configured.
Thank you in advance.
Yes it's possible. Here the example template configuration code is given. Please change the required configs to your need. The key is to define Sub static classes of configuration with different order. Here i have considered any requests which is orginating from \api as a REST API call.
I have not checked the code by compiling it.
#Configuration
#EnableWebSecurity
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true, proxyTargetClass = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Order(1)
#Configuration
public static class ApiWebSecurityConfig extends OAuth2ServerConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
//Write the AuthenticationManagerBuilder codes for the OAuth
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable()
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().authenticated()
.and()
.apply(new OAuth2ServerConfigurer())
.tokenStore(new InMemoryTokenStore())
.resourceId(applicationName);
}
}
}
#Order(2)
#Configuration
public static class FormWebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
//Write the AuthenticationManagerBuilder codes for the Normal authentication
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable() //HTTP with Disable CSRF
.authorizeRequests() //Authorize Request Configuration
.anyRequest().authenticated()
.and() //Login Form configuration for all others
.formLogin()
.loginPage("/login").permitAll()
.and() //Logout Form configuration
.logout().permitAll();
}
}
}

Spring Boot + Security + Multi HTTP Web Configuration

I'm trying to do an example using spring-boot with spring security. My idea is to create a web app and also provide an API, I would like to both have security; so I need to create a multi http web security configuration however it is not working.
I followed this link http://docs.spring.io/spring-security/site/docs/3.2.x/reference/htmlsingle/#multiple-httpsecurity but no success. And, I'm getting this error
Error creating bean with name 'webSecurityConfiguration': Injection of autowired dependencies failed; nested exception is java.lang.IllegalStateException: Cannot apply org.springframework.security.config.annotation.authentication.configurers.provisioning.InMemoryUserDetailsManagerConfigurer to already built object
The configuration that I'm using is the following:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalAuthentication
#EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfiguration {
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("user").password("12345").roles("USER").and()
.withUser("admin").password("12345").roles("USER", "ADMIN");
}
#Configuration
#Order(1)
public static class ApiConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.antMatcher("/api/**")
.authorizeRequests()
.anyRequest().hasRole("ADMIN")
.and()
.httpBasic();
}
}
#Configuration
#Order(2)
public static class WebConfigurationAdapter extends
WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web
.ignoring()
.antMatchers("/resources/**");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout().permitAll();
}
}
}
Thanks in advance
after a lot of reading I found something that works for me:
#Configuration
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
#EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfiguration extends GlobalAuthenticationConfigurerAdapter {
#Resource(name = "customUserDetailsService")
protected CustomUserDetailsService customUserDetailsService;
#Resource
private DataSource dataSource;
#Autowired
protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService);
}
#Configuration
#Order(1)
public static class ApiConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Resource(name = "restUnauthorizedEntryPoint")
private RestUnauthorizedEntryPoint restUnauthorizedEntryPoint;
#Resource(name = "restAccessDeniedHandler")
private RestAccessDeniedHandler restAccessDeniedHandler;
#Override
protected void configure(HttpSecurity http) throws Exception {
SecurityConfigurer<DefaultSecurityFilterChain, HttpSecurity> securityXAuthConfigurerAdapter = new XAuthTokenConfigurer(
userDetailsServiceBean());
// #formatter:off
http
.antMatcher("/api/**").csrf().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.exceptionHandling()
.authenticationEntryPoint(restUnauthorizedEntryPoint)
.accessDeniedHandler(restAccessDeniedHandler)
.and()
.authorizeRequests()
.antMatchers(HttpMethod.POST, "/api/authenticate").permitAll()
.anyRequest().hasRole("ADMIN")
.and()
.apply(securityXAuthConfigurerAdapter);
// #formatter:on
}
}
#Configuration
#Order(2)
public static class WebConfigurationAdapter extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http
.authorizeRequests()
.antMatchers("/", "/home").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.loginPage("/login").permitAll()
.and()
.logout().permitAll()
;
// #formatter:on
}
}
}
I'm also faced the same issue. But I got it solved when I extend the WebSecurityConfiguration master class from WebSecurityConfigurerAdapter.
Kindly refer the following stackoverflow post in which you can find the full configuration.
Spring Security HTTP Basic for RESTFul and FormLogin for web - Annotations
I found I could solve this problem by annotating my class with
#EnableWebSecurity after reading this hint: https://github.com/spring-projects/spring-data-examples/issues/189#issuecomment-229552207

Using multiple WebSecurityConfigurerAdapter in spring boot

I'm having 2 classes which extends WebSecurityConfigurerAdapter. And can't make them work together.
The idea is as follows:
Have one WebSecurityConfigurerAdapter which only adds custom filter to security chain. The filter does some custom authentication and saves Authentication into SecurityContext. This generally works fine. Configured as follows (imports omitted):
#Order(1)
#Configuration
#EnableWebMvcSecurity
public class BestSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private BestPreAuthenticationFilter ssoAuthenticationFilter;
#Bean
protected FilterRegistrationBean getSSOAuthenticationFilter() {
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean(ssoAuthenticationFilter);
// Avoid include to the default chain
filterRegistrationBean.setEnabled(false);
return filterRegistrationBean;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(ssoAuthenticationFilter, SecurityContextPersistenceFilter.class);
}
#Configuration
protected static class AuthenticationConfiguration extends
GlobalAuthenticationConfigurerAdapter {
#Autowired
private BestAuthenticationProvider authenticationProvider;
#Override
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
}
I want the above to be kind of library class which anyone can include via #ComponentScan and get the custom authentication sorted. Obviously they want to provide custom HttpSecurity to secure edpoints. Trying something like:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/testUrl").hasRole("NON_EXISTING")
.anyRequest().authenticated();
}
}
Obviously the test URL should not be accessible as my user is not member of role NON_EXISTING. Unfortunatelly she is.
If I move the security authorizeRequests() part to the configuration class form 1. next to adding the security filter then it blocks the access as expected. But in my case it looks like the second configuration is ignored.
I also debugged the configure() methods and noticed that HttpSecurity is not the same object which smells a bit.
Any tips how can I make this work much appreciated.
Sum up of the goal:
have one WebSecurityConfigurerAdapter which adds the filter and is hidden from the user of the library
let the user define her own custom endpoint security
Spring boot 1.1.6-RELEASE
Define a special interface
public interface ServiceWebSecurityConfigurer {
void configure(HttpSecurity http) throws Exception;
}
Then have just one ConfigurerAdapter:
public class MyConfigurerAdapter extends WebSecurityConfigurerAdapter {
#Autowired(required = false)
ServiceWebSecurityConfigurer serviceSecConfig;
public void configure(HttpSecurity http) throws Exception {
http.authorizeRequests(). // whatever
if (serviceSecConfig != null) serviceSecConfig.configure(http);
http.authorizeRequests(). // whatever
}
}
and then just implement ServiceWebSecurityConfigurer elsewhere when needed. There can be multiple implementations as well, just autowire them as list and iterate and use them all in your main configuration.
So one option I just found is:
Remove the #Configuration annotation from the first bean
And change the 2. to:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true, prePostEnabled = true)
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
public class SecurityConfig extends BestSecurityConfig { //Note the changed extend !
#Override
protected void configure(HttpSecurity http) throws Exception {
super.configure(http); // Merge of the 2 HTTP configurations
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/testUrl").hasRole("NON_EXISTING")
.anyRequest().authenticated();
}
}
Any comments on whether this is right or wrong approach much appreciated
Edit: After few years I still didn't find other way but I like this way more and more. Even in the default case you extend the abstract WebSecurityConfigurerAdapter there is no reason why some other layer of abstraction can't provide another abstract extension which provides meaningful defaults.
I founded (in my opinion) a cleaner way of structuring some default configurations and make it simple to integrate in new projects by using Custom DSLs.
I'm using it to config JWT authentication filters, but i think a CORS filter is more simple and didactic:
public class CustomCorsFilterDsl extends AbstractHttpConfigurer<CustomCorsFilterDsl, HttpSecurity> {
#Override
public void init(HttpSecurity http) throws Exception {
//your init code here, no needed in this case
}
#Override
public void configure(HttpSecurity http) throws Exception {
CorsFilter corsFilter = corsFilter(corsProperties);
http.addFilterBefore(corsFilter, UsernamePasswordAuthenticationFilter.class);
}
private CorsFilter corsFilter(CorsProperties corsProperties) {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowCredentials(true);
config.addAllowedOrigin("http://localhost:9000");
config.addAllowedHeader("*");
config.addAllowedMethod("GET, POST, PUT, PATCH, DELETE");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
public static CustomCorsFilterDsl dsl() {
return new CustomCorsFilterDsl();
}
}
And in your WebSecurityConfig you can use it like this:
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.exceptionHandling()
.and()
.sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.authorizeRequests()
.antMatchers("/foo/**").permitAll()
//... your configurations
.antMatchers("/**").authenticated()
.and()
.apply(CustomCorsFilterDsl.dsl());
}
}
And you accomplished your objective of having libraries with default configurations independent of your projects code, in a more clear way, because you can visualize in the project's WebSecurityConfig a custom CORS entry.

need spring security java config example showing basic auth only

My current java security config looks as follows:
#Configuration
#EnableWebSecurity
public class RootConfig extends WebSecurityConfigurerAdapter {
#Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception
{
auth.inMemoryAuthentication()
.withUser("tester").password("passwd").roles("USER");
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
}
When I perform a GET request using a browser, I'll get an error 403.
I would expect to get a browser popup asking me for a username / password.
What might be the problem?
UPDATE: This is fixed in Spring Security 3.2.0.RC1+
This is a bug in the Security Java Configuration that will be resolved for the next release. I have created SEC-2198 to track it. For now, a work around is to use something like the following:
#Bean
public BasicAuthenticationEntryPoint entryPoint() {
BasicAuthenticationEntryPoint basicAuthEntryPoint = new BasicAuthenticationEntryPoint();
basicAuthEntryPoint.setRealmName("My Realm");
return basicAuthEntryPoint;
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.exceptionHandling()
.authenticationEntryPoint(entryPoint())
.and()
.authorizeUrls()
.anyRequest().authenticated()
.and()
.httpBasic();
}
PS: Thanks for giving Spring Security Java Configuration a try! Keep the feedback up :)
With Spring Security 4.2.3 and probably before you can simply use this configuration:
#Configuration
#EnableWebSecurity
public class CommonWebSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(final HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.httpBasic();
}
#Autowired
public void dlcmlUserDetails(final AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("tom").password("111").roles("USER");
}
}

Resources