SAML2 Authentication with authorization based on SAML assertions

Viewed 799

I'm using spring-security-saml2-service-provider to authenticate my SpringBoot webapp against a SAML IdP - this works. I can also access the SAML assertions within a REST Controller using @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal, but what I would like to do is restrict access by url using the values within the assertions within the Saml2AuthenticatedPrincipal principal - its a common approach within SAML federations to release values of eduPersonEntitlement, and decide access based on this. Has anyone done this? All my research/trials on this have come up with nothing. Here's what I have so far:

@EnableWebSecurity
public class SAMLSecurityConfig extends WebSecurityConfigurerAdapter {

@Autowired
RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;

protected void configure(HttpSecurity http) throws Exception {

    RelyingPartyRegistrationResolver relyingPartyRegistrationResolver =
    new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);

    Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());
    
    http
        .saml2Login(withDefaults())
            .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class).antMatcher("/**")
        .authorizeRequests()
            .anyRequest().authenticated();
    }
}

I think I need to swap out authenticated() with something maybe to do with roles, and somehow set roles for users as they log in, but have got nowhere with this. Any ideas?

1 Answers

OK, got it working....you need to customize the saml2Login - replace withDefaults() method with a new Customizer (Saml2LoginSettings below):

SAMLSecurityconfig.java:

@EnableWebSecurity
public class SAMLSecurityConfig extends WebSecurityConfigurerAdapter {
  
    @Autowired
    RelyingPartyRegistrationRepository relyingPartyRegistrationRepository;

    @Autowired
    Saml2LoginSettings settings;
    
    protected void configure(HttpSecurity http) throws Exception {

        RelyingPartyRegistrationResolver relyingPartyRegistrationResolver =
        new DefaultRelyingPartyRegistrationResolver(this.relyingPartyRegistrationRepository);

        Saml2MetadataFilter filter = new Saml2MetadataFilter(relyingPartyRegistrationResolver, new OpenSamlMetadataResolver());

        http
            .saml2Login(settings)
                .addFilterBefore(filter, Saml2WebSsoAuthenticationFilter.class).antMatcher("/**")  // 
            .authorizeRequests()
            .antMatchers("/attributes").hasAuthority("ADMIN")
            .anyRequest().authenticated();

With Saml2LoginSettings.java:

@Component
class Saml2LoginSettings implements Customizer <Saml2LoginConfigurer<HttpSecurity>> {

    @Override
    public void customize(Saml2LoginConfigurer<HttpSecurity> t) {
   
        t.successHandler(new SavedRequestAwareAuthenticationSuccessHandler() {

            @Override
            public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
                    Authentication authentication) throws IOException, ServletException {

                authentication = assignAuthorities (authentication, request);
                super.onAuthenticationSuccess(request, response, authentication);
            }
        }); 
    }

Assigning authorities is a bit cumbersome but this works:

    private Authentication assignAuthorities (Authentication authentication, HttpServletRequest request) {
        Collection<SimpleGrantedAuthority> oldAuthorities = (Collection<SimpleGrantedAuthority>)SecurityContextHolder.getContext()
                .getAuthentication().getAuthorities();

        DefaultSaml2AuthenticatedPrincipal princ = (DefaultSaml2AuthenticatedPrincipal) authentication.getPrincipal();
        if (princ.getAttribute("urn:oid:1.3.6.1.4.1.5923.1.1.1.7").contains("urn:mace:dir:entitlement:common-lib-terms")) {

            List<SimpleGrantedAuthority> updatedAuthorities = new ArrayList<SimpleGrantedAuthority>();
            updatedAuthorities.addAll(oldAuthorities);
            updatedAuthorities.add(new SimpleGrantedAuthority("ADMIN"));
            Saml2Authentication sAuth = (Saml2Authentication) authentication;

            sAuth = new Saml2Authentication(
                    (AuthenticatedPrincipal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(),
                    sAuth.getSaml2Response(),
                    updatedAuthorities
            );
            SecurityContextHolder.getContext().setAuthentication(sAuth);

            return sAuth;
        }
        else 
            return authentication;
    }

Sample code here

Related