[java-identity-provider] branch master updated: IDP-701 First pass at SAML metadata for CAS.
Marvin S. Addison
marvin.addison at gmail.com
Mon Jun 18 07:38:49 EDT 2018
This is an automated email from the git hooks/post-receive script.
serac pushed a commit to branch master
in repository java-identity-provider.
View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=cbfbd4c24e26d55d3de73f76a5d3916292096062
The following commit(s) were added to refs/heads/master by this push:
new cbfbd4c IDP-701 First pass at SAML metadata for CAS.
cbfbd4c is described below
commit cbfbd4c24e26d55d3de73f76a5d3916292096062
Author: Marvin S. Addison <serac at vt.edu>
AuthorDate: Mon Jun 18 07:37:07 2018 -0400
IDP-701 First pass at SAML metadata for CAS.
Index AssertionConsumerService URLs of CAS-specific SPSSODescriptor and
perform starts-with matching to find a matching entity.
---
idp-cas-impl/pom.xml | 5 +
.../flow/impl/BuildRelyingPartyContextAction.java | 34 +++-
.../cas/service/impl/MetadataServiceRegistry.java | 192 +++++++++++++++++++++
.../service/impl/MetadataServiceRegistryTest.java | 107 ++++++++++++
.../test/resources/metadata/cas-test-metadata.xml | 174 +++++++++++++++++++
idp-conf/src/main/resources/conf/cas-protocol.xml | 10 ++
.../resources/system/conf/cas-protocol-system.xml | 7 +-
.../main/resources/system/conf/services-system.xml | 4 +
.../system/flows/cas/cas-abstract-beans.xml | 4 +-
9 files changed, 527 insertions(+), 10 deletions(-)
diff --git a/idp-cas-impl/pom.xml b/idp-cas-impl/pom.xml
index 06d501f..6707b15 100644
--- a/idp-cas-impl/pom.xml
+++ b/idp-cas-impl/pom.xml
@@ -49,6 +49,11 @@
<version>${opensaml.version}</version>
</dependency>
<dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-saml-impl</artifactId>
+ <version>${opensaml.version}</version>
+ </dependency>
+ <dependency>
<groupId>${httpclient.groupId}</groupId>
<artifactId>httpclient</artifactId>
</dependency>
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java
index 21928a2..d23eab8 100644
--- a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/flow/impl/BuildRelyingPartyContextAction.java
@@ -17,6 +17,8 @@
package net.shibboleth.idp.cas.flow.impl;
+import java.util.Arrays;
+import java.util.List;
import javax.annotation.Nonnull;
import net.shibboleth.idp.cas.protocol.ProxyTicketRequest;
@@ -25,15 +27,19 @@ import net.shibboleth.idp.cas.protocol.TicketValidationRequest;
import net.shibboleth.idp.cas.service.Service;
import net.shibboleth.idp.cas.service.ServiceRegistry;
import net.shibboleth.idp.profile.context.RelyingPartyContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
import net.shibboleth.utilities.java.support.logic.Constraint;
import org.opensaml.profile.context.ProfileRequestContext;
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.webflow.execution.Event;
import org.springframework.webflow.execution.RequestContext;
/**
- * Creates the {@link RelyingPartyContext} as a child of the {@link ProfileRequestContext}.
+ * Creates the {@link RelyingPartyContext} as a child of the {@link ProfileRequestContext}. The component queries
+ * a configured list of {@link ServiceRegistry} until a result is found, otherwise the relying party is treated as
+ * unverified.
*
* @author Marvin S. Addison
*/
@@ -45,17 +51,19 @@ public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
/** Class logger. */
private final Logger log = LoggerFactory.getLogger(BuildRelyingPartyContextAction.class);
- /** Repository for verified CAS services (relying parties). */
+ /** List of registries to query for verified CAS services (relying parties). */
@Nonnull
- private final ServiceRegistry serviceRegistry;
+ @NotEmpty
+ private final List<ServiceRegistry> serviceRegistries;
+
/**
* Creates a new instance.
*
- * @param registry Service registry.
+ * @param registries One or more service registries to query for CAS services.
*/
- public BuildRelyingPartyContextAction(@Nonnull final ServiceRegistry registry) {
- this.serviceRegistry = Constraint.isNotNull(registry, "Service registry cannot be null");
+ public BuildRelyingPartyContextAction(@Nonnull @NotEmpty final ServiceRegistry ... registries) {
+ serviceRegistries = Arrays.asList(Constraint.isNotEmpty(registries, "Service registries cannot be null"));
}
@Nonnull
@@ -75,7 +83,7 @@ public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
} else {
throw new IllegalStateException("Service URL not found in flow state");
}
- Service service = serviceRegistry.lookup(serviceURL);
+ Service service = query(serviceURL);
final RelyingPartyContext rpc = new RelyingPartyContext();
rpc.setVerified(service != null);
rpc.setRelyingPartyId(serviceURL);
@@ -85,8 +93,20 @@ public class BuildRelyingPartyContextAction extends AbstractCASProtocolAction {
service = new Service(serviceURL, UNVERIFIED_GROUP, false);
log.debug("Setting up RP context for unverified relying party {}", service);
}
+ log.debug("Relying party context created for {}", service);
profileRequestContext.addSubcontext(rpc);
setCASService(profileRequestContext, service);
return null;
}
+
+ private Service query(final String serviceURL) {
+ for (ServiceRegistry registry : serviceRegistries) {
+ log.debug("Querying {} for CAS service URL {}", registry.getClass().getName(), serviceURL);
+ final Service service = registry.lookup(serviceURL);
+ if (service != null) {
+ return service;
+ }
+ }
+ return null;
+ }
}
diff --git a/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/service/impl/MetadataServiceRegistry.java b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/service/impl/MetadataServiceRegistry.java
new file mode 100644
index 0000000..f286e00
--- /dev/null
+++ b/idp-cas-impl/src/main/java/net/shibboleth/idp/cas/service/impl/MetadataServiceRegistry.java
@@ -0,0 +1,192 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.idp.cas.service.impl;
+
+import java.util.List;
+import java.util.Objects;
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import com.google.common.collect.Lists;
+import net.shibboleth.idp.cas.config.impl.AbstractProtocolConfiguration;
+import net.shibboleth.idp.cas.service.Service;
+import net.shibboleth.idp.cas.service.ServiceRegistry;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.resolver.CriteriaSet;
+import net.shibboleth.utilities.java.support.resolver.ResolverException;
+import org.opensaml.core.xml.XMLObject;
+import org.opensaml.core.xml.schema.XSAny;
+import org.opensaml.saml.criterion.EndpointCriterion;
+import org.opensaml.saml.criterion.EntityRoleCriterion;
+import org.opensaml.saml.criterion.ProtocolCriterion;
+import org.opensaml.saml.criterion.StartsWithLocationCriterion;
+import org.opensaml.saml.ext.saml2mdattr.EntityAttributes;
+import org.opensaml.saml.metadata.resolver.MetadataResolver;
+import org.opensaml.saml.saml2.core.Attribute;
+import org.opensaml.saml.saml2.metadata.AssertionConsumerService;
+import org.opensaml.saml.saml2.metadata.EntitiesDescriptor;
+import org.opensaml.saml.saml2.metadata.EntityDescriptor;
+import org.opensaml.saml.saml2.metadata.Extensions;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+import org.opensaml.saml.saml2.metadata.SingleLogoutService;
+import org.opensaml.saml.saml2.metadata.impl.AssertionConsumerServiceBuilder;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * CAS service registry implementation that queries SAML metadata for a CAS service given a CAS service URL using
+ * the following strategy. A {@link MetadataResolver} is queried for an {@link EntityDescriptor} that contains at
+ * least one <code>AssertionConsumerService</code> endpoint that meets the following criteria:
+ *
+ * <ol>
+ * <li>Defines <code>https://www.apereo.org/cas/protocol</code> in its <code>protocolSupportEnumeration</code>
+ * attribute.</li>
+ * <li>Defines a <code>Location</code> URL where the given service URL starts with the ACS URL.</li>
+ * </ol>
+ *
+ * If a single match is found, it is converted to a {@link Service} and returned; if more than result is found, a
+ * {@link ResolverException} is raised, otherwise null is returned.
+ *
+ * @author Marvin S. Addison
+ */
+public class MetadataServiceRegistry implements ServiceRegistry {
+
+ /** Metadata attribute used to tag an entity as authorized to request proxy-granting tickets. */
+ private static final String PROXY_ATTRIBUTE = AbstractProtocolConfiguration.PROTOCOL_URI + "/authorizedToProxy";
+
+ /** Class logger. */
+ private final Logger log = LoggerFactory.getLogger(MetadataServiceRegistry.class);
+
+ /** SAML metadata resolver. */
+ @Nonnull
+ private final MetadataResolver metadataResolver;
+
+
+ /**
+ * Create a new instance that queries the given metadata resolver.
+ *
+ * @param resolver SAML metadata resolver.
+ */
+ public MetadataServiceRegistry(@Nonnull final MetadataResolver resolver) {
+ metadataResolver = resolver;
+ }
+
+ @Nullable
+ @Override
+ public Service lookup(@Nonnull String serviceURL) {
+ try {
+ final List<EntityDescriptor> entities = Lists.newArrayList(metadataResolver.resolve(criteria(serviceURL)));
+ if (entities.size() > 1) {
+ throw new ResolverException("Multiple results found");
+ } else if (entities.size() == 1) {
+ return create(serviceURL, entities.get(0));
+ }
+ } catch (ResolverException e) {
+ log.warn("Metadata resolution failed for {}", serviceURL, e);
+ }
+ return null;
+ }
+
+ /**
+ * Create the set of criteria used to find a unique CAS service given a CAS service URL.
+ *
+ * @param serviceURL CAS service URL.
+ *
+ * @return Metadata resolver criteria set.
+ */
+ @Nonnull
+ protected CriteriaSet criteria(@Nonnull final String serviceURL) {
+ final AssertionConsumerService acs = new AssertionConsumerServiceBuilder().buildObject();
+ acs.setLocation(serviceURL);
+ return new CriteriaSet(
+ new EntityRoleCriterion(SPSSODescriptor.DEFAULT_ELEMENT_NAME),
+ new EndpointCriterion<>(acs),
+ new ProtocolCriterion(AbstractProtocolConfiguration.PROTOCOL_URI),
+ new StartsWithLocationCriterion()
+ );
+ }
+
+ /**
+ * Create a CAS {@link Service} from an input service URL and the matching {@link EntityDescriptor} that was
+ * resolved from the metadata source.
+ *
+ * @param serviceURL CAS service URL.
+ * @param entity Entity resolved from metadata.
+ *
+ * @return CAS service created from inputs.
+ */
+ @Nonnull
+ protected Service create(@Nonnull final String serviceURL, @Nonnull final EntityDescriptor entity) {
+ final XMLObject parent = entity.getParent();
+ return new Service(
+ serviceURL,
+ parent instanceof EntitiesDescriptor ? ((EntitiesDescriptor) parent).getName() : "unknown",
+ isAllowedToProxy(entity),
+ hasSingleLogoutService(entity));
+ }
+
+ private boolean hasSingleLogoutService(@Nonnull final EntityDescriptor entity) {
+ final SPSSODescriptor casSP = entity.getSPSSODescriptor(AbstractProtocolConfiguration.PROTOCOL_URI);
+ if (casSP != null) {
+ return casSP.getEndpoints(SingleLogoutService.DEFAULT_ELEMENT_NAME).size() > 0;
+ }
+ return false;
+ }
+
+ private boolean isAllowedToProxy(@Nonnull final EntityDescriptor entity) {
+ final Attribute allowedToProxy = findAttribute(entity, PROXY_ATTRIBUTE);
+ if (allowedToProxy != null) {
+ final XMLObject first = allowedToProxy.getAttributeValues().iterator().next();
+ if (first instanceof XSAny) {
+ return Boolean.parseBoolean(((XSAny) first).getTextContent());
+ } else {
+ throw new RuntimeException("Expected boolean value for " + PROXY_ATTRIBUTE);
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Find a matching entity attribute in the input metadata.
+ *
+ * @param entity the metadata to examine
+ * @param name the attribute name to search for
+ *
+ * @return matching attribute or null
+ */
+ @Nullable
+ private Attribute findAttribute(
+ @Nonnull final EntityDescriptor entity, @Nonnull @NotEmpty final String name) {
+
+ // Check for a tag match in the EntityAttributes extension of the entity and its parent(s).
+ Extensions exts = entity.getExtensions();
+ if (exts != null) {
+ final List<XMLObject> children = exts.getUnknownXMLObjects(EntityAttributes.DEFAULT_ELEMENT_NAME);
+ if (!children.isEmpty() && children.get(0) instanceof EntityAttributes) {
+ final EntityAttributes ea = (EntityAttributes) children.get(0);
+ for (Attribute attribute : ea.getAttributes()) {
+ if (Objects.equals(attribute.getName(), name) &&
+ Objects.equals(attribute.getNameFormat(), Attribute.URI_REFERENCE)) {
+ return attribute;
+ }
+ }
+ }
+ }
+ return null;
+ }
+}
diff --git a/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/service/impl/MetadataServiceRegistryTest.java b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/service/impl/MetadataServiceRegistryTest.java
new file mode 100644
index 0000000..e2d5dad
--- /dev/null
+++ b/idp-cas-impl/src/test/java/net/shibboleth/idp/cas/service/impl/MetadataServiceRegistryTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements. See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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
+ *
+ * http://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 net.shibboleth.idp.cas.service.impl;
+
+import java.util.Collections;
+import java.util.Timer;
+
+import net.shibboleth.ext.spring.resource.ResourceHelper;
+import net.shibboleth.idp.cas.service.Service;
+import net.shibboleth.utilities.java.support.resource.Resource;
+import org.opensaml.core.config.InitializationException;
+import org.opensaml.core.config.InitializationService;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.metadata.resolver.impl.ResourceBackedMetadataResolver;
+import org.opensaml.saml.metadata.resolver.index.MetadataIndex;
+import org.opensaml.saml.metadata.resolver.index.impl.EndpointMetadataIndex;
+import org.springframework.core.io.ClassPathResource;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.BeforeSuite;
+import org.testng.annotations.DataProvider;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.*;
+
+/**
+ * Unit test for {@link MetadataServiceRegistry}.
+ *
+ * @author Marvin S. Addison
+ */
+public class MetadataServiceRegistryTest {
+
+ private ResourceBackedMetadataResolver metadataResolver;
+
+ @DataProvider(name = "parameters")
+ public Object[][] parameters() {
+ final String group = "urn:mace:example.org";
+ return new Object[][] {
+ {"https://alpha.example.org/", new Service("https://alpha.example.org/", group, true, true)},
+ {"https://alpha.example.org/a/b/", new Service("https://alpha.example.org/a/b/", group, true, true)},
+ {"https://alpha.dev.example.org/", new Service("https://alpha.dev.example.org/", group, true, true)},
+ {"https://alpha.dev.example.org/#1", new Service("https://alpha.dev.example.org/#1", group, true, true)},
+ {"https://alpha.dev.example.org", null},
+ {"https://beta.example.org/", new Service("https://beta.example.org/", group, false)},
+ {
+ "https://betatest.example.org:8443/a?b=2",
+ new Service("https://betatest.example.org:8443/a?b=2", group, false),
+ },
+ };
+ }
+
+ /**
+ * Initialize OpenSAML.
+ *
+ * @throws InitializationException
+ */
+ @BeforeSuite
+ public void initOpenSAML() throws InitializationException {
+ InitializationService.initialize();
+ }
+
+ @BeforeClass
+ public void setUp() throws Exception {
+ final Resource metadata = ResourceHelper.of(new ClassPathResource("/metadata/cas-test-metadata.xml"));
+ metadataResolver = new ResourceBackedMetadataResolver(new Timer(true), metadata);
+ metadataResolver.setParserPool(XMLObjectProviderRegistrySupport.getParserPool());
+ metadataResolver.setMaxRefreshDelay(500000);
+ metadataResolver.setId("cas");
+ metadataResolver.setIndexes(Collections.<MetadataIndex>singleton(new EndpointMetadataIndex()));
+ metadataResolver.initialize();
+ }
+
+ @AfterClass
+ public void tearDown() {
+ metadataResolver.destroy();
+ }
+
+ @Test(dataProvider = "parameters")
+ public void testLookup(final String serviceURL, final Service expected) {
+ final MetadataServiceRegistry registry = new MetadataServiceRegistry(metadataResolver);
+ final Service actual = registry.lookup(serviceURL);
+ if (expected == null) {
+ assertNull(actual);
+ } else {
+ assertNotNull(actual);
+ assertEquals(actual.getName(), expected.getName());
+ assertEquals(actual.getGroup(), expected.getGroup());
+ assertEquals(actual.isAuthorizedToProxy(), expected.isAuthorizedToProxy());
+ assertEquals(actual.isSingleLogoutParticipant(), expected.isSingleLogoutParticipant());
+ }
+ }
+}
\ No newline at end of file
diff --git a/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml b/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml
new file mode 100644
index 0000000..7855d7c
--- /dev/null
+++ b/idp-cas-impl/src/test/resources/metadata/cas-test-metadata.xml
@@ -0,0 +1,174 @@
+<EntitiesDescriptor
+ Name="urn:mace:example.org"
+ xmlns="urn:oasis:names:tc:SAML:2.0:metadata"
+ xmlns:ds="http://www.w3.org/2000/09/xmldsig#"
+ xmlns:mdattr="urn:oasis:names:tc:SAML:metadata:attribute"
+ xmlns:mdui="urn:oasis:names:tc:SAML:metadata:ui"
+ xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
+ validUntil="2050-12-31T23:59:59Z">
+
+ <!--
+ | Middleware test SP shib-sp.middleware.vt.edu
+ -->
+ <EntityDescriptor entityID="https://shib-sp.middleware.vt.edu/shibboleth">
+ <SPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol"
+ AuthnRequestsSigned="false"
+ WantAssertionsSigned="false">
+ <Extensions>
+ <mdui:UIInfo>
+ <mdui:DisplayName xml:lang="en">Middleware Test Shibboelth SP</mdui:DisplayName>
+ </mdui:UIInfo>
+ </Extensions>
+ <KeyDescriptor use="signing">
+ <ds:KeyInfo>
+ <ds:KeyName>shib-sp.middleware.vt.edu</ds:KeyName>
+ <ds:X509Data>
+ <ds:X509SubjectName>CN=shib-sp.middleware.vt.edu</ds:X509SubjectName>
+ <ds:X509IssuerSerial>
+ <ds:X509IssuerName>CN=shib-sp.middleware.vt.edu</ds:X509IssuerName>
+ <ds:X509SerialNumber>13911054624363863887</ds:X509SerialNumber>
+ </ds:X509IssuerSerial>
+ <ds:X509Certificate>
+ MIIDEjCCAfqgAwIBAgIJAMEN/noYQ19PMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
+ BAMTGXNoaWItc3AubWlkZGxld2FyZS52dC5lZHUwHhcNMDkxMDEyMTkwOTI5WhcN
+ MTkxMDEwMTkwOTI5WjAkMSIwIAYDVQQDExlzaGliLXNwLm1pZGRsZXdhcmUudnQu
+ ZWR1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1+/HSUxoAKfvUi1
+ D+D0YMVQqaGcWmXndnsR4dBuHaVsl48F6c428bJAwC/u5KEO74PiNFw5tQIY3Msk
+ pR0CGM41Hj9f+jZF5K0Q9QdHOQEyNJjQtLCwyXXSJzvOHVgZhTbyrTyGCxCqs0jb
+ w9oCLLtclZcSxO/OgC/PpYN03juTu7EsoyTqB1zkAz+LXM8nd3/egts7EGzVmmo4
+ n4fAwtfeNjwHxdonRj99UvDernxTe9o671qPcTOSyaAgxC8k3XN1CXFArWDF0aHH
+ ZuYyfLf2ANvI0EHtvBTkwtjSK32hEAK90FU2AVw4KS4JO/+5kO0E7AfQdefCK5WR
+ pbaO8wIDAQABo0cwRTAkBgNVHREEHTAbghlzaGliLXNwLm1pZGRsZXdhcmUudnQu
+ ZWR1MB0GA1UdDgQWBBSkQ5Kf9DS2iZPBzxaM8hgarRUGKjANBgkqhkiG9w0BAQUF
+ AAOCAQEAM6rz9hcTaDj521/q2BIPmx2Kw3nhmcUgi/tjrBsaR2UeGLwH1NokEr0r
+ 9eiJNRLO8JpnVEFRJ3DOJdgYoUD9Ic6HYBAo0ezPCRPHQ+ugh5vqKMypV7syTz8R
+ q1F3BuT9gGRNiYosZl/Zm+Gaf6rTwXIOq45RJOTd9m1maM0TSkl4eR13hOewR0ry
+ BomWaAR/z2m4k1eAggeH1gRufI7NiDx2UfYlrCdU1aTXHkx9i2Wcz4NZu8o3mFOY
+ Q0cjExJWVeywifStwQT+JOALdQWBIVX56d8n+XH8f6ChJKqP+KZXtUuDf5ARdHIN
+ L4EFJSmh5lpx88LwgxTsPXUpvcARfQ==
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ <KeyDescriptor use="encryption">
+ <ds:KeyInfo>
+ <ds:KeyName>shib-sp.middleware.vt.edu</ds:KeyName>
+ <ds:X509Data>
+ <ds:X509SubjectName>CN=shib-sp.middleware.vt.edu</ds:X509SubjectName>
+ <ds:X509IssuerSerial>
+ <ds:X509IssuerName>CN=shib-sp.middleware.vt.edu</ds:X509IssuerName>
+ <ds:X509SerialNumber>13911054624363863887</ds:X509SerialNumber>
+ </ds:X509IssuerSerial>
+ <ds:X509Certificate>
+ MIIDEjCCAfqgAwIBAgIJAMEN/noYQ19PMA0GCSqGSIb3DQEBBQUAMCQxIjAgBgNV
+ BAMTGXNoaWItc3AubWlkZGxld2FyZS52dC5lZHUwHhcNMDkxMDEyMTkwOTI5WhcN
+ MTkxMDEwMTkwOTI5WjAkMSIwIAYDVQQDExlzaGliLXNwLm1pZGRsZXdhcmUudnQu
+ ZWR1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAq1+/HSUxoAKfvUi1
+ D+D0YMVQqaGcWmXndnsR4dBuHaVsl48F6c428bJAwC/u5KEO74PiNFw5tQIY3Msk
+ pR0CGM41Hj9f+jZF5K0Q9QdHOQEyNJjQtLCwyXXSJzvOHVgZhTbyrTyGCxCqs0jb
+ w9oCLLtclZcSxO/OgC/PpYN03juTu7EsoyTqB1zkAz+LXM8nd3/egts7EGzVmmo4
+ n4fAwtfeNjwHxdonRj99UvDernxTe9o671qPcTOSyaAgxC8k3XN1CXFArWDF0aHH
+ ZuYyfLf2ANvI0EHtvBTkwtjSK32hEAK90FU2AVw4KS4JO/+5kO0E7AfQdefCK5WR
+ pbaO8wIDAQABo0cwRTAkBgNVHREEHTAbghlzaGliLXNwLm1pZGRsZXdhcmUudnQu
+ ZWR1MB0GA1UdDgQWBBSkQ5Kf9DS2iZPBzxaM8hgarRUGKjANBgkqhkiG9w0BAQUF
+ AAOCAQEAM6rz9hcTaDj521/q2BIPmx2Kw3nhmcUgi/tjrBsaR2UeGLwH1NokEr0r
+ 9eiJNRLO8JpnVEFRJ3DOJdgYoUD9Ic6HYBAo0ezPCRPHQ+ugh5vqKMypV7syTz8R
+ q1F3BuT9gGRNiYosZl/Zm+Gaf6rTwXIOq45RJOTd9m1maM0TSkl4eR13hOewR0ry
+ BomWaAR/z2m4k1eAggeH1gRufI7NiDx2UfYlrCdU1aTXHkx9i2Wcz4NZu8o3mFOY
+ Q0cjExJWVeywifStwQT+JOALdQWBIVX56d8n+XH8f6ChJKqP+KZXtUuDf5ARdHIN
+ L4EFJSmh5lpx88LwgxTsPXUpvcARfQ==
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </KeyDescriptor>
+ <SingleLogoutService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SLO/SOAP"/>
+ <SingleLogoutService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SLO/Redirect"/>
+ <SingleLogoutService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SLO/POST"/>
+ <SingleLogoutService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SLO/Artifact"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SAML2/POST"
+ index="1"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST-SimpleSign"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SAML2/POST-SimpleSign"
+ index="2"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SAML2/Artifact"
+ index="3"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SAML2/ECP"
+ index="4"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:1.0:profiles:browser-post"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SAML/POST"
+ index="5"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:1.0:profiles:artifact-01"
+ Location="https://shib-sp.middleware.vt.edu:8443/Shibboleth.sso/SAML/Artifact"
+ index="6"/>
+ </SPSSODescriptor>
+ </EntityDescriptor>
+
+ <!--
+ | Alpha (authorizedToProxy="true", singleLogoutParticipant="true")
+ -->
+ <EntityDescriptor entityID="https://alpha.example.org/">
+ <Extensions>
+ <mdattr:EntityAttributes>
+ <saml:Attribute Name="https://www.apereo.org/cas/protocol/authorizedToProxy"
+ NameFormat="urn:oasis:names:tc:SAML:2.0:attrname-format:uri">
+ <saml:AttributeValue>true</saml:AttributeValue>
+ </saml:Attribute>
+ </mdattr:EntityAttributes>
+ </Extensions>
+ <SPSSODescriptor protocolSupportEnumeration="https://www.apereo.org/cas/protocol">
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://alpha.example.org/"
+ index="1"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://alpha.dev.example.org/"
+ index="2"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://alpha.test.example.org/"
+ index="3"/>
+ <SingleLogoutService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP"
+ Location="https://not.used.invalid/"/>
+ </SPSSODescriptor>
+ </EntityDescriptor>
+
+ <!--
+ | Beta (authorizedToProxy="false", singleLogoutParticipant="false")
+ -->
+ <EntityDescriptor entityID="https://beta.example.org/">
+ <SPSSODescriptor protocolSupportEnumeration="https://www.apereo.org/cas/protocol">
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://beta.example.org/"
+ index="1"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://betatest.example.org/"
+ index="2"/>
+ <AssertionConsumerService
+ Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact"
+ Location="https://betatest.example.org:8443/"
+ index="3"/>
+ </SPSSODescriptor>
+ </EntityDescriptor>
+
+</EntitiesDescriptor>
diff --git a/idp-conf/src/main/resources/conf/cas-protocol.xml b/idp-conf/src/main/resources/conf/cas-protocol.xml
index 1c2ce92..bddae19 100644
--- a/idp-conf/src/main/resources/conf/cas-protocol.xml
+++ b/idp-conf/src/main/resources/conf/cas-protocol.xml
@@ -36,6 +36,16 @@
</bean>
<!--
+ | Uncomment this bean if you want to override the default list of CAS service registries.
+ | The default configuration tries to find the relying party in a SAML metadata source and falls back to
+ | reloadableServiceRegistry if a match is not found.
+ -->
+ <!--<util:list id="shibboleth.CASServiceRegistries">
+ <ref bean="shibboleth.CASMetadataServiceRegistry" />
+ <ref bean="shibboleth.CASServiceRegistry" />
+ </util:list>-->
+
+ <!--
| The default ticket service as of 3.3.0 serializes ticket data into the opaque section of the ticket ID
| for service tickets and proxy tickets. Proxy-granting tickets still require server-side storage, and
| a StorageService defined by the idp.cas.StorageService is used. Thus for deployers that do not require
diff --git a/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml b/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml
index 3591d0b..f8ddc30 100644
--- a/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml
+++ b/idp-conf/src/main/resources/system/conf/cas-protocol-system.xml
@@ -3,8 +3,8 @@
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
+ xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
- http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize"
@@ -46,6 +46,11 @@
<bean id="shibboleth.DefaultCASServiceComparator"
class="net.shibboleth.idp.cas.service.impl.DefaultServiceComparator" />
+ <util:list id="shibboleth.DefaultCASServiceRegistries">
+ <ref bean="shibboleth.CASMetadataServiceRegistry" />
+ <ref bean="shibboleth.CASServiceRegistry" />
+ </util:list>
+
<import resource="../../conf/cas-protocol.xml" />
</beans>
\ No newline at end of file
diff --git a/idp-conf/src/main/resources/system/conf/services-system.xml b/idp-conf/src/main/resources/system/conf/services-system.xml
index 198ac1c..224a452 100644
--- a/idp-conf/src/main/resources/system/conf/services-system.xml
+++ b/idp-conf/src/main/resources/system/conf/services-system.xml
@@ -149,4 +149,8 @@
class="net.shibboleth.idp.cas.service.impl.ReloadingServiceRegistry"
c:delegate-ref="shibboleth.ReloadableCASServiceRegistry" />
+ <bean id="shibboleth.CASMetadataServiceRegistry"
+ class="net.shibboleth.idp.cas.service.impl.MetadataServiceRegistry"
+ c:resolver-ref="shibboleth.MetadataResolver" />
+
</beans>
diff --git a/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml b/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml
index b056b20..f7c84e8 100644
--- a/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/cas/cas-abstract-beans.xml
@@ -24,10 +24,10 @@
<bean id="PopulateMetricContext"
class="org.opensaml.profile.action.impl.PopulateMetricContext" scope="prototype"
p:metricStrategy="#{getObject('shibboleth.metrics.MetricStrategy')}" />
-
+
<bean id="BuildRelyingPartyContext"
class="net.shibboleth.idp.cas.flow.impl.BuildRelyingPartyContextAction"
- c:registry-ref="shibboleth.CASServiceRegistry"/>
+ c:registries="#{getObject('shibboleth.CASServiceRegistries') ?: getObject('shibboleth.DefaultCASServiceRegistries')}" />
<bean id="BuildSAMLMetadataContext"
class="net.shibboleth.idp.cas.flow.impl.BuildSAMLMetadataContextAction" />
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list