Spring security : handling SSO and DB users

2020-08-04 04:22发布

问题:

I have two different types of users.

  1. SSO users
  2. DB users.

SSO users would have already been authenticated by different system and DB users should be authenticated by our system. Can i configure Spring security to handle this scenario where by i can say prompt login page for some users and don't prompt for some.

Lets say for SSO users i can get there users ID in request headers while DB when they access the application there is no user id present in request header .How can i handle this scenario ?

Can i override authenticate method of DaoAuthenticationProvider by extending it and then page on some parameter decide to authenticate user or is there any other means ? can i add any information to Authentication class

This is What i have tried to Far

Security Config java

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    DataSource dataSource;


    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder builder) throws Exception {
        builder.jdbcAuthentication().dataSource(dataSource).passwordEncoder(passwordEncoder())
                .usersByUsernameQuery("select username,password, enabled from users where username=?")
                .authoritiesByUsernameQuery("select username, role from user_roles where username=?");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().authenticated().and().httpBasic()
        .and().addFilterBefore(new UserTypeFilter(), BasicAuthenticationFilter.class);
    }

    public PasswordEncoder passwordEncoder() {
        PasswordEncoder encoder = new BCryptPasswordEncoder();
        return encoder;
    }

    /*
     * @Bean public MethodSecurityInterceptor methodSecurityService() { return
     * new MethodSecurityInterceptor(); }
     */

     @Bean(name="myAuthenticationManager")
       public AuthenticationManager authenticationManagerBean() throws Exception {
           return super.authenticationManagerBean();
       }

     @Bean
        public ExceptionTranslationFilter exceptionTranslationFilter() {
            ExceptionTranslationFilter exceptionTranslationFilter = new ExceptionTranslationFilter(
                    new Http403ForbiddenEntryPoint());
            AccessDeniedHandlerImpl accessDeniedHandlerImpl = new AccessDeniedHandlerImpl();
            accessDeniedHandlerImpl.setErrorPage("/exception");
            exceptionTranslationFilter
                    .setAccessDeniedHandler(accessDeniedHandlerImpl);
            exceptionTranslationFilter.afterPropertiesSet();
            return exceptionTranslationFilter;
        }

     @Bean
     public UserTypeFilter authenticationFilter() throws Exception {
         UserTypeFilter authFilter = new UserTypeFilter();
         authFilter.setAuthenticationManager(authenticationManager());
         return authFilter;
     }
}

My Custom AbstractAuthenticationProcessingFilter

public class UserTypeFilter extends AbstractAuthenticationProcessingFilter {

    private static final String INTERCEPTOR_PROCESS_URL = "/index";

    @Autowired
    public void setAuthenticationManager(AuthenticationManager authenticationManager) {
        super.setAuthenticationManager(authenticationManager);
    }

    public UserTypeFilter() {
        super(INTERCEPTOR_PROCESS_URL);
    }

    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
            throws AuthenticationException, IOException, ServletException {
        System.out.println(" BASIC AUTHENTICATION FILTER");
        String userId = request.getHeader("USERID");
        if (userId == null) {
            System.out.println(" THROWING EXCEPTION FILTER");
            throw new PreAuthenticatedCredentialsNotFoundException("USERID param not found");
        }
        return null;
    }

}

My Controller

@Controller
public class MainController {


    @RequestMapping(value = { "/index" }, method = RequestMethod.GET)
    public ModelAndView index() {

        ModelAndView model = new ModelAndView();
        model.addObject("message", "This is test page!");
        model.setViewName("dummy");

        return model;

    }

}

The control goes to My Custom filter and then when the exception is thrown but ExceptionTranslationFilter is not getting called

Have i configured httpsecurity correctly Have i configured My custom filter correctly Have i configured ExceptionTranslation Filter Am i missing anything

回答1:

This is a pretty standard use case for spring security. You will need to provide an Authentication object into the security context before any security interceptor is encountered.

Typically you would have some kind of filter which extracted SSO parameters from the request, authenticated those parameters against the SSO service, and then create an Authentication object and put it into the security context. The type of filter and configuration of the filter will depend on what SSO technology you are using.

There would often also be a filter (usually an ExceptionTranslationFilter) which will send unauthenticated requests to a login page.

There would also be filters to receive the parameters from the login form and store them in the security context.

Putting it all together I would expect one possible workflow to be:

User logs in with SSO parameters

  1. Request comes in prepopulated with credentials
  2. Some filter extracts those credentials, verifies them, creates an Authentication object, places the object in the security context.
  3. The security interceptor finds the Authentication object in the security context, verifies the user is allowed access to the particular function, and passes the request on.

User logs in without SSO parameters (needs login page)

  1. Request comes in with no credentials
  2. The security interceptor finds no Authentication object and throws an exception.
  3. The ExceptionTranslationFilter turns the exception into a redirect to a login page.

User logs in with filled out login form (e.g. for DB login)

  1. Request comes in with a login form as the entity body
  2. Some filter (e.g. UsernamePasswordAuthenticationFilter) extracts the credentials from the login form and defers to an authentication provider (e.g. your DAO authentication provider) to query the database and verify the user. If verified this filter will create an Authentication object and place it in the security context.
  3. The security interceptor finds the Authentication object in the security context, verifies the user is allowed access to the particular function, and passes the request on.