Spring Security SAML2 dynamic selection of IDPs or dynamic URLs for them
Asked Answered
G

1

9

We're trying to configure several identity providers in the application to support different types of SSO. The problem is that for a non-authenticated request the application doesn't know which IDP to redirect to. We can figure out which IDP to use based on the domain name. That's not a problem. The problem is to change filters the way to redirect to that specific IDP instead of the first found one.

I wonder if there's an easy way to support it in Spring Security or its SAML2 library.

I can either somehow modify metadata to redirect it to my own URL (and then have some custom code there) or make the authentication filter pick the right IDP based on some criteria.

UPDATE

Current yaml configuration:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          idpone:
            identityprovider:
              entity-id: https://idpone.com
              sso-url: https://idpone.com
              verification: 
                credentials:
                - certificate-location: "classpath:saml/idpone.crt"
          idptwo:
            identityprovider:
              entity-id: https://idptwo.com
              sso-url: https://idptwo.com
              verification: 
                credentials:
                - certificate-location: "classpath:saml/idptwo.crt"
Gigantean answered 10/3, 2020 at 21:43 Comment(0)
H
9

As of Spring Security 5.2, you can set up multiple IDPs via the RelyingPartyRegistrationRepository.

Each one looks something like this when using Spring Boot:

spring:
  security:
    saml2:
      relyingparty:
        registration:
          idpone:
            identityprovider:
              verification:
                credentials:
                  - certificate-location: "classpath:idpOne.crt"
              entity-id: https://idp.example.org
              sso-url: https://idp.example.org/SSOService.saml2
          idptwo:
            identityprovider:
              ...

Then, you can initiate an AuthNRequest for idpOne by naving to http://localhost:8080/saml2/authenticate/idpOne.

By Hostname

If you want to do it by hostname, then you can customize the /login page to know which of the /saml2/authenticate/{registrationId} endpoints to redirect to.

First, you'd tell Spring Security that you have a custom /login page, so it doesn't create one:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) {
        http
            .authorizeRequests(authz -> authz
                .mvcMatchers("/login").permitAll() // here
                .anyRequest().authenticated())
            .saml2Login(saml2 -> saml2.loginPage("/login")) // and here
    }

}

And then, you'd define it:

@Controller
public class LoginController {
    private final RelyingPartyRegistrationRepository relyingParties;

    // ... constructor

    @GetMapping("/login")
    public void login(HttpServletRequest request, HttpServletResponse response) {
        String registrationId = // ... derive from the host name
        RelyingPartyRegistration relyingParty = this.relyingParties
                .findByRegistrationId(registrationId);
        if (relyingParty == null) {
            response.setStatusCode(401);
        } else {
            response.sendRedirect("/saml2/authenticate/" + registrationId);
        }
    }
}

The reason for the lookup in the /login endpoint is to ensure that the registrationId supplied in the hostname is legitimate.

Hymettus answered 10/3, 2020 at 22:14 Comment(8)
jzheaux, I'm trying to configure it the way you suggested, but I'm getting class not found RelyingPartyRegistrationRepository. Somehow spring knows about the class, but I can't even locate this class using findjar.com...Gigantean
I'm using spring boot 2.2.5 with spring 5.2.4.Gigantean
These are the properties I configured, where idpone represents my proprietary idp hostname: spring.security.saml2.relyingparty.registration.idpone.identityprovider.verification.credentials=certificate-location: "classpath:saml/keystore.p12" spring.security.saml2.relyingparty.registration.idpone.identityprovider.entity-id=idpone.com spring.security.saml2.relyingparty.registration.idpone.identityprovider.sso-url="idpone.com/idp/endpoint/HttpPost"Gigantean
Try checking your configuration against the sample in the Spring Security repo: github.com/spring-projects/spring-security/tree/master/samples/…Hymettus
I was able to fix the relyingparties problem. What I'm facing now is circular redirects between login and authenticate/idpone. I permit all for "/saml2*" requests. I'm probably not setting sso-url properly or other parameters.Gigantean
Possibly. Adding a permit all for "/saml2*" shouldn't be necessary since the Saml2WebSsoAuthenticationRequestFilter comes before the FilterSecurityInterceptor. You might consider starting a new question where you can add some additional detail - whatever is wrong in the application, your app probably isn't the first to experience it.Hymettus
There were several misconfiguration problems, but all got resolved! Thank you, sir! I have another question about logout, but I will post it as a separate question with the hope you would respond.Gigantean
Do you happen to know the answer to my other question about single logout or at least for the logout of currently used IDP?Gigantean

© 2022 - 2024 — McMap. All rights reserved.