浏览代码

Polish Federation Example

Issue gh-122
Josh Cummings 2 年之前
父节点
当前提交
7ffe455088

+ 17 - 8
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;

+ 0 - 22
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<RelyingPartyRegistration> registrations;
-
-	@Autowired
-	public IndexController(Iterable<RelyingPartyRegistration> 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<String> urls = new ArrayList<>();
-		for (RelyingPartyRegistration registration : this.registrations) {
-			urls.add("/saml/login?id=" + registration.getRegistrationId());
-		}
-		model.addAttribute("urls", urls);
-		return "login";
-	}
-
 }

+ 2 - 3
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<String, String> urlMapping = Map.of("/saml/SSO", "/login/saml2/sso/one",
-			"/saml/login", "/saml2/authenticate/one",
+	private static final Map<String, String> 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();

+ 6 - 15
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<Saml2MetadataFilter> metadata(Iterable<RelyingPartyRegistration> 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())

+ 5 - 5
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

+ 0 - 38
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/templates/login.html

@@ -1,38 +0,0 @@
-<!--
-  ~ Copyright 2002-2021 the original author or authors.
-  ~
-  ~ Licensed under the Apache License, Version 2.0 (the "License");
-  ~ you may not use this file except in compliance with the License.
-  ~ You may obtain a copy of the License at
-  ~
-  ~      https://www.apache.org/licenses/LICENSE-2.0
-  ~
-  ~ Unless required by applicable law or agreed to in writing, software
-  ~ distributed under the License is distributed on an "AS IS" BASIS,
-  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-  ~ See the License for the specific language governing permissions and
-  ~ limitations under the License.
-  -->
-
-<!doctype html>
-<html lang="en">
-<head>
-    <meta charset="utf-8">
-    <title>Please sign in</title>
-    <link href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" rel="stylesheet"
-          integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous">
-    <link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet" crossorigin="anonymous">
-</head>
-<body data-new-gr-c-s-check-loaded="8.904.0" data-gr-ext-installed="">
-<div class="container">
-    <h2 class="form-signin-heading">Login with SAML 2.0</h2>
-    <table class="table table-striped">
-        <tbody>
-        <tr th:each="url : ${urls}">
-            <td><a th:href="${url}"><span th:text="${url}"></span></a></td>
-        </tr>
-        </tbody>
-    </table>
-</div>
-</body>
-</html>