Spring security oauth2 and form login configuration

22,025

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();
        }
    }
}
Share:
22,025

Related videos on Youtube

maxsap
Author by

maxsap

students at technological institute of Messologi at the department of telecomunnications and computer networks

Updated on July 09, 2022

Comments

  • maxsap
    maxsap almost 2 years

    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,

    • Maleen Abewardana
      Maleen Abewardana almost 9 years
      Were you able to fix this issue? Can you post an answer please.
    • maxsap
      maxsap almost 9 years
      @Maleenc unfortunately no, I would really appreciate and answer from Spring security guys.
  • WhatAKitty
    WhatAKitty over 7 years
    Can I use formLogin with /** and use another rest formLogin with /api/** ? Not customsizing own formLogin what you do above.
  • Igor Petrov
    Igor Petrov about 5 years
    Yep, it does work. But how do you match user once authenticated with form login with exact sample user authenticated with OAuth2?
  • Nick
    Nick over 3 years
    you're a livesaver! thanks! @Order annotations solved my issue