Skip to content

Add SAML Service Provider Support #7260

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 6, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions config/spring-security-config.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dependencies {

optional project(':spring-security-ldap')
optional project(':spring-security-messaging')
optional project(':spring-security-saml2-service-provider')
optional project(':spring-security-oauth2-client')
optional project(':spring-security-oauth2-jose')
optional project(':spring-security-oauth2-resource-server')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -73,13 +73,19 @@ final class FilterComparator implements Comparator<Filter>, Serializable {
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestRedirectFilter",
order.next());
filterToOrder.put(
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationRequestFilter",
order.next());
put(X509AuthenticationFilter.class, order.next());
put(AbstractPreAuthenticatedProcessingFilter.class, order.next());
filterToOrder.put("org.springframework.security.cas.web.CasAuthenticationFilter",
order.next());
filterToOrder.put(
"org.springframework.security.oauth2.client.web.OAuth2LoginAuthenticationFilter",
order.next());
filterToOrder.put(
"org.springframework.security.saml2.provider.service.servlet.filter.Saml2WebSsoAuthenticationFilter",
order.next());
put(UsernamePasswordAuthenticationFilter.class, order.next());
put(ConcurrentSessionFilter.class, order.next());
filterToOrder.put(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,13 @@
import org.springframework.security.config.annotation.web.configurers.oauth2.client.OAuth2LoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.oauth2.server.resource.OAuth2ResourceServerConfigurer;
import org.springframework.security.config.annotation.web.configurers.openid.OpenIDLoginConfigurer;
import org.springframework.security.config.annotation.web.configurers.saml2.Saml2LoginConfigurer;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository;
import org.springframework.security.web.DefaultSecurityFilterChain;
import org.springframework.security.web.PortMapper;
import org.springframework.security.web.PortMapperImpl;
Expand All @@ -75,11 +78,11 @@
import org.springframework.web.filter.CorsFilter;
import org.springframework.web.servlet.handler.HandlerMappingIntrospector;

import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import javax.servlet.Filter;
import javax.servlet.http.HttpServletRequest;

/**
* A {@link HttpSecurity} is similar to Spring Security's XML &lt;http&gt; element in the
Expand Down Expand Up @@ -1857,6 +1860,191 @@ public HttpSecurity formLogin(Customizer<FormLoginConfigurer<HttpSecurity>> form
return HttpSecurity.this;
}

/**
* Configures authentication support using an SAML 2.0 Service Provider.
* <br>
* <br>
*
* The &quot;authentication flow&quot; is implemented using the <b>Web Browser SSO Profile, using POST and REDIRECT bindings</b>,
* as documented in the <a target="_blank" href="https://docs.oasis-open.org/security/saml/">SAML V2.0 Core,Profiles and Bindings</a>
* specifications.
* <br>
* <br>
*
* As a prerequisite to using this feature, is that you have a SAML v2.0 Identity Provider to provide an assertion.
* The representation of the Service Provider, the relying party, and the remote Identity Provider, the asserting party
* is contained within {@link RelyingPartyRegistration}.
* <br>
* <br>
*
* {@link RelyingPartyRegistration}(s) are composed within a
* {@link RelyingPartyRegistrationRepository},
* which is <b>required</b> and must be registered with the {@link ApplicationContext} or
* configured via <code>saml2Login().relyingPartyRegistrationRepository(..)</code>.
* <br>
* <br>
*
* The default configuration provides an auto-generated login page at <code>&quot;/login&quot;</code> and
* redirects to <code>&quot;/login?error&quot;</code> when an authentication error occurs.
* The login page will display each of the identity providers with a link
* that is capable of initiating the &quot;authentication flow&quot;.
* <br>
* <br>
*
* <p>
* <h2>Example Configuration</h2>
*
* The following example shows the minimal configuration required, using SimpleSamlPhp as the Authentication Provider.
*
* <pre>
* &#064;Configuration
* public class Saml2LoginConfig {
*
* &#064;EnableWebSecurity
* public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .authorizeRequests()
* .anyRequest().authenticated()
* .and()
* .saml2Login();
* }
* }
*
* &#064;Bean
* public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
* return new InMemoryRelyingPartyRegistrationRepository(this.getSaml2RelyingPartyRegistration());
* }
*
* private RelyingPartyRegistration getSaml2RelyingPartyRegistration() {
* //remote IDP entity ID
* String idpEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php";
* //remote WebSSO Endpoint - Where to Send AuthNRequests to
* String webSsoEndpoint = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php";
* //local registration ID
* String registrationId = "simplesamlphp";
* //local entity ID - autogenerated based on URL
* String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
* //local signing (and decryption key)
* Saml2X509Credential signingCredential = getSigningCredential();
* //IDP certificate for verification of incoming messages
* Saml2X509Credential idpVerificationCertificate = getVerificationCertificate();
* return RelyingPartyRegistration.withRegistrationId(registrationId)
* * .remoteIdpEntityId(idpEntityId)
* * .idpWebSsoUrl(webSsoEndpoint)
* * .credential(signingCredential)
* * .credential(idpVerificationCertificate)
* * .localEntityIdTemplate(localEntityIdTemplate)
* * .build();
* }
* }
* </pre>
*
* <p>
*
* @since 5.2
* @return the {@link Saml2LoginConfigurer} for further customizations
* @throws Exception
*/
public Saml2LoginConfigurer<HttpSecurity> saml2Login() throws Exception {
return getOrApply(new Saml2LoginConfigurer<>());
}

/**
* Configures authentication support using an SAML 2.0 Service Provider.
* <br>
* <br>
*
* The &quot;authentication flow&quot; is implemented using the <b>Web Browser SSO Profile, using POST and REDIRECT bindings</b>,
* as documented in the <a target="_blank" href="https://docs.oasis-open.org/security/saml/">SAML V2.0 Core,Profiles and Bindings</a>
* specifications.
* <br>
* <br>
*
* As a prerequisite to using this feature, is that you have a SAML v2.0 Identity Provider to provide an assertion.
* The representation of the Service Provider, the relying party, and the remote Identity Provider, the asserting party
* is contained within {@link RelyingPartyRegistration}.
* <br>
* <br>
*
* {@link RelyingPartyRegistration}(s) are composed within a
* {@link RelyingPartyRegistrationRepository},
* which is <b>required</b> and must be registered with the {@link ApplicationContext} or
* configured via <code>saml2Login().relyingPartyRegistrationRepository(..)</code>.
* <br>
* <br>
*
* The default configuration provides an auto-generated login page at <code>&quot;/login&quot;</code> and
* redirects to <code>&quot;/login?error&quot;</code> when an authentication error occurs.
* The login page will display each of the identity providers with a link
* that is capable of initiating the &quot;authentication flow&quot;.
* <br>
* <br>
*
* <p>
* <h2>Example Configuration</h2>
*
* The following example shows the minimal configuration required, using SimpleSamlPhp as the Authentication Provider.
*
* <pre>
* &#064;Configuration
* public class Saml2LoginConfig {
*
* &#064;EnableWebSecurity
* public static class OAuth2LoginSecurityConfig extends WebSecurityConfigurerAdapter {
* &#064;Override
* protected void configure(HttpSecurity http) throws Exception {
* http
* .authorizeRequests()
* .anyRequest().authenticated()
* .and()
* .saml2Login(withDefaults());
* }
* }
*
* &#064;Bean
* public RelyingPartyRegistrationRepository relyingPartyRegistrationRepository() {
* return new InMemoryRelyingPartyRegistrationRepository(this.getSaml2RelyingPartyRegistration());
* }
*
* private RelyingPartyRegistration getSaml2RelyingPartyRegistration() {
* //remote IDP entity ID
* String idpEntityId = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/metadata.php";
* //remote WebSSO Endpoint - Where to Send AuthNRequests to
* String webSsoEndpoint = "https://simplesaml-for-spring-saml.cfapps.io/saml2/idp/SSOService.php";
* //local registration ID
* String registrationId = "simplesamlphp";
* //local entity ID - autogenerated based on URL
* String localEntityIdTemplate = "{baseUrl}/saml2/service-provider-metadata/{registrationId}";
* //local signing (and decryption key)
* Saml2X509Credential signingCredential = getSigningCredential();
* //IDP certificate for verification of incoming messages
* Saml2X509Credential idpVerificationCertificate = getVerificationCertificate();
* return RelyingPartyRegistration.withRegistrationId(registrationId)
* * .remoteIdpEntityId(idpEntityId)
* * .idpWebSsoUrl(webSsoEndpoint)
* * .credential(signingCredential)
* * .credential(idpVerificationCertificate)
* * .localEntityIdTemplate(localEntityIdTemplate)
* * .build();
* }
* }
* </pre>
*
* <p>
*
* @since 5.2
* @param saml2LoginCustomizer the {@link Customizer} to provide more options for
* the {@link Saml2LoginConfigurer}
* @return the {@link HttpSecurity} for further customizations
* @throws Exception
*/
public HttpSecurity saml2Login(Customizer<Saml2LoginConfigurer<HttpSecurity>> saml2LoginCustomizer) throws Exception {
saml2LoginCustomizer.customize(getOrApply(new Saml2LoginConfigurer<>()));
return HttpSecurity.this;
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should add the saml2Login(Customizer) method too

/**
* Configures authentication support using an OAuth 2.0 and/or OpenID Connect 1.0 Provider.
* <br>
Expand Down
Loading