mirror of
				https://github.com/spring-projects/spring-security.git
				synced 2025-10-31 14:48:54 +00:00 
			
		
		
		
	Merge branch '6.0.x'
Closes gh-12800
This commit is contained in:
		
						commit
						41fadaecd3
					
				| @ -1,5 +1,36 @@ | ||||
| [[servlet-saml2login-metadata]] | ||||
| = Producing `<saml2:SPSSODescriptor>` Metadata | ||||
| = Saml 2.0 Metadata | ||||
| 
 | ||||
| Spring Security can <<parsing-asserting-party-metadata,parse asserting party metadata>> to produce an `AssertingPartyDetails` instance as well as <<publishing-relying-party-metadata,publish relying party metadata>> from a `RelyingPartyRegistration` instance. | ||||
| 
 | ||||
| [[parsing-asserting-party-metadata]] | ||||
| == Parsing `<saml2:IDPSSODescriptor>` metadata | ||||
| 
 | ||||
| You can parse an asserting party's metadata xref:servlet/saml2/login/overview.adoc#servlet-saml2login-relyingpartyregistrationrepository[using `RelyingPartyRegistrations`]. | ||||
| 
 | ||||
| When using the OpenSAML vendor support, the resulting `AssertingPartyDetails` will be of type `OpenSamlAssertingPartyDetails`. | ||||
| This means you'll be able to do get the underlying OpenSAML XMLObject by doing the following: | ||||
| 
 | ||||
| ==== | ||||
| .Java | ||||
| [source,java,role="primary"] | ||||
| ---- | ||||
| OpenSamlAssertingPartyDetails details = (OpenSamlAssertingPartyDetails) | ||||
|         registration.getAssertingPartyDetails(); | ||||
| EntityDescriptor openSamlEntityDescriptor = details.getEntityDescriptor(); | ||||
| ---- | ||||
| 
 | ||||
| .Kotlin | ||||
| [source,kotlin,role="secondary"] | ||||
| ---- | ||||
| val details: OpenSamlAssertingPartyDetails = | ||||
|         registration.getAssertingPartyDetails() as OpenSamlAssertingPartyDetails; | ||||
| val openSamlEntityDescriptor: EntityDescriptor = details.getEntityDescriptor(); | ||||
| ---- | ||||
| ==== | ||||
| 
 | ||||
| [[publishing-relying-party-metadata]] | ||||
| == Producing `<saml2:SPSSODescriptor>` Metadata | ||||
| 
 | ||||
| You can publish a metadata endpoint by adding the `Saml2MetadataFilter` to the filter chain, as you'll see below: | ||||
| 
 | ||||
|  | ||||
| @ -0,0 +1,35 @@ | ||||
| /* | ||||
|  * Copyright 2002-2023 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.registration; | ||||
| 
 | ||||
| import java.io.InputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| class OpenSamlMetadataRelyingPartyRegistrationConverter { | ||||
| 
 | ||||
| 	private final OpenSamlMetadataAssertingPartyDetailsConverter converter = new OpenSamlMetadataAssertingPartyDetailsConverter(); | ||||
| 
 | ||||
| 	Collection<RelyingPartyRegistration.Builder> convert(InputStream source) { | ||||
| 		Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>(); | ||||
| 		for (RelyingPartyRegistration.AssertingPartyDetails.Builder builder : this.converter.convert(source)) { | ||||
| 			builders.add(new RelyingPartyRegistration.Builder(builder)); | ||||
| 		} | ||||
| 		return builders; | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright 2002-2022 the original author or authors. | ||||
|  * Copyright 2002-2023 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. | ||||
| @ -89,8 +89,7 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter | ||||
| 	@Override | ||||
| 	public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz, | ||||
| 			HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException { | ||||
| 		return RelyingPartyRegistration | ||||
| 				.withAssertingPartyDetails(this.converter.convert(inputMessage.getBody()).iterator().next().build()); | ||||
| 		return new RelyingPartyRegistration.Builder(this.converter.convert(inputMessage.getBody()).iterator().next()); | ||||
| 	} | ||||
| 
 | ||||
| 	@Override | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright 2002-2022 the original author or authors. | ||||
|  * Copyright 2002-2023 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. | ||||
| @ -26,6 +26,7 @@ import java.util.function.Consumer; | ||||
| 
 | ||||
| import org.opensaml.xmlsec.signature.support.SignatureConstants; | ||||
| 
 | ||||
| import org.springframework.core.convert.converter.Converter; | ||||
| import org.springframework.security.saml2.core.Saml2X509Credential; | ||||
| import org.springframework.util.Assert; | ||||
| import org.springframework.util.CollectionUtils; | ||||
| @ -737,7 +738,7 @@ public final class RelyingPartyRegistration { | ||||
| 
 | ||||
| 	public static final class Builder { | ||||
| 
 | ||||
| 		private String registrationId; | ||||
| 		private Converter<AssertingPartyDetails, String> registrationId = AssertingPartyDetails::getEntityId; | ||||
| 
 | ||||
| 		private String entityId = "{baseUrl}/saml2/service-provider-metadata/{registrationId}"; | ||||
| 
 | ||||
| @ -757,10 +758,15 @@ public final class RelyingPartyRegistration { | ||||
| 
 | ||||
| 		private String nameIdFormat = null; | ||||
| 
 | ||||
| 		private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder(); | ||||
| 		private AssertingPartyDetails.Builder assertingPartyDetailsBuilder; | ||||
| 
 | ||||
| 		private Builder(String registrationId) { | ||||
| 			this.registrationId = registrationId; | ||||
| 			this.registrationId = (party) -> registrationId; | ||||
| 			this.assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder(); | ||||
| 		} | ||||
| 
 | ||||
| 		Builder(AssertingPartyDetails.Builder builder) { | ||||
| 			this.assertingPartyDetailsBuilder = builder; | ||||
| 		} | ||||
| 
 | ||||
| 		/** | ||||
| @ -769,7 +775,7 @@ public final class RelyingPartyRegistration { | ||||
| 		 * @return this object | ||||
| 		 */ | ||||
| 		public Builder registrationId(String id) { | ||||
| 			this.registrationId = id; | ||||
| 			this.registrationId = (party) -> id; | ||||
| 			return this; | ||||
| 		} | ||||
| 
 | ||||
| @ -967,11 +973,12 @@ public final class RelyingPartyRegistration { | ||||
| 				this.singleLogoutServiceBindings.add(Saml2MessageBinding.POST); | ||||
| 			} | ||||
| 
 | ||||
| 			return new RelyingPartyRegistration(this.registrationId, this.entityId, | ||||
| 					this.assertionConsumerServiceLocation, this.assertionConsumerServiceBinding, | ||||
| 					this.singleLogoutServiceLocation, this.singleLogoutServiceResponseLocation, | ||||
| 					this.singleLogoutServiceBindings, this.assertingPartyDetailsBuilder.build(), this.nameIdFormat, | ||||
| 					this.decryptionX509Credentials, this.signingX509Credentials); | ||||
| 			AssertingPartyDetails party = this.assertingPartyDetailsBuilder.build(); | ||||
| 			String registrationId = this.registrationId.convert(party); | ||||
| 			return new RelyingPartyRegistration(registrationId, this.entityId, this.assertionConsumerServiceLocation, | ||||
| 					this.assertionConsumerServiceBinding, this.singleLogoutServiceLocation, | ||||
| 					this.singleLogoutServiceResponseLocation, this.singleLogoutServiceBindings, party, | ||||
| 					this.nameIdFormat, this.decryptionX509Credentials, this.signingX509Credentials); | ||||
| 		} | ||||
| 
 | ||||
| 	} | ||||
|  | ||||
| @ -1,5 +1,5 @@ | ||||
| /* | ||||
|  * Copyright 2002-2022 the original author or authors. | ||||
|  * Copyright 2002-2023 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. | ||||
| @ -18,13 +18,11 @@ package org.springframework.security.saml2.provider.service.registration; | ||||
| 
 | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collection; | ||||
| 
 | ||||
| import org.springframework.core.io.DefaultResourceLoader; | ||||
| import org.springframework.core.io.ResourceLoader; | ||||
| import org.springframework.security.saml2.Saml2Exception; | ||||
| import org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails; | ||||
| 
 | ||||
| /** | ||||
|  * A utility class for constructing instances of {@link RelyingPartyRegistration} | ||||
| @ -36,7 +34,7 @@ import org.springframework.security.saml2.provider.service.registration.RelyingP | ||||
|  */ | ||||
| public final class RelyingPartyRegistrations { | ||||
| 
 | ||||
| 	private static final OpenSamlMetadataAssertingPartyDetailsConverter assertingPartyMetadataConverter = new OpenSamlMetadataAssertingPartyDetailsConverter(); | ||||
| 	private static final OpenSamlMetadataRelyingPartyRegistrationConverter relyingPartyRegistrationConverter = new OpenSamlMetadataRelyingPartyRegistrationConverter(); | ||||
| 
 | ||||
| 	private static final ResourceLoader resourceLoader = new DefaultResourceLoader(); | ||||
| 
 | ||||
| @ -215,11 +213,7 @@ public final class RelyingPartyRegistrations { | ||||
| 	 * @since 5.7 | ||||
| 	 */ | ||||
| 	public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadata(InputStream source) { | ||||
| 		Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>(); | ||||
| 		for (AssertingPartyDetails.Builder builder : assertingPartyMetadataConverter.convert(source)) { | ||||
| 			builders.add(RelyingPartyRegistration.withAssertingPartyDetails(builder.build())); | ||||
| 		} | ||||
| 		return builders; | ||||
| 		return relyingPartyRegistrationConverter.convert(source); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | ||||
| @ -0,0 +1,57 @@ | ||||
| /* | ||||
|  * Copyright 2002-2023 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.registration; | ||||
| 
 | ||||
| import java.io.BufferedReader; | ||||
| import java.io.ByteArrayInputStream; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.nio.charset.StandardCharsets; | ||||
| import java.util.stream.Collectors; | ||||
| 
 | ||||
| import org.junit.jupiter.api.BeforeEach; | ||||
| import org.junit.jupiter.api.Test; | ||||
| 
 | ||||
| import org.springframework.core.io.ClassPathResource; | ||||
| 
 | ||||
| import static org.assertj.core.api.Assertions.assertThat; | ||||
| 
 | ||||
| public class OpenSamlMetadataRelyingPartyRegistrationConverterTests { | ||||
| 
 | ||||
| 	private OpenSamlMetadataRelyingPartyRegistrationConverter converter = new OpenSamlMetadataRelyingPartyRegistrationConverter(); | ||||
| 
 | ||||
| 	private String metadata; | ||||
| 
 | ||||
| 	@BeforeEach | ||||
| 	public void setup() throws Exception { | ||||
| 		ClassPathResource resource = new ClassPathResource("test-metadata.xml"); | ||||
| 		try (BufferedReader reader = new BufferedReader(new InputStreamReader(resource.getInputStream()))) { | ||||
| 			this.metadata = reader.lines().collect(Collectors.joining()); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	// gh-12667 | ||||
| 	@Test | ||||
| 	public void convertWhenDefaultsThenAssertingPartyInstanceOfOpenSaml() throws Exception { | ||||
| 		try (InputStream source = new ByteArrayInputStream(this.metadata.getBytes(StandardCharsets.UTF_8))) { | ||||
| 			this.converter.convert(source) | ||||
| 					.forEach((registration) -> assertThat(registration.build().getAssertingPartyDetails()) | ||||
| 							.isInstanceOf(OpenSamlAssertingPartyDetails.class)); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user