Przeglądaj źródła

Adding keyInfo section to LogoutRequest from RP side

 Issue gh-10438
Vladimir Surcov 3 lat temu
rodzic
commit
7330ec41e4

+ 20 - 0
saml2/saml2-service-provider/src/main/java/org/springframework/security/saml2/provider/service/web/authentication/logout/OpenSamlSigningUtils.java

@@ -42,6 +42,9 @@ import org.opensaml.xmlsec.SignatureSigningParametersResolver;
 import org.opensaml.xmlsec.criterion.SignatureSigningConfigurationCriterion;
 import org.opensaml.xmlsec.crypto.XMLSigningUtil;
 import org.opensaml.xmlsec.impl.BasicSignatureSigningConfiguration;
+import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorManager;
+import org.opensaml.xmlsec.keyinfo.NamedKeyInfoGeneratorManager;
+import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
 import org.opensaml.xmlsec.signature.SignableXMLObject;
 import org.opensaml.xmlsec.signature.support.SignatureConstants;
 import org.opensaml.xmlsec.signature.support.SignatureSupport;
@@ -103,6 +106,7 @@ final class OpenSamlSigningUtils {
 		signingConfiguration.setSignatureAlgorithms(algorithms);
 		signingConfiguration.setSignatureReferenceDigestMethods(digests);
 		signingConfiguration.setSignatureCanonicalizationAlgorithm(canonicalization);
+		signingConfiguration.setKeyInfoGeneratorManager(buildSignatureKeyInfoGeneratorManager());
 		criteria.add(new SignatureSigningConfigurationCriterion(signingConfiguration));
 		try {
 			SignatureSigningParameters parameters = resolver.resolveSingle(criteria);
@@ -114,6 +118,22 @@ final class OpenSamlSigningUtils {
 		}
 	}
 
+	private static NamedKeyInfoGeneratorManager buildSignatureKeyInfoGeneratorManager() {
+		final NamedKeyInfoGeneratorManager namedManager = new NamedKeyInfoGeneratorManager();
+
+		namedManager.setUseDefaultManager(true);
+		final KeyInfoGeneratorManager defaultManager = namedManager.getDefaultManager();
+
+		// Generator for X509Credentials
+		final X509KeyInfoGeneratorFactory x509Factory = new X509KeyInfoGeneratorFactory();
+		x509Factory.setEmitEntityCertificate(true);
+		x509Factory.setEmitEntityCertificateChain(true);
+
+		defaultManager.registerFactory(x509Factory);
+
+		return namedManager;
+	}
+
 	private static List<Credential> resolveSigningCredentials(RelyingPartyRegistration relyingPartyRegistration) {
 		List<Credential> credentials = new ArrayList<>();
 		for (Saml2X509Credential x509Credential : relyingPartyRegistration.getSigningX509Credentials()) {

+ 16 - 0
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/TestOpenSamlObjects.java

@@ -384,6 +384,22 @@ public final class TestOpenSamlObjects {
 		return logoutResponse;
 	}
 
+	public static LogoutRequest relyingPartyLogoutRequest(RelyingPartyRegistration registration) {
+		LogoutRequestBuilder logoutRequestBuilder = new LogoutRequestBuilder();
+		LogoutRequest logoutRequest = logoutRequestBuilder.buildObject();
+		logoutRequest.setID("id");
+		NameIDBuilder nameIdBuilder = new NameIDBuilder();
+		NameID nameId = nameIdBuilder.buildObject();
+		nameId.setValue("user");
+		logoutRequest.setNameID(nameId);
+		IssuerBuilder issuerBuilder = new IssuerBuilder();
+		Issuer issuer = issuerBuilder.buildObject();
+		issuer.setValue(registration.getAssertingPartyDetails().getEntityId());
+		logoutRequest.setIssuer(issuer);
+		logoutRequest.setDestination(registration.getAssertingPartyDetails().getSingleLogoutServiceLocation());
+		return logoutRequest;
+	}
+
 	static <T extends XMLObject> T build(QName qName) {
 		return (T) XMLObjectProviderRegistrySupport.getBuilderFactory().getBuilder(qName).buildObject(qName);
 	}

+ 20 - 0
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/authentication/logout/OpenSamlSigningUtils.java

@@ -42,6 +42,9 @@ import org.opensaml.xmlsec.SignatureSigningParametersResolver;
 import org.opensaml.xmlsec.criterion.SignatureSigningConfigurationCriterion;
 import org.opensaml.xmlsec.crypto.XMLSigningUtil;
 import org.opensaml.xmlsec.impl.BasicSignatureSigningConfiguration;
+import org.opensaml.xmlsec.keyinfo.KeyInfoGeneratorManager;
+import org.opensaml.xmlsec.keyinfo.NamedKeyInfoGeneratorManager;
+import org.opensaml.xmlsec.keyinfo.impl.X509KeyInfoGeneratorFactory;
 import org.opensaml.xmlsec.signature.SignableXMLObject;
 import org.opensaml.xmlsec.signature.support.SignatureConstants;
 import org.opensaml.xmlsec.signature.support.SignatureSupport;
@@ -103,6 +106,7 @@ final class OpenSamlSigningUtils {
 		signingConfiguration.setSignatureAlgorithms(algorithms);
 		signingConfiguration.setSignatureReferenceDigestMethods(digests);
 		signingConfiguration.setSignatureCanonicalizationAlgorithm(canonicalization);
+		signingConfiguration.setKeyInfoGeneratorManager(buildSignatureKeyInfoGeneratorManager());
 		criteria.add(new SignatureSigningConfigurationCriterion(signingConfiguration));
 		try {
 			SignatureSigningParameters parameters = resolver.resolveSingle(criteria);
@@ -114,6 +118,22 @@ final class OpenSamlSigningUtils {
 		}
 	}
 
+	private static NamedKeyInfoGeneratorManager buildSignatureKeyInfoGeneratorManager() {
+		final NamedKeyInfoGeneratorManager namedManager = new NamedKeyInfoGeneratorManager();
+
+		namedManager.setUseDefaultManager(true);
+		final KeyInfoGeneratorManager defaultManager = namedManager.getDefaultManager();
+
+		// Generator for X509Credentials
+		final X509KeyInfoGeneratorFactory x509Factory = new X509KeyInfoGeneratorFactory();
+		x509Factory.setEmitEntityCertificate(true);
+		x509Factory.setEmitEntityCertificateChain(true);
+
+		defaultManager.registerFactory(x509Factory);
+
+		return namedManager;
+	}
+
 	private static List<Credential> resolveSigningCredentials(RelyingPartyRegistration relyingPartyRegistration) {
 		List<Credential> credentials = new ArrayList<>();
 		for (Saml2X509Credential x509Credential : relyingPartyRegistration.getSigningX509Credentials()) {

+ 57 - 0
saml2/saml2-service-provider/src/test/java/org/springframework/security/saml2/provider/service/web/authentication/logout/Saml2LogoutSigningUtilsTests.java

@@ -0,0 +1,57 @@
+/*
+ * 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.
+ */
+
+package org.springframework.security.saml2.provider.service.web.authentication.logout;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.opensaml.saml.saml2.core.LogoutRequest;
+import org.opensaml.xmlsec.signature.Signature;
+
+import org.springframework.security.saml2.core.TestSaml2X509Credentials;
+import org.springframework.security.saml2.provider.service.authentication.TestOpenSamlObjects;
+import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+/**
+ * Test open SAML Logout signatures
+ */
+public class Saml2LogoutSigningUtilsTests {
+
+	private RelyingPartyRegistration registration;
+
+	@BeforeEach
+	public void setup() {
+		this.registration = RelyingPartyRegistration.withRegistrationId("saml-idp")
+				.entityId("https://some.idp.example.com/entity-id").signingX509Credentials((c) -> {
+					c.add(TestSaml2X509Credentials.relyingPartySigningCredential());
+					c.add(TestSaml2X509Credentials.assertingPartySigningCredential());
+				}).assertingPartyDetails((c) -> c.entityId("https://some.idp.example.com/entity-id")
+						.singleSignOnServiceLocation("https://some.idp.example.com/service-location"))
+				.build();
+	}
+
+	@Test
+	public void whenSigningLogoutRequestRPThenKeyInfoIsPartOfTheSignature() {
+		LogoutRequest logoutRequest = TestOpenSamlObjects.relyingPartyLogoutRequest(this.registration);
+		OpenSamlSigningUtils.sign(logoutRequest, this.registration);
+		Signature signature = logoutRequest.getSignature();
+		assertThat(signature).isNotNull();
+		assertThat(signature.getKeyInfo()).isNotNull();
+	}
+
+}