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"
SAML works by exchanging user information, such as logins, authentication state, identifiers, and other relevant attributes between the identity and service provider. As a result, it simplifies and secures the authentication process as the user only needs to log in once with a single set of authentication credentials.
Spring SAML Extension allows seamless inclusion of SAML 2.0 Service Provider capabilities in Spring applications. All products supporting SAML 2.0 in Identity Provider mode (e.g. ADFS 2.0, Shibboleth, OpenAM/OpenSSO, Ping Federate, Okta) can be used to connect with Spring SAML Extension.
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
.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With