Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring security oauth2 and form login configuration

Tags:

My project consists exposes two different parts, a JSF admin panel and a RESTfull service. I am trying to setup spring security to use different authentication methods depending on the URL the user navigates.

The requirements are

  • Users navigating to the JSF page get a login screen where they authentication using form authentication.
  • Users navigating to the REST service use OAuth2 implicit authentication with basic authentication for the token granting.

The seperate configurations work by themselves, the problem is when I try to combine both of them in one configuration, in that case it seems like the REST provider gets in the way and authenticates each request even if the requests go to the admin url (this is documented from spring security ordering).

My sample configurations are as shown:

  • For the form login (JSF)

    @Override @Order(1) protected void configure(HttpSecurity http) throws Exception { http         .csrf().disable()         .authorizeRequests()         .antMatchers("/resources/**").permitAll()         .antMatchers("/templates/**").permitAll()         .antMatchers("/401.html").permitAll()         .antMatchers("/404.html").permitAll()         .antMatchers("/500.html").permitAll()         .antMatchers("/api/**").permitAll()         .antMatchers("/ui/admin.xhtml").hasAnyAuthority("admin", "ADMIN")         .antMatchers("/thymeleaf").hasAnyAuthority("admin", "ADMIN")         //.anyRequest().authenticated()         .and()         .formLogin()         .loginPage("/login")         .defaultSuccessUrl("/ui/index.xhtml")         .failureUrl("/login?error=1")         .permitAll()         .and()         .logout()         .permitAll()         .and()         .rememberMe()         .and().exceptionHandling().accessDeniedPage("/error/403"); 
  • OAuth2 security config (REST)

    @EnableResourceServer @Order(2) public class RestSecurityConfig extends WebSecurityConfigurerAdapter {      @Inject     private UserRepository userRepository;      @Inject     private PasswordEncoder passwordEncoder;      @Bean     ApplicationListener<AbstractAuthorizationEvent> loggerBean() {         return new AuthenticationLoggerListener();     }      @Bean     AccessDeniedHandler accessDeniedHandler() {         return new AccessDeniedExceptionHandler();     }      @Bean     AuthenticationEntryPoint entryPointBean() {         return new UnauthorizedEntryPoint();     }      /*Override     public void configure(WebSecurity web) throws Exception {         web.ignoring()                 .antMatchers(                         "/resources/**"                         , "/templates/**"                         , "/login"                         , "/logout"                         , "/ui/**"                         , "/401.html"                         , "/404.html"                         , "/500.html"                 );     }*/      @Override     protected void configure(HttpSecurity http) throws Exception {         ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);         if (contentNegotiationStrategy == null) {             contentNegotiationStrategy = new HeaderContentNegotiationStrategy();         }         MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,                 MediaType.APPLICATION_FORM_URLENCODED,                 MediaType.APPLICATION_JSON,                 MediaType.MULTIPART_FORM_DATA);          http.authorizeRequests()                 .antMatchers("/ui/**").permitAll()                 .and()                 .anonymous().disable()                 .sessionManagement()                 .sessionCreationPolicy(SessionCreationPolicy.STATELESS)                 .and().httpBasic()                 .and()                 .exceptionHandling()                 .accessDeniedHandler(accessDeniedHandler()) // handle access denied in general (for example comming from @PreAuthorization                 .authenticationEntryPoint(entryPointBean()) // handle authentication exceptions for unauthorized calls.                 .defaultAuthenticationEntryPointFor(entryPointBean(), preferredMatcher)                 .and()                 .authorizeRequests()                 .antMatchers("/api/**").fullyAuthenticated();      }      @Override     @Bean     public AuthenticationManager authenticationManagerBean() throws Exception {         return super.authenticationManagerBean();     }      @Override     protected void configure(AuthenticationManagerBuilder auth) throws Exception {         auth.userDetailsService(new UserDetailsService() {             @Override             public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {                 User user = userRepository.findOneByUsername(s);                  if (null == user) {                     // leave that to be handled by log listener                     throw new UsernameNotFoundException("The user with email " + s + " was not found");                 }                  return (UserDetails) user;             }         }).passwordEncoder(passwordEncoder);     }       @Configuration     @EnableAuthorizationServer     protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {            @Autowired         private AuthenticationManager authenticationManager;           @Bean         public JwtAccessTokenConverter accessTokenConverter() {             return new JwtAccessTokenConverter();         }          @Override         public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {             oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");         }          @Override         public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {             endpoints.authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());         }           @Override         public void configure(ClientDetailsServiceConfigurer clients) throws Exception {             clients.inMemory()                     .withClient("xxx")                     .resourceIds(xxx)                     .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")                     .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")                     .scopes("read", "write", "trust", "update")                     .accessTokenValiditySeconds(xxx)                     .refreshTokenValiditySeconds(xxx)                     .secret("xxx")          }     } } 

These configurations exist on different classes and the ordering is set manually.

Has anyone any solutions to this issue?

Best,

like image 538
maxsap Avatar asked Mar 06 '15 22:03

maxsap


People also ask

Does Spring Security use default login form?

In this configuration Spring Security will render a default log in page. Most production applications will require a custom log in form. The configuration below demonstrates how to provide a custom log in form. public SecurityFilterChain filterChain(HttpSecurity http) { http .

What is form login in Spring Security?

Form-based login is one form of Username/password authentication that Spring Security provides support for. This is provided through an Html form. Whenever a user requests a protected resource, Spring Security checks for the authentication of the request.

Does Spring Security use OAuth2?

Spring Security provides comprehensive OAuth 2 support. This section discusses how to integrate OAuth 2 into your servlet based application.

Is Spring Security OAuth2 Autoconfigure deprecated?

OAuth2 Authorization Server Support. As we saw, the Spring Security OAuth stack offered the possibility of setting up an Authorization Server as a Spring Application. But the project has been deprecated, and Spring does not support its own authorization server as of now.


1 Answers

I tried to adapt your security configuration. Unfortunately, I can not validate this configuration due to missing reference application.

Maybe it can help you:

@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter {      @Autowired     private UserRepository userRepository;      @Autowired     private PasswordEncoder passwordEncoder;      @Autowired     protected void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {         auth.userDetailsService(new UserDetailsService() {             @Override             public UserDetails loadUserByUsername(String s) throws UsernameNotFoundException {                 User user = userRepository.findOneByUsername(s);                  if (null == user) {                     throw new UsernameNotFoundException("The user with email " + s + " was not found");                 }                  return (UserDetails) user;             }         }).passwordEncoder(passwordEncoder);     }      @Override     public void configure(WebSecurity webSecurity) throws Exception {         webSecurity                 .ignoring()                 .antMatchers("/resources/**"                         , "/templates/**"                         , "/login"                         , "/logout"                         , "/ui/**"                         , "/401.html"                         , "/404.html"                         , "/500.html");     }      @Configuration     @EnableAuthorizationServer     public static class OAuth2Configuration extends AuthorizationServerConfigurerAdapter {          @Autowired         private AuthenticationManager authenticationManager;          @Bean         public JwtAccessTokenConverter accessTokenConverter() {             return new JwtAccessTokenConverter();         }          @Override         public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {             oauthServer.tokenKeyAccess("isAnonymous() || hasAuthority('ROLE_TRUSTED_CLIENT')").checkTokenAccess("hasAuthority('ROLE_TRUSTED_CLIENT')");         }          @Override         public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {             endpoints.authenticationManager(authenticationManager).accessTokenConverter(accessTokenConverter());         }           @Override         public void configure(ClientDetailsServiceConfigurer clients) throws Exception {             clients.inMemory()                     .withClient("xxx")                     .resourceIds("xxx")                     .authorizedGrantTypes("password", "authorization_code", "refresh_token", "implicit")                     .authorities("ROLE_CLIENT", "ROLE_TRUSTED_CLIENT")                     .scopes("read", "write", "trust", "update")                     .accessTokenValiditySeconds(xxx)                     .refreshTokenValiditySeconds(xxx)                     .secret("xxx");          }     }      @Configuration     @Order(1)     public static class FormLoginWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {          @Override         public void configure(HttpSecurity http) throws Exception {             http                     .csrf().disable()                     .authorizeRequests()                     .antMatchers("/ui/admin.xhtml").hasAnyAuthority("admin", "ADMIN")                     .antMatchers("/thymeleaf").hasAnyAuthority("admin", "ADMIN")                     .and()                     .formLogin()                     .loginPage("/login")                     .defaultSuccessUrl("/ui/index.xhtml")                     .failureUrl("/login?error=1")                     .permitAll()                     .and()                     .logout()                     .permitAll()                     .and()                     .rememberMe()                     .and().exceptionHandling().accessDeniedPage("/error/403");         }     }      @Order(2)     @Configuration     @EnableResourceServer     public static class CustomResourceServerConfigurerAdapter extends ResourceServerConfigurerAdapter {          @Bean         ApplicationListener<AbstractAuthorizationEvent> loggerBean() {             return new AuthenticationLoggerListener();         }          @Bean         AccessDeniedHandler accessDeniedHandler() {             return new AccessDeniedExceptionHandler();         }          @Bean         AuthenticationEntryPoint entryPointBean() {             return new UnauthorizedEntryPoint();         }          @Override         public void configure(HttpSecurity http) throws Exception {             ContentNegotiationStrategy contentNegotiationStrategy = http.getSharedObject(ContentNegotiationStrategy.class);             if (contentNegotiationStrategy == null) {                 contentNegotiationStrategy = new HeaderContentNegotiationStrategy();             }             MediaTypeRequestMatcher preferredMatcher = new MediaTypeRequestMatcher(contentNegotiationStrategy,                     MediaType.APPLICATION_FORM_URLENCODED,                     MediaType.APPLICATION_JSON,                     MediaType.MULTIPART_FORM_DATA);              http.authorizeRequests()                     .and()                     .anonymous().disable()                     .sessionManagement()                     .sessionCreationPolicy(SessionCreationPolicy.STATELESS)                     .and().httpBasic()                     .and()                     .exceptionHandling()                     .accessDeniedHandler(accessDeniedHandler()) // handle access denied in general (for example comming from @PreAuthorization                     .authenticationEntryPoint(entryPointBean()) // handle authentication exceptions for unauthorized calls.                     .defaultAuthenticationEntryPointFor(entryPointBean(), preferredMatcher)                     .and()                     .authorizeRequests()                     .antMatchers("/api/**").fullyAuthenticated();         }     } } 
like image 98
ksokol Avatar answered Sep 30 '22 07:09

ksokol