浏览代码

Polish saml-extension-federation Configuration

Josh Cummings 9 月之前
父节点
当前提交
0a7da94e22

+ 133 - 0
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/RelyingPartyMetadata.java

@@ -0,0 +1,133 @@
+/*
+ * Copyright 2002-2024 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.
+ */
+
+package example;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
+import java.security.interfaces.RSAPrivateKey;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.io.ApplicationResourceLoader;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.ResourceLoader;
+import org.springframework.security.converter.RsaKeyConverters;
+import org.springframework.security.saml2.core.Saml2X509Credential;
+import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
+import org.springframework.security.saml2.provider.service.registration.Saml2MessageBinding;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties("saml2")
+public class RelyingPartyMetadata {
+
+	private final ResourceLoader resourceLoader = new ApplicationResourceLoader();
+
+	private String entityId = "{baseUrl}/saml/metadata";
+
+	private String sso = "{baseUrl}/saml/SSO";
+
+	private SingleLogout slo = new SingleLogout();
+
+	private X509Certificate certificate;
+
+	private RSAPrivateKey key;
+
+	public RelyingPartyRegistration apply(RelyingPartyRegistration.Builder builder) {
+		Saml2X509Credential signing = Saml2X509Credential.signing(this.key, this.certificate);
+		return builder.entityId(this.entityId)
+			.assertionConsumerServiceLocation(this.sso)
+			.singleLogoutServiceBinding(this.slo.getBinding())
+			.singleLogoutServiceLocation(this.slo.getLocation())
+			.singleLogoutServiceResponseLocation(this.slo.getResponseLocation())
+			.signingX509Credentials((c) -> c.add(signing))
+			.build();
+	}
+
+	public void setEntityId(String entityId) {
+		this.entityId = entityId;
+	}
+
+	public void setSso(String sso) {
+		this.sso = sso;
+	}
+
+	public void setSlo(SingleLogout slo) {
+		this.slo = slo;
+	}
+
+	public void setCertificate(String certificate) {
+		Resource source = this.resourceLoader.getResource(certificate);
+		try (InputStream in = source.getInputStream()) {
+			CertificateFactory certificates = CertificateFactory.getInstance("X.509");
+			this.certificate = (X509Certificate) certificates.generateCertificate(in);
+		}
+		catch (CertificateException | IOException ex) {
+			throw new IllegalArgumentException(ex);
+		}
+	}
+
+	public void setKey(String key) {
+		Resource source = this.resourceLoader.getResource(key);
+		try (InputStream in = source.getInputStream()) {
+			this.key = RsaKeyConverters.pkcs8().convert(in);
+		}
+		catch (IOException ex) {
+			throw new IllegalArgumentException(ex);
+		}
+	}
+
+	public static class SingleLogout {
+
+		private Saml2MessageBinding binding = Saml2MessageBinding.REDIRECT;
+
+		private String location = "{baseUrl}/saml/logout";
+
+		private String responseLocation = "{baseUrl}/saml/SingleLogout";
+
+		public Saml2MessageBinding getBinding() {
+			return this.binding;
+		}
+
+		public void setBinding(Saml2MessageBinding binding) {
+			this.binding = binding;
+		}
+
+		public String getLocation() {
+			return this.location;
+		}
+
+		public void setLocation(String location) {
+			this.location = location;
+		}
+
+		public String getResponseLocation() {
+			if (this.responseLocation == null) {
+				return this.location;
+			}
+			return this.responseLocation;
+		}
+
+		public void setResponseLocation(String responseLocation) {
+			this.responseLocation = responseLocation;
+		}
+
+	}
+
+}

+ 10 - 39
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/java/example/SecurityConfiguration.java

@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2022 the original author or authors.
+ * Copyright 2002-2024 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.
@@ -16,26 +16,16 @@
 
 package example;
 
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.IOException;
-import java.io.InputStream;
-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 java.util.List;
 
 import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties;
-import org.springframework.boot.autoconfigure.security.saml2.Saml2RelyingPartyProperties.Registration;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.saml2.core.Saml2X509Credential;
 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.web.SecurityFilterChain;
 
@@ -60,32 +50,13 @@ public class SecurityConfiguration {
 	}
 
 	@Bean
-	InMemoryRelyingPartyRegistrationRepository repository(Saml2RelyingPartyProperties properties,
-			@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().values().iterator().next();
-		return new InMemoryRelyingPartyRegistrationRepository(RelyingPartyRegistrations
-			.collectionFromMetadataLocation(registration.getAssertingparty().getMetadataUri())
+	RelyingPartyRegistrationRepository registrations(RelyingPartyMetadata rp,
+			@Value("${saml2.ap.metadata}") String ap) {
+		List<RelyingPartyRegistration> registrations = RelyingPartyRegistrations.collectionFromMetadataLocation(ap)
 			.stream()
-			.map((builder) -> builder.registrationId(UUID.randomUUID().toString())
-				.entityId(registration.getEntityId())
-				.assertionConsumerServiceLocation(registration.getAcs().getLocation())
-				.singleLogoutServiceBinding(registration.getSinglelogout().getBinding())
-				.singleLogoutServiceLocation(registration.getSinglelogout().getUrl())
-				.singleLogoutServiceResponseLocation(registration.getSinglelogout().getResponseUrl())
-				.signingX509Credentials((credentials) -> credentials.add(signing))
-				.build())
-			.collect(Collectors.toList()));
-	}
-
-	X509Certificate x509Certificate(File location) {
-		try (InputStream source = new FileInputStream(location)) {
-			return (X509Certificate) CertificateFactory.getInstance("X.509").generateCertificate(source);
-		}
-		catch (CertificateException | IOException ex) {
-			throw new IllegalArgumentException(ex);
-		}
+			.map(rp::apply)
+			.toList();
+		return new InMemoryRelyingPartyRegistrationRepository(registrations);
 	}
 
 }

+ 5 - 12
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/application.yml

@@ -10,15 +10,8 @@ spring:
   security:
     filter:
       dispatcher-types: async, error, request, forward
-    saml2:
-      relyingparty:
-        registration:
-          metadata:
-            entity-id: "{baseUrl}/saml/metadata"
-            singlelogout:
-              binding: REDIRECT
-              url: "{baseUrl}/saml/logout"
-              responseUrl: "{baseUrl}/saml/SingleLogout"
-            acs:
-              location: "{baseUrl}/saml/SSO"
-            assertingparty.metadata-uri:  http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php
+
+saml2:
+  certificate: classpath:credentials/rp-certificate.crt
+  key: classpath:credentials/rp-private.key
+  ap.metadata: http://idp-one.7f000001.nip.io/simplesaml/saml2/idp/metadata.php

+ 0 - 24
servlet/spring-boot/java/saml2/saml-extension-federation/src/main/resources/credentials/idp-certificate.crt

@@ -1,24 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEEzCCAvugAwIBAgIJAIc1qzLrv+5nMA0GCSqGSIb3DQEBCwUAMIGfMQswCQYD
-VQQGEwJVUzELMAkGA1UECAwCQ08xFDASBgNVBAcMC0Nhc3RsZSBSb2NrMRwwGgYD
-VQQKDBNTYW1sIFRlc3RpbmcgU2VydmVyMQswCQYDVQQLDAJJVDEgMB4GA1UEAwwX
-c2ltcGxlc2FtbHBocC5jZmFwcHMuaW8xIDAeBgkqhkiG9w0BCQEWEWZoYW5pa0Bw
-aXZvdGFsLmlvMB4XDTE1MDIyMzIyNDUwM1oXDTI1MDIyMjIyNDUwM1owgZ8xCzAJ
-BgNVBAYTAlVTMQswCQYDVQQIDAJDTzEUMBIGA1UEBwwLQ2FzdGxlIFJvY2sxHDAa
-BgNVBAoME1NhbWwgVGVzdGluZyBTZXJ2ZXIxCzAJBgNVBAsMAklUMSAwHgYDVQQD
-DBdzaW1wbGVzYW1scGhwLmNmYXBwcy5pbzEgMB4GCSqGSIb3DQEJARYRZmhhbmlr
-QHBpdm90YWwuaW8wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC4cn62
-E1xLqpN34PmbrKBbkOXFjzWgJ9b+pXuaRft6A339uuIQeoeH5qeSKRVTl32L0gdz
-2ZivLwZXW+cqvftVW1tvEHvzJFyxeTW3fCUeCQsebLnA2qRa07RkxTo6Nf244mWW
-RDodcoHEfDUSbxfTZ6IExSojSIU2RnD6WllYWFdD1GFpBJOmQB8rAc8wJIBdHFdQ
-nX8Ttl7hZ6rtgqEYMzYVMuJ2F2r1HSU1zSAvwpdYP6rRGFRJEfdA9mm3WKfNLSc5
-cljz0X/TXy0vVlAV95l9qcfFzPmrkNIst9FZSwpvB49LyAVke04FQPPwLgVH4gph
-iJH3jvZ7I+J5lS8VAgMBAAGjUDBOMB0GA1UdDgQWBBTTyP6Cc5HlBJ5+ucVCwGc5
-ogKNGzAfBgNVHSMEGDAWgBTTyP6Cc5HlBJ5+ucVCwGc5ogKNGzAMBgNVHRMEBTAD
-AQH/MA0GCSqGSIb3DQEBCwUAA4IBAQAvMS4EQeP/ipV4jOG5lO6/tYCb/iJeAduO
-nRhkJk0DbX329lDLZhTTL/x/w/9muCVcvLrzEp6PN+VWfw5E5FWtZN0yhGtP9R+v
-ZnrV+oc2zGD+no1/ySFOe3EiJCO5dehxKjYEmBRv5sU/LZFKZpozKN/BMEa6CqLu
-xbzb7ykxVr7EVFXwltPxzE9TmL9OACNNyF5eJHWMRMllarUvkcXlh4pux4ks9e6z
-V9DQBy2zds9f1I3qxg0eX6JnGrXi/ZiCT+lJgVe3ZFXiejiLAiKB04sXW3ti0LW3
-lx13Y1YlQ4/tlpgTgfIJxKV6nyPiLoK0nywbMd+vpAirDt2Oc+hk
------END CERTIFICATE-----