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

I am creating a Spring security configuration that will be used as a library by any developer who wants to create a Spring Stormpath application protected by Spring Security.

To do this, I subclassed WebSecurityConfigurerAdapter and defined Stormpath Access Controls in configure(HttpSecurity) , as well as Stormpath AuthenticationProvider using configure(AuthenticationManagerBuilder) . All of this can be seen in this abstract class and its specific subclass:

 @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 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 basically define our entry and exit mechanisms and integrate our CSRF code to play well with Spring Security.

Up to this point, everything is working fine.

But this is just a "library", and we want users to create their own applications on top of it.

So, we created the Sample application to demonstrate how the 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(); } } 

If it is really necessary, WebApplicationInitializer as follows:

 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 loads correctly. If I go to localhost:8080 , I will see a welcome screen. If I go to localhost:8080/login , I will 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 see the Access Denied page.

Then, if I add the login URL to the application access control, for example:

 protected void configure(HttpSecurity http) throws Exception { http .formLogin().loginPage("/login") .and() .authorizeRequests().antMatchers("/restricted").fullyAuthenticated(); } 

Now it redirects me to the login page, but as soon as I submit the credentials, I get a CSRF problem meaning that our entire configuration is not really part of this filter chain.

When I debug all this, it seems that each WebApplicationInitializer has its own instance with its own filter chain. I would expect them to be somehow concatenated, but it seems like this is not really happening ...

Has anyone ever tried something like this?

BTW: As a workaround, users can do the public class SpringSecurityWebAppConfig extends StormpathWebSecurityConfiguration instead of SpringSecurityWebAppConfig extends WebSecurityConfigurerAdapter . This way it works, but I want users to have a clean Spring security code, and extending from our StormpathWebSecurityConfiguration deviate from this goal.

All code can be seen here . Spring Stormpath security library for Spring is under extensions/spring/stormpath-spring-security-webmvc . A sample application using the library is under examples/spring-security-webmvc .

It is very easy to run ... You just need to register with the Stormpath as described here . Then you can check the spring_security_extension_redirect_to_login_not_working branch and run the sample application as follows:

 $ 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 redirected to the login page.

Any help is much appreciated!

+5
source share
2 answers

In my experience, there are problems with having multiple WebSecurityConfigurer messing with security configuration on startup.

The best way to solve this problem is to configure your library in SecurityConfigurerAdapters , which can be applied where necessary.

 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); } } 

Then you have your apply users in your 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(...)); } } 
+3
source

This is definitely a problem with respect to any order of your Antmatchers or has not indicated the ROLE of the users allowing you to access the URL.

What do you have something above "/ limited"?

Is something completely blocking anything below this url? You must specify more specific URLs first, followed by generic URLs.

Try setting the URL above correctly (or tell me what exactly I can help you with), maybe apply "fullAuthenticated" as well as "allowAll" ROLE on the parent "/ limited" URL.

-2
source

Source: https://habr.com/ru/post/1233008/


All Articles