Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
* Copyright 2002-2022 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 org.opensaml.saml.saml2.metadata.EntityDescriptor;

/**
* A {@link RelyingPartyRegistration.AssertingPartyDetails} that contains
* OpenSAML-specific members
*
* @author Josh Cummings
* @since 5.7
*/
public final class OpenSamlAssertingPartyDetails extends RelyingPartyRegistration.AssertingPartyDetails {

private final EntityDescriptor descriptor;

OpenSamlAssertingPartyDetails(RelyingPartyRegistration.AssertingPartyDetails details, EntityDescriptor descriptor) {
super(details.getEntityId(), details.getWantAuthnRequestsSigned(), details.getSigningAlgorithms(),
details.getVerificationX509Credentials(), details.getEncryptionX509Credentials(),
details.getSingleSignOnServiceLocation(), details.getSingleSignOnServiceBinding(),
details.getSingleLogoutServiceLocation(), details.getSingleLogoutServiceResponseLocation(),
details.getSingleLogoutServiceBinding());
this.descriptor = descriptor;
}

/**
* Get the {@link EntityDescriptor} that underlies this
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails}
* @return the {@link EntityDescriptor}
*/
public EntityDescriptor getEntityDescriptor() {
return this.descriptor;
}

/**
* Use this {@link EntityDescriptor} to begin building an
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails}
* @param entity the {@link EntityDescriptor} to use
* @return the
* {@link org.springframework.security.saml2.provider.service.registration.OpenSamlAssertingPartyDetails.Builder}
* for further configurations
*/
public static OpenSamlAssertingPartyDetails.Builder withEntityDescriptor(EntityDescriptor entity) {
return new OpenSamlAssertingPartyDetails.Builder(entity);
}

/**
* An OpenSAML version of
* {@link org.springframework.security.saml2.provider.service.registration.RelyingPartyRegistration.AssertingPartyDetails.Builder}
* that contains the underlying {@link EntityDescriptor}
*/
public static final class Builder extends RelyingPartyRegistration.AssertingPartyDetails.Builder {

private final EntityDescriptor descriptor;

private Builder(EntityDescriptor descriptor) {
this.descriptor = descriptor;
}

/**
* Build an
* {@link org.springframework.security.saml2.provider.service.registration.OpenSamlAssertingPartyDetails}
* @return
*/
@Override
public OpenSamlAssertingPartyDetails build() {
return new OpenSamlAssertingPartyDetails(super.build(), this.descriptor);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@
import org.springframework.security.saml2.core.OpenSamlInitializationService;
import org.springframework.security.saml2.core.Saml2X509Credential;

class OpenSamlAssertingPartyMetadataConverter {
class OpenSamlMetadataAssertingPartyDetailsConverter {

static {
OpenSamlInitializationService.initialize();
Expand All @@ -58,15 +58,15 @@ class OpenSamlAssertingPartyMetadataConverter {
private final ParserPool parserPool;

/**
* Creates a {@link OpenSamlAssertingPartyMetadataConverter}
* Creates a {@link OpenSamlMetadataAssertingPartyDetailsConverter}
*/
OpenSamlAssertingPartyMetadataConverter() {
OpenSamlMetadataAssertingPartyDetailsConverter() {
this.registry = ConfigurationService.get(XMLObjectProviderRegistry.class);
this.parserPool = this.registry.getParserPool();
}

Collection<RelyingPartyRegistration.Builder> convert(InputStream inputStream) {
List<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
Collection<RelyingPartyRegistration.AssertingPartyDetails.Builder> convert(InputStream inputStream) {
List<RelyingPartyRegistration.AssertingPartyDetails.Builder> builders = new ArrayList<>();
XMLObject xmlObject = xmlObject(inputStream);
if (xmlObject instanceof EntitiesDescriptor) {
EntitiesDescriptor descriptors = (EntitiesDescriptor) xmlObject;
Expand All @@ -82,7 +82,7 @@ Collection<RelyingPartyRegistration.Builder> convert(InputStream inputStream) {
throw new Saml2Exception("Unsupported element of type " + xmlObject.getClass());
}

RelyingPartyRegistration.Builder convert(EntityDescriptor descriptor) {
RelyingPartyRegistration.AssertingPartyDetails.Builder convert(EntityDescriptor descriptor) {
IDPSSODescriptor idpssoDescriptor = descriptor.getIDPSSODescriptor(SAMLConstants.SAML20P_NS);
if (idpssoDescriptor == null) {
throw new Saml2Exception("Metadata response is missing the necessary IDPSSODescriptor element");
Expand Down Expand Up @@ -114,15 +114,14 @@ RelyingPartyRegistration.Builder convert(EntityDescriptor descriptor) {
throw new Saml2Exception(
"Metadata response is missing verification certificates, necessary for verifying SAML assertions");
}
RelyingPartyRegistration.Builder builder = RelyingPartyRegistration.withRegistrationId(descriptor.getEntityID())
.assertingPartyDetails((party) -> party.entityId(descriptor.getEntityID())
.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
.verificationX509Credentials((c) -> c.addAll(verification))
.encryptionX509Credentials((c) -> c.addAll(encryption)));
RelyingPartyRegistration.AssertingPartyDetails.Builder party = OpenSamlAssertingPartyDetails
.withEntityDescriptor(descriptor).entityId(descriptor.getEntityID())
.wantAuthnRequestsSigned(Boolean.TRUE.equals(idpssoDescriptor.getWantAuthnRequestsSigned()))
.verificationX509Credentials((c) -> c.addAll(verification))
.encryptionX509Credentials((c) -> c.addAll(encryption));
List<SigningMethod> signingMethods = signingMethods(idpssoDescriptor);
for (SigningMethod method : signingMethods) {
builder.assertingPartyDetails(
(party) -> party.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm())));
party.signingAlgorithms((algorithms) -> algorithms.add(method.getAlgorithm()));
}
if (idpssoDescriptor.getSingleSignOnServices().isEmpty()) {
throw new Saml2Exception(
Expand All @@ -139,9 +138,7 @@ else if (singleSignOnService.getBinding().equals(Saml2MessageBinding.REDIRECT.ge
else {
continue;
}
builder.assertingPartyDetails(
(party) -> party.singleSignOnServiceLocation(singleSignOnService.getLocation())
.singleSignOnServiceBinding(binding));
party.singleSignOnServiceLocation(singleSignOnService.getLocation()).singleSignOnServiceBinding(binding);
break;
}
for (SingleLogoutService singleLogoutService : idpssoDescriptor.getSingleLogoutServices()) {
Expand All @@ -157,12 +154,11 @@ else if (singleLogoutService.getBinding().equals(Saml2MessageBinding.REDIRECT.ge
}
String responseLocation = (singleLogoutService.getResponseLocation() == null)
? singleLogoutService.getLocation() : singleLogoutService.getResponseLocation();
builder.assertingPartyDetails(
(party) -> party.singleLogoutServiceLocation(singleLogoutService.getLocation())
.singleLogoutServiceResponseLocation(responseLocation).singleLogoutServiceBinding(binding));
party.singleLogoutServiceLocation(singleLogoutService.getLocation())
.singleLogoutServiceResponseLocation(responseLocation).singleLogoutServiceBinding(binding);
break;
}
return builder;
return party;
}

private List<X509Certificate> certificates(KeyDescriptor keyDescriptor) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,13 @@ public class OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter
OpenSamlInitializationService.initialize();
}

private final OpenSamlAssertingPartyMetadataConverter converter;
private final OpenSamlMetadataAssertingPartyDetailsConverter converter;

/**
* Creates a {@link OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter}
*/
public OpenSamlRelyingPartyRegistrationBuilderHttpMessageConverter() {
this.converter = new OpenSamlAssertingPartyMetadataConverter();
this.converter = new OpenSamlMetadataAssertingPartyDetailsConverter();
}

@Override
Expand All @@ -89,7 +89,8 @@ public List<MediaType> getSupportedMediaTypes() {
@Override
public RelyingPartyRegistration.Builder read(Class<? extends RelyingPartyRegistration.Builder> clazz,
HttpInputMessage inputMessage) throws IOException, HttpMessageNotReadableException {
return this.converter.convert(inputMessage.getBody()).iterator().next();
return RelyingPartyRegistration
.withAssertingPartyDetails(this.converter.convert(inputMessage.getBody()).iterator().next().build());
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2002-2021 the original author or authors.
* Copyright 2002-2022 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.
Expand Down Expand Up @@ -422,6 +422,21 @@ public static Builder withRegistrationId(String registrationId) {
return new Builder(registrationId);
}

public static Builder withAssertingPartyDetails(AssertingPartyDetails assertingPartyDetails) {
Assert.notNull(assertingPartyDetails, "assertingPartyDetails cannot be null");
return withRegistrationId(assertingPartyDetails.getEntityId()).assertingPartyDetails((party) -> party
.entityId(assertingPartyDetails.getEntityId())
.wantAuthnRequestsSigned(assertingPartyDetails.getWantAuthnRequestsSigned())
.signingAlgorithms((algorithms) -> algorithms.addAll(assertingPartyDetails.getSigningAlgorithms()))
.verificationX509Credentials((c) -> c.addAll(assertingPartyDetails.getVerificationX509Credentials()))
.encryptionX509Credentials((c) -> c.addAll(assertingPartyDetails.getEncryptionX509Credentials()))
.singleSignOnServiceLocation(assertingPartyDetails.getSingleSignOnServiceLocation())
.singleSignOnServiceBinding(assertingPartyDetails.getSingleSignOnServiceBinding())
.singleLogoutServiceLocation(assertingPartyDetails.getSingleLogoutServiceLocation())
.singleLogoutServiceResponseLocation(assertingPartyDetails.getSingleLogoutServiceResponseLocation())
.singleLogoutServiceBinding(assertingPartyDetails.getSingleLogoutServiceBinding()));
}

/**
* Creates a {@code RelyingPartyRegistration} {@link Builder} based on an existing
* object
Expand Down Expand Up @@ -510,7 +525,7 @@ private static org.springframework.security.saml2.credentials.Saml2X509Credentia
*
* @since 5.4
*/
public static final class AssertingPartyDetails {
public static class AssertingPartyDetails {

private final String entityId;

Expand All @@ -532,7 +547,7 @@ public static final class AssertingPartyDetails {

private final Saml2MessageBinding singleLogoutServiceBinding;

private AssertingPartyDetails(String entityId, boolean wantAuthnRequestsSigned, List<String> signingAlgorithms,
AssertingPartyDetails(String entityId, boolean wantAuthnRequestsSigned, List<String> signingAlgorithms,
Collection<Saml2X509Credential> verificationX509Credentials,
Collection<Saml2X509Credential> encryptionX509Credentials, String singleSignOnServiceLocation,
Saml2MessageBinding singleSignOnServiceBinding, String singleLogoutServiceLocation,
Expand Down Expand Up @@ -701,7 +716,7 @@ public Saml2MessageBinding getSingleLogoutServiceBinding() {
return this.singleLogoutServiceBinding;
}

public static final class Builder {
public static class Builder {

private String entityId;

Expand Down Expand Up @@ -951,7 +966,7 @@ public Saml2MessageBinding getBinding() {
@Deprecated
public static final class Builder {

private final AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();
private AssertingPartyDetails.Builder assertingPartyDetailsBuilder = new AssertingPartyDetails.Builder();

/**
* Set the asserting party's <a href=
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,13 @@

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}
Expand All @@ -34,7 +36,7 @@
*/
public final class RelyingPartyRegistrations {

private static final OpenSamlAssertingPartyMetadataConverter assertingPartyMetadataConverter = new OpenSamlAssertingPartyMetadataConverter();
private static final OpenSamlMetadataAssertingPartyDetailsConverter assertingPartyMetadataConverter = new OpenSamlMetadataAssertingPartyDetailsConverter();

private static final ResourceLoader resourceLoader = new DefaultResourceLoader();

Expand Down Expand Up @@ -123,7 +125,7 @@ public static RelyingPartyRegistration.Builder fromMetadataLocation(String metad
* @since 5.6
*/
public static RelyingPartyRegistration.Builder fromMetadata(InputStream source) {
return assertingPartyMetadataConverter.convert(source).iterator().next();
return collectionFromMetadata(source).iterator().next();
}

/**
Expand Down Expand Up @@ -213,7 +215,11 @@ public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadat
* @since 5.7
*/
public static Collection<RelyingPartyRegistration.Builder> collectionFromMetadata(InputStream source) {
return assertingPartyMetadataConverter.convert(source);
Collection<RelyingPartyRegistration.Builder> builders = new ArrayList<>();
for (AssertingPartyDetails.Builder builder : assertingPartyMetadataConverter.convert(source)) {
builders.add(RelyingPartyRegistration.withAssertingPartyDetails(builder.build()));
}
return builders;
}

}
Loading