Search code examples
springspring-bootspring-securityadfsspring-oauth2

Connect Spring Authorization server to external IDP and trigger authentication


We created an authorization server with JDBC backend token store. A similar implementation is hosted on GitHub. It is working perfectly fine in our environment using different grant types. Different web applications use this for SSO, and it issues tokens, which are then used to consume API as well.

We need a way to log a user in, and issue token if the user is returned as authenticated from external IDP, kind of simulating a user logging in manually from the login form.

We have to extend this server with external IDP authentication. So if a user is connected to their domain network, and has ADFS (as an example), expected flow is as follows:

  • User tries to access a client app
  • Redirected to authorization server
  • Instead of entering credentials user can click on a button to authenticate via ADFS (this can be automated too later on)
  • ADFS should return authentication ok, with user information
  • Trigger login of that user in the authorization server, so that an OAuth2 token is issued, and redirected back to the client app

We have tried multiple ways to achieve it, and have referred to multiple resources online, but no success yet. Please note that we do not have the need to connect to social media IDP, rather we have to consume response from enterprise-grade like ADFS, One-login etc.

Any initial pointers would be much appreciated.


Solution

  • To authenticate with GitHub and generate spring token which can be used downstream application we can change our codes like below.

    In WebSecurityConfigurerAdapter add below code additional to configure(HttpSecurity http)

    http.exceptionHandling()
                      .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and()
                    .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class).addFilter(customBasicAuthFilter);
    

    then in WebSecurityConfigurerAdapter again

    @Bean
            public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
                FilterRegistrationBean registration = new FilterRegistrationBean();
                registration.setFilter(filter);
                registration.setOrder(-100);
                return registration;
            }
    
            @Bean
            @ConfigurationProperties("github")
            public ClientResources github() {
                return new ClientResources();
            }
    
    
        private Filter ssoFilter() {
            CompositeFilter filter = new CompositeFilter();
            List<Filter> filters = new ArrayList<>();
            filters.add(ssoFilter(github(), "/login/github"));
            filter.setFilters(filters);
            return filter;
        }
    
        private Filter ssoFilter(ClientResources client, String path) {
            OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(
                    path);
            OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext);
            oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
            UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(),
                    client.getClient().getClientId());
            tokenServices.setRestTemplate(oAuth2RestTemplate);
            oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices);
            return oAuth2ClientAuthenticationFilter;
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.parentAuthenticationManager(authenticationManager);
            PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
            auth.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder);
        }
    

    add one class ClientResources

    class ClientResources {
    
        @NestedConfigurationProperty
        private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails();
    
        @NestedConfigurationProperty
        private ResourceServerProperties resource = new ResourceServerProperties();
    
        public AuthorizationCodeResourceDetails getClient() {
            return client;
        }
    
        public ResourceServerProperties getResource() {
            return resource;
        }
    }
    

    additional to all we need to add GitHub setting in our application.

    github.client.clientId = <<Clientid>>
    github.client.clientSecret = <<clientSecret>>
    github.client.accessTokenUri = https://github.com/login/oauth/access_token
    github.client.userAuthorizationUri = https://github.com/login/oauth/authorize
    github.client.clientAuthenticationScheme = form
    github.resource.userInfoUri = https://api.github.com/user
    logging.level.org.springframework.security = DEBUG
    

    Similar way you can do it for other which supports OAuth. I am also exploring for working with ADFS authentication. Query posted on Stackoverflow for the same.