difference between global authentication and local authentication in spring security - spring

Hello GUYS I am new in spring security, I found article about authentication global (#Autowired configure) and local authentication (#Override configure)
could you tell me what is the difference between #Autowired configure() and #Override configure.
//Global
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin#password").roles("ROLE_ADMIN");
}
}
//local
#Configuration
#EnableWebSecurity
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.inMemoryAuthentication()
.withUser("admin").password("admin#password").roles("ROLE_ADMIN");
}
}

One way of looking at it is that the global AuthenticationManager is "global" because it can be shared across the application as a bean, so when you #Autowire an AuthenticationManager, you must be configuring the global AuthenticationManager. If not, the AuthenticationManager you configure locally as you do above will only exist within the context of your WebSecurityConfigurerAdapter.
Take a look at this guide in the Spring website.

The Authentication and Access Control guide ( the same NatFar has provided link to) describes the following
Sometimes an application has logical groups of protected resources
(e.g. all web resources that match a path pattern /api/**), and each
group can have its own dedicated AuthenticationManager. Often, each of
those is a ProviderManager, and they share a parent. The parent is
then a kind of "global" resource, acting as a fallback for all
providers.
The image depicts the global (parent) and local resources , which is self explanatory
Also go through the links :
https://github.com/spring-projects/spring-security/issues/4571
https://github.com/spring-projects/spring-security/issues/4324

Related

spring boot using 2 different oauth providers at the same time

I'm facing a use where I have to check oauth token against 2 different oauth provider given an input context (private call to may api vs public call)
Is there a simple way to define 2 oauth provider in spring boot and how to configure this balancing between the 2 providers ?
First you will need to implement 2 AuthenticationProvider then in your configuration class that implements WebSecurityConfigurerAdapter you would autowire those providers. Finally override the public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception { to add those providers.
#Configuration
public class SampleAuthConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
private CustomAuthenticationProvider1 provider1;
#Autowired
private CustomAuthenticationProvider2 provider2;
#Override
public void configure(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
authenticationManagerBuilder
.authenticationProvider(this.provider1)
.authenticationProvider(this.provider2);
}
}
Below are some tutorials. The may be outdated but may help you to figure it out.
https://dzone.com/articles/spring-security-authentication
https://www.baeldung.com/spring-security-multiple-auth-providers

Spring Security : configure(AuthenticationManagerBuilder auth) vs authenticationManagerBean()

I am configuring Spring Security. To authenticate and authorize users, I override configure(AuthenticationManagerBuilder auth) of WebSecurityConfigurerAdapter. This works fine. Below is my code:
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.userDetailsService(customUserDetailsService)
.passwordEncoder(getPasswordEncoder());
}
But when I try to to enable method level security, per action, using #EnableGlobalMethodSecurity(securedEnabled = true) it throws an exception:
No AuthenticationManager found
As per my understanding AuthenticationManager is used to authenticate and authorize users, which I was already doing using configure(AuthenticationManagerBuilder auth) and Spring was injecting auth object itself.
Why I need to register AuthenticationManager manually?
#Bean #Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
What are the differennt purposes configure(AuthenticationManagerBuilder auth) and authenticationManagerBean() serves?
I am extending WebSecurityConfigurerAdapter. Why I need to provide a custom AuthenticationManager by overriding authenticationManagerBean().
Your configuration class extends WebSecurityConfigurerAdapter, which only configures web security (not method security):
Provides a convenient base class for creating a WebSecurityConfigurer instance. The implementation allows customization by overriding methods.
So your AuthenticationManager is only used for web security.
If you want to configure (change the defaults) method security, you can extend GlobalMethodSecurityConfiguration:
Base Configuration for enabling global method security. Classes may extend this class to customize the defaults, but must be sure to specify the EnableGlobalMethodSecurity annotation on the subclass.
To configure AuthenticationManager for method security, you can
overwrite GlobalMethodSecurityConfiguration#configure:
Sub classes can override this method to register different types of authentication. If not overridden, configure(AuthenticationManagerBuilder) will attempt to autowire by type.
expose your AuthenticationManager as a bean that can be autowired by GlobalMethodSecurityConfiguration, see WebSecurityConfigurerAdapter#authenticationManagerBean:
Override this method to expose the AuthenticationManager from configure(AuthenticationManagerBuilder) to be exposed as a Bean.
use only one global AuthenticationManager by autowiring the global AuthenticationManagerBuild, see Spring Security 3.2.0.RC2 Released:
For example, if you want to configure global authentication (i.e. you only have a single AuthenticationManager) you should autowire the AuthenticationMangerBuilder:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) {
// ... configure it ...
}

Spring Boot setup with multiple authentication providers (API+Browser)

My application serves both API and browser. I've implemented API Token authentication with all custom providers and filter. The configuration now seems to interfere with the browser version.
I have two questions that I need advice on how to solve, as I'm not getting anywhere after digging through the documentation and other examples.
1) My StatelessAuthenticationFilter is being called despite a request
coming from the browser. I have e.g. specified the request matcher to "/api/**". Why is that?
2) The AuthenticationManager have not registered two AuthenticationProviders. This is my conclusion after debugging my StatelessAuthenticationFilter that's being called wrongly.
Here's the configuration classes that I have
#Configuration
#EnableWebSecurity
public class WebSecurityConfig {
#Order(1)
#Configuration
public static class A extends WebSecurityConfigurerAdapter {
#Autowired
TokenAuthenticationProvider tokenAuthenticationProvider;
#Autowired
ApiEntryPoint apiEntryPoint;
#Override
protected void configure(HttpSecurity http) throws Exception {
StatelessAuthenticationFilter filter = new StatelessAuthenticationFilter();
AntPathRequestMatcher requestMatcher = new AntPathRequestMatcher("/api/**");
filter.setRequiresAuthenticationRequestMatcher(requestMatcher);
filter.setAuthenticationManager(super.authenticationManager());
http.csrf().disable()
.exceptionHandling().authenticationEntryPoint(apiEntryPoint)
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
.and()
.addFilterBefore(filter, UsernamePasswordAuthenticationFilter.class);
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAuthenticationProvider);
}
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/api/user/register");
}
}
#Configuration
public static class B extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new DaoAuthenticationProvider());
}
}
}
As you can see, B class doesn't specify anything, yet when I access localhost:8080 the StatelessAuthenticationFilter is called. What is going on here?
In class A you are configuring the StatelessAuthenticationFilter to use a requestMatcher. Whatever you do with that, spring does not know or care about that.
You must also restrict your security configuration using
http.antMatcher("/api/**")
otherwise its configured for every URI and the StatelessAuthenticationFilter will be invoked for every request, exactly as you described.
You should also annotate class A and B with #Order as shown in the example at multiple-httpsecurity

spring security not able to add custom authentication providers

I have created additional authentication providers. I am registering them like following:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalMethodSecurity(prePostEnabled = true)
class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAP());
auth.authenticationProvider(usernameAndPasswordAP());
auth.userDetailsService(getUserDetailsService());
}
Later in my code I am using AuthenticationManager to authenticate users. The issue is that I have only one authentication provider registered in authentication manager which is DaoAuthenticationProvider. It looks like my authentication providers are not registered at all. Should I do some additional config to make it work? I am using spring boot 1.2.6 Thanks in advance for any tips. Best Regards
When you override the configure(AuthenticationManagerBuilder auth), the underlying AuthenticationManager is exposed in one of 2 ways:
1) within SecurityConfig, you can simply call authenticationManager()
2) if you need AuthenticationManager outside of your SecurityConfig you will need to expose it as a bean, for example:
class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAP());
auth.authenticationProvider(usernameAndPasswordAP());
auth.userDetailsService(getUserDetailsService());
}
#Bean
#Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
The way we have authentication providers configured in our Spring Boot web applications is similar to what is discussed in the example Spring Security Java configuration from the current release reference guide, which modifies the default autowired AuthenticationManagerBuilder. Using your methods, it might look like:
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(tokenAP())
.authenticationProvider(usernameAndPasswordAP())
.userDetailsService(getUserDetailsService());
}
If I am reading the Javadocs for the configure(AuthenticationManagerBuilder) method correctly, when you override this method you must specify your own AuthenticationManager. By using the autowired instance as described above, the default AuthenticationManager (which is ProviderManager, which in turn delegates to one or more configured AuthorizationProvider instances).
You may also need to annotate your configuration class with:
#Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
So that your access control rules are applied before the defaults that Spring Boot will otherwise configure for you.

Multiple WebSecurityConfigurerAdapter: one as a library, in the other users can add their own security access

I am creating a Spring Security configuration to be used as a library by any developer who wants to create a Stormpath Spring application secured by Spring Security.
For that I have sub-classed WebSecurityConfigurerAdapter and defined the Stormpath Access Controls in configure(HttpSecurity) as well as the Stormpath AuthenticationProvider by means of configure(AuthenticationManagerBuilder). All this can be seen in this abstract class and its concrete sub-class:
#Order(99)
public abstract class AbstractStormpathWebSecurityConfiguration extends WebSecurityConfigurerAdapter {
//Removed properties and beans for the sake of keeping focus on the important stuff
/**
* The pre-defined Stormpath access control settings are defined here.
*
* #param http the {#link HttpSecurity} to be modified
* #throws Exception if an error occurs
*/
protected void configure(HttpSecurity http, AuthenticationSuccessHandler successHandler, LogoutHandler logoutHandler)
throws Exception {
if (loginEnabled) {
http
.formLogin()
.loginPage(loginUri)
.defaultSuccessUrl(loginNextUri)
.successHandler(successHandler)
.usernameParameter("login")
.passwordParameter("password");
}
if (logoutEnabled) {
http
.logout()
.invalidateHttpSession(true)
.logoutUrl(logoutUri)
.logoutSuccessUrl(logoutNextUri)
.addLogoutHandler(logoutHandler);
}
if (!csrfProtectionEnabled) {
http.csrf().disable();
} else {
//Let's configure HttpSessionCsrfTokenRepository to play nicely with our Controllers' forms
http.csrf().csrfTokenRepository(stormpathCsrfTokenRepository());
}
}
/**
* Method to specify the {#link AuthenticationProvider} that Spring Security will use when processing authentications.
*
* #param auth the {#link AuthenticationManagerBuilder} to use
* #param authenticationProvider the {#link AuthenticationProvider} to whom Spring Security will delegate authentication attempts
* #throws Exception if an error occurs
*/
protected void configure(AuthenticationManagerBuilder auth, AuthenticationProvider authenticationProvider) throws Exception {
auth.authenticationProvider(authenticationProvider);
}
}
#Configuration
public class StormpathWebSecurityConfiguration extends AbstractStormpathWebSecurityConfiguration {
//Removed beans for the sake of keeping focus on the important stuff
#Override
protected final void configure(HttpSecurity http) throws Exception {
configure(http, stormpathAuthenticationSuccessHandler(), stormpathLogoutHandler());
}
#Override
protected final void configure(AuthenticationManagerBuilder auth) throws Exception {
configure(auth, super.stormpathAuthenticationProvider);
}
}
In short, we are basically defining our login and logout mechanisms and integrating our CSRF code to play nicely with Spring Security's one.
Up to this point everything works OK.
But this is just the "library" and we want users to build their own applications on top of it.
So, we have created a Sample application to demonstrate how a user will use our library.
Basically users will want to create their own WebSecurityConfigurerAdapter. Like this:
#EnableStormpathWebSecurity
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
#Order(1)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
/**
* {#inheritDoc}
*/
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();
}
}
In case this is actually needed, the WebApplicationInitializer looks like this:
public class WebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext context = new AnnotationConfigWebApplicationContext();
context.register(SpringSecurityWebAppConfig.class);
context.register(StormpathMethodSecurityConfiguration.class);
sc.addListener(new ContextLoaderListener(context));
ServletRegistration.Dynamic dispatcher = sc.addServlet("dispatcher", new DispatcherServlet(context));
dispatcher.setLoadOnStartup(1);
dispatcher.addMapping("/");
//Stormpath Filter
FilterRegistration.Dynamic filter = sc.addFilter("stormpathFilter", new DelegatingFilterProxy());
EnumSet<DispatcherType> types =
EnumSet.of(DispatcherType.ERROR, DispatcherType.FORWARD, DispatcherType.INCLUDE, DispatcherType.REQUEST);
filter.addMappingForUrlPatterns(types, false, "/*");
//Spring Security Filter
FilterRegistration.Dynamic securityFilter = sc.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
}
}
All this code boots up correctly. If I go to localhost:8080 I see the welcome screen. If I go to localhost:8080/login I see the login screen. But, if I go to localhost:8080/restricted I should be redirected to the login page since we have this line: http.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();. However I am seeing the Access Denied page instead.
Then, if I add the login url in the App's access control, like this:
protected void configure(HttpSecurity http) throws Exception {
http
.formLogin().loginPage("/login")
.and()
.authorizeRequests().antMatchers("/restricted").fullyAuthenticated();
}
It now redirects me to the login page but as soon as I submit the credentials I get an CSRF problem meaning that all our configuration is not actually part of this filter chain.
When I debug it all it seems that each WebApplicationInitializer is having its own instance with its own Filter Chain. I would expect them to be concatenated somehow but it seems that it is not actually happening...
Anyone has ever tried something like this?
BTW: As a workaround users can do public class SpringSecurityWebAppConfig extends StormpathWebSecurityConfiguration instead of SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter. This way it works but I want users to have pure Spring Security code and extending from our StormpathWebSecurityConfiguration diverges from that goal.
All the code can be seen here. The Stormpath Spring Security library for Spring is under extensions/spring/stormpath-spring-security-webmvc. The Sample App using the library is under examples/spring-security-webmvc.
It is very simple to run... You just need to register to Stormpath as explained here. Then you can checkout the spring_security_extension_redirect_to_login_not_working branch and start the sample app like this:
$ git clone git#github.com:mrioan/stormpath-sdk-java.git
$ git checkout spring_security_extension_redirect_to_login_not_working
$ mvn install -DskipTests=true
$ cd examples/spring-security-webmvc
$ mvn jetty:run
Then you can go to localhost:8080/restricted to see that you are not being redirected to the login page.
Any help is very much appreciated!
In my experience there are issues with having multiple WebSecurityConfigurers messing with the security configuration on startup.
The best way to solve this is to make your library configuration into SecurityConfigurerAdapters that can be applied where appropriate.
public class StormpathHttpSecurityConfigurer
extends AbstractStormpathWebSecurityConfiguration
implements SecurityConfigurer<DefaultSecurityFilterChain, HttpSecurity> {
//Removed beans for the sake of keeping focus on the important stuff
#Override
protected final void configure(HttpSecurity http) throws Exception {
configure(http, stormpathAuthenticationSuccessHandler(), stormpathLogoutHandler());
}
}
public class StormpathAuthenticationManagerConfigurer
extends AbstractStormpathWebSecurityConfiguration
implements SecurityConfigurer<AuthenticationManager, AuthenticationManagerBuilder> {
//Removed beans for the sake of keeping focus on the important stuff
#Override
protected final void configure(AuthenticationManagerBuilder auth) throws Exception {
configure(auth, super.stormpathAuthenticationProvider);
}
}
You then have your users apply these in their own configuration:
#EnableStormpathWebSecurity
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
#Order(1)
public class SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/restricted").fullyAuthenticated()
.and()
.apply(new StormPathHttpSecurityConfigurer(...))
;
}
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.apply(new StormPathAuthenticationManagerConfigurer(...));
}
}
It's definitely the problem regarding either order of your Antmatchers or hasn't specified ROLES of users that you permit to access the URL.
What do you have anything above "/restricted"?
Is something completely blocking anything below that URL? You should specify more specific URLS first then, generalised URLs.
Try configuring above URL properly (or tell me what it is so I can help you out), perhaps apply "fullyAuthenticated" also "permitAll" ROLEs on the parent URL of "/restricted".

Resources