From 7ffe4550881b9891d7e4985de778dbc2013652c7 Mon Sep 17 00:00:00 2001 From: Josh Cummings Date: Tue, 28 Feb 2023 07:20:28 -0700 Subject: [PATCH] Polish Federation Example Issue gh-122 --- ...ityIdRelyingPartyRegistrationResolver.java | 25 ++++++++---- .../main/java/example/IndexController.java | 22 ----------- .../SamlExtensionUrlForwardingFilter.java | 5 +-- .../java/example/SecurityConfiguration.java | 21 +++------- .../src/main/resources/application.yml | 10 ++--- .../src/main/resources/templates/login.html | 38 ------------------- 6 files changed, 30 insertions(+), 91 deletions(-) delete mode 100644 servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/templates/login.html diff --git a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/EntityIdRelyingPartyRegistrationResolver.java b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/EntityIdRelyingPartyRegistrationResolver.java index 86ff6bf..de44860 100644 --- a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/EntityIdRelyingPartyRegistrationResolver.java +++ b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/EntityIdRelyingPartyRegistrationResolver.java @@ -29,14 +29,14 @@ import org.opensaml.saml.saml2.core.impl.ResponseUnmarshaller; import org.w3c.dom.Document; import org.w3c.dom.Element; +import org.springframework.lang.NonNull; import org.springframework.security.saml2.core.OpenSamlInitializationService; import org.springframework.security.saml2.core.Saml2Error; import org.springframework.security.saml2.core.Saml2ErrorCodes; import org.springframework.security.saml2.core.Saml2ParameterNames; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticationException; +import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; -import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.RelyingPartyRegistrationResolver; public class EntityIdRelyingPartyRegistrationResolver implements RelyingPartyRegistrationResolver { @@ -47,25 +47,34 @@ public class EntityIdRelyingPartyRegistrationResolver implements RelyingPartyReg private final ResponseUnmarshaller responseUnmarshaller; private final ParserPool parserPool; - private final RelyingPartyRegistrationResolver delegate; + private final InMemoryRelyingPartyRegistrationRepository registrations; - public EntityIdRelyingPartyRegistrationResolver(RelyingPartyRegistrationRepository registrations) { + public EntityIdRelyingPartyRegistrationResolver(InMemoryRelyingPartyRegistrationRepository registrations) { XMLObjectProviderRegistry registry = ConfigurationService.get(XMLObjectProviderRegistry.class); this.responseUnmarshaller = (ResponseUnmarshaller) registry.getUnmarshallerFactory() .getUnmarshaller(Response.DEFAULT_ELEMENT_NAME); this.parserPool = registry.getParserPool(); - this.delegate = new DefaultRelyingPartyRegistrationResolver(registrations); + this.registrations = registrations; } @Override public RelyingPartyRegistration resolve(HttpServletRequest request, String relyingPartyRegistrationId) { if (relyingPartyRegistrationId != null) { - return this.delegate.resolve(request, relyingPartyRegistrationId); + return this.registrations.findByRegistrationId(relyingPartyRegistrationId); } - return this.delegate.resolve(request, resolveRegistrationId(request)); + String entityId = resolveEntityId(request); + if (entityId == null) { + return null; + } + for (RelyingPartyRegistration registration : this.registrations) { + if (entityId.equals(registration.getAssertingPartyDetails().getEntityId())) { + return registration; + } + } + return null; } - private String resolveRegistrationId(HttpServletRequest request) { + private String resolveEntityId(HttpServletRequest request) { String saml2Response = request.getParameter(Saml2ParameterNames.SAML_RESPONSE); if (saml2Response == null) { return null; diff --git a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/IndexController.java b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/IndexController.java index dbac7df..4d22891 100644 --- a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/IndexController.java +++ b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/IndexController.java @@ -16,13 +16,8 @@ package example; -import java.util.ArrayList; -import java.util.Collection; - -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.security.saml2.provider.service.authentication.Saml2AuthenticatedPrincipal; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; import org.springframework.web.bind.annotation.GetMapping; @@ -30,13 +25,6 @@ import org.springframework.web.bind.annotation.GetMapping; @Controller public class IndexController { - private final Iterable registrations; - - @Autowired - public IndexController(Iterable registrations) { - this.registrations = registrations; - } - @GetMapping("/") public String index(Model model, @AuthenticationPrincipal Saml2AuthenticatedPrincipal principal) { String emailAddress = principal.getFirstAttribute("email"); @@ -45,14 +33,4 @@ public class IndexController { return "index"; } - @GetMapping("/login") - public String login(Model model) { - Collection urls = new ArrayList<>(); - for (RelyingPartyRegistration registration : this.registrations) { - urls.add("/saml/login?id=" + registration.getRegistrationId()); - } - model.addAttribute("urls", urls); - return "login"; - } - } diff --git a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SamlExtensionUrlForwardingFilter.java b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SamlExtensionUrlForwardingFilter.java index 476e175..3461805 100644 --- a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SamlExtensionUrlForwardingFilter.java +++ b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SamlExtensionUrlForwardingFilter.java @@ -40,11 +40,10 @@ import org.springframework.web.filter.OncePerRequestFilter; public class SamlExtensionUrlForwardingFilter extends OncePerRequestFilter { // @formatter:off - private static final Map urlMapping = Map.of("/saml/SSO", "/login/saml2/sso/one", - "/saml/login", "/saml2/authenticate/one", + private static final Map urlMapping = Map.of("/saml/SSO", "/login/saml2/sso/sp", "/saml/logout", "/logout/saml2/slo", "/saml/SingleLogout", "/logout/saml2/slo", - "/saml/metadata", "/saml2/service-provider-metadata/one"); + "/saml/metadata", "/saml2/service-provider-metadata/sp"); // @formatter:on private final RequestMatcher matcher = createRequestMatcher(); diff --git a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SecurityConfiguration.java b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SecurityConfiguration.java index b44c5b5..d8cb628 100644 --- a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SecurityConfiguration.java +++ b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SecurityConfiguration.java @@ -20,11 +20,11 @@ import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; -import java.security.KeyStore; import java.security.cert.CertificateException; import java.security.cert.CertificateFactory; import java.security.cert.X509Certificate; import java.security.interfaces.RSAPrivateKey; +import java.util.UUID; import java.util.stream.Collectors; import org.springframework.beans.factory.annotation.Value; @@ -41,13 +41,10 @@ import org.springframework.security.saml2.core.Saml2X509Credential; import org.springframework.security.saml2.provider.service.metadata.OpenSamlMetadataResolver; import org.springframework.security.saml2.provider.service.registration.InMemoryRelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration; -import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrationRepository; import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistrations; import org.springframework.security.saml2.provider.service.web.DefaultRelyingPartyRegistrationResolver; import org.springframework.security.saml2.provider.service.web.Saml2AuthenticationTokenConverter; import org.springframework.security.saml2.provider.service.web.Saml2MetadataFilter; -import org.springframework.security.saml2.provider.service.web.authentication.OpenSaml4AuthenticationRequestResolver; -import org.springframework.security.saml2.provider.service.web.authentication.Saml2AuthenticationRequestResolver; import org.springframework.security.web.SecurityFilterChain; @Configuration @@ -59,10 +56,10 @@ public class SecurityConfiguration { // @formatter:off http .authorizeHttpRequests((authorize) -> authorize - .requestMatchers("/login", "/error").permitAll() + .requestMatchers("/error").permitAll() .anyRequest().authenticated() ) - .saml2Login((saml2) -> saml2.loginPage("/login")) + .saml2Login(Customizer.withDefaults()) .saml2Logout(Customizer.withDefaults()); // @formatter:on return http.build(); @@ -70,18 +67,11 @@ public class SecurityConfiguration { @Bean - Saml2AuthenticationTokenConverter usingEntityId(RelyingPartyRegistrationRepository repository) { + Saml2AuthenticationTokenConverter usingEntityId(InMemoryRelyingPartyRegistrationRepository repository) { var registrations = new EntityIdRelyingPartyRegistrationResolver(repository); return new Saml2AuthenticationTokenConverter(registrations); } - @Bean - Saml2AuthenticationRequestResolver usingQueryParameter(RelyingPartyRegistrationRepository repository) { - var registrations = new DefaultRelyingPartyRegistrationResolver(repository); - return new OpenSaml4AuthenticationRequestResolver((request, id) -> - registrations.resolve(request, request.getParameter("id"))); - } - @Bean @Order(-101) FilterRegistrationBean metadata(Iterable repository) { @@ -95,10 +85,11 @@ public class SecurityConfiguration { @Value("classpath:credentials/rp-private.key") RSAPrivateKey key, @Value("classpath:credentials/rp-certificate.crt") File cert) { Saml2X509Credential signing = Saml2X509Credential.signing(key, x509Certificate(cert)); - Registration registration = properties.getRegistration().get("one"); + Registration registration = properties.getRegistration().values().iterator().next(); return new InMemoryRelyingPartyRegistrationRepository(RelyingPartyRegistrations .collectionFromMetadataLocation(registration.getAssertingparty().getMetadataUri()) .stream().map((builder) -> builder + .registrationId(UUID.randomUUID().toString()) .entityId(registration.getEntityId()) .assertionConsumerServiceLocation(registration.getAcs().getLocation()) .singleLogoutServiceLocation(registration.getSinglelogout().getUrl()) diff --git a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/application.yml b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/application.yml index 57be308..41d286a 100644 --- a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/application.yml +++ b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/application.yml @@ -8,12 +8,12 @@ spring: saml2: relyingparty: registration: - one: - entity-id: "{baseUrl}/saml2/service-provider-metadata/one" + sp: + entity-id: "http://localhost:8080/saml2/service-provider-metadata/one" singlelogout: binding: POST - url: "{baseUrl}/saml/logout" - responseUrl: "{baseUrl}/saml/SingleLogout" + url: "http://localhost:8080/saml/logout" + responseUrl: "http://localhost:8080/saml/SingleLogout" acs: - location: "{baseUrl}/saml/SSO" + location: "http://localhost:8080/saml/SSO" assertingparty.metadata-uri: https://dev-05937739.okta.com/app/exk598vc9bHhwoTXM5d7/sso/saml/metadata diff --git a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/templates/login.html b/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/templates/login.html deleted file mode 100644 index 34d8b57..0000000 --- a/servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/templates/login.html +++ /dev/null @@ -1,38 +0,0 @@ - - - - - - - Please sign in - - - - -
- - - - - - - -
-
- - \ No newline at end of file