[java-opensaml] branch main updated: JMETAGEN-5 - Add Velocity-based metadata generator to OpenSAML
Scott Cantor
cantor.2 at osu.edu
Mon Jul 10 19:17:09 UTC 2023
This is an automated email from the git hooks/post-receive script.
scantor pushed a commit to branch main
in repository java-opensaml.
View the commit online:
http://git.shibboleth.net/view/?p=java-opensaml.git;a=commit;h=4ba3f15b243dde6747fda9bc859eb48f6f3fc98e
The following commit(s) were added to refs/heads/main by this push:
new 4ba3f15b2 JMETAGEN-5 - Add Velocity-based metadata generator to OpenSAML
4ba3f15b2 is described below
commit 4ba3f15b243dde6747fda9bc859eb48f6f3fc98e
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jul 10 15:17:05 2023 -0400
JMETAGEN-5 - Add Velocity-based metadata generator to OpenSAML
https://shibboleth.atlassian.net/browse/JMETAGEN-5
Drafty implementation of template-driven generation.
Converters that parse endpoint expressions to deduce bindings/protocols.
---
.../generator/impl/AbstractEndpointConverter.java | 178 +++++++++++++++++++++
.../impl/ArtifactResolutionServiceConverter.java | 53 ++++++
.../impl/AssertionConsumerServiceConverter.java | 53 ++++++
.../generator/impl/AttributeServiceConverter.java | 53 ++++++
.../metadata/generator/impl/MetadataGenerator.java | 47 ++++++
.../impl/MetadataGeneratorParameters.java | 117 ++++++++++++++
.../impl/SingleLogoutServiceConverter.java | 53 ++++++
.../impl/SingleSignOnServiceConverter.java | 53 ++++++
.../impl/TemplateMetadataGeneratorParameters.java | 40 +++++
.../generator/impl/VelocityMetadataGenerator.java | 121 ++++++++++++++
.../saml/metadata/generator/impl/package-info.java | 24 +++
.../metadata/AttributeAuthorityDescriptor.vm | 7 +
.../templates/metadata/EntityDescriptor.vm | 13 ++
.../templates/metadata/IDPSSODescriptor.vm | 13 ++
.../resources/templates/metadata/KeyDescriptors.vm | 30 ++++
.../templates/metadata/SPSSODescriptor.vm | 13 ++
16 files changed, 868 insertions(+)
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AbstractEndpointConverter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AbstractEndpointConverter.java
new file mode 100644
index 000000000..aecdea380
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AbstractEndpointConverter.java
@@ -0,0 +1,178 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.BiFunction;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.saml2.metadata.Endpoint;
+
+import net.shibboleth.shared.annotation.constraint.Live;
+import net.shibboleth.shared.collection.Pair;
+import net.shibboleth.shared.logic.Constraint;
+
+/**
+ * Support for parsing a binding/endpoint pair into an endpoint of a particular type.
+ *
+ * <p>The input format is a binding token, forward slash, and an endpoint. The endpoint MAY omit the
+ * scheme, in which case 'https://' is prepended.</p>
+ *
+ * <p>The SAML 2.0 bindings are represented by the tokens
+ * "Redirect", "POST", "SimpleSign", "Artifact", "SOAP", and "PAOS".</p>
+ *
+ * <p>The SAML 1.1 bindings are represented by the tokens
+ * "Redirect1", "POST1", "Artifact1", and "SOAP1". The first token
+ * is actually the proprietary Shibboleth request protocol.</p>
+ *
+ * <p>The second input parameter is mutated to maintain the list of protocols applicable to the surrounding role.</p>
+ *
+ * @param <T> endpoint type
+ *
+ * @since 5.0.0
+ */
+public abstract class AbstractEndpointConverter<T extends Endpoint> implements BiFunction<String,List<String>,T> {
+
+ /** Map of binding shortcuts to constants. */
+ @Nonnull private static Map<String,Pair<String,String>> bindingMap;
+
+ /** Object builder. */
+ @Nonnull private final SAMLObjectBuilder<T> builder;
+
+ /**
+ * Constructor.
+ *
+ * @param theBuilder builder to use
+ */
+ public AbstractEndpointConverter(@Nonnull final SAMLObjectBuilder<T> theBuilder) {
+ builder = Constraint.isNotNull(theBuilder, "Builder cannot be null");
+ }
+
+ /**
+ * Process an endpoint expression into an absolute URL.
+ *
+ * <p>For now, this merely detects the http schemes and if absent, adds the https scheme.</p>
+ *
+ * @param protocols live list of protocol strings
+ * @param input the argument
+ *
+ * @return the endpoint object
+ */
+ @Nonnull protected T getProcessedEndpoint(@Nullable @Live final List<String> protocols,
+ @Nullable final String input) {
+
+ if (input == null) {
+ throw new IllegalArgumentException("Argument was null");
+ }
+
+ final Pair<String,String> pair = getProtocolAndBinding(input);
+ final String loc = getLocation(input);
+
+ final T endpoint = builder.buildObject();
+
+ if (loc.startsWith("https://") || loc.startsWith("http://")) {
+ endpoint.setLocation(loc);
+ } else {
+ endpoint.setLocation("https://" + loc);
+ }
+
+ endpoint.setBinding(pair.getSecond());
+
+ if (protocols != null) {
+ protocols.add(pair.getFirst());
+ }
+
+ return endpoint;
+ }
+
+ /**
+ * Parse out the binding shortcut and map to a protocol and binding constant.
+ *
+ * @param input the argument
+ *
+ * @return the mapped constant
+ */
+ @Nonnull protected Pair<String,String> getProtocolAndBinding(@Nonnull final String input) {
+ final int sep = input.indexOf('/');
+ if (sep == -1) {
+ throw new IllegalArgumentException("No separator found in string.");
+ }
+
+ final Pair<String,String> binding;
+ synchronized(bindingMap) {
+ binding = bindingMap.get(input.substring(0, sep));
+ }
+ if (binding == null) {
+ throw new IllegalArgumentException("Binding " + input.substring(0, sep) + " did not match a known value.");
+ }
+
+ return binding;
+ }
+
+ /**
+ * Parse out the endpoint location.
+ *
+ * @param input the argument
+ *
+ * @return the endpoint location
+ */
+ @Nonnull protected String getLocation(@Nonnull final String input) {
+ final int sep = input.indexOf('/');
+ if (sep == -1 || input.length() == sep + 1) {
+ throw new IllegalArgumentException("No separator found in string.");
+ }
+
+ return input.substring(sep + 1);
+ }
+
+ /**
+ * Add a new mapping to the static set of protocol/binding mappings.
+ *
+ * @param token token used in strings converted into endpoints
+ * @param protocol protocol support string for binding
+ * @param binding binding constant
+ */
+ public static void addBinding(@Nonnull final String token, @Nonnull final String protocol,
+ @Nonnull final String binding) {
+ synchronized(bindingMap) {
+ bindingMap.put(token, new Pair<>(protocol, binding));
+ }
+ }
+
+ static {
+ bindingMap = new HashMap<>();
+ bindingMap.put("Redirect", new Pair<>(SAMLConstants.SAML20P_NS, SAMLConstants.SAML2_REDIRECT_BINDING_URI));
+ bindingMap.put("POST", new Pair<>(SAMLConstants.SAML20P_NS, SAMLConstants.SAML2_POST_BINDING_URI));
+ bindingMap.put("SimpleSign",
+ new Pair<>(SAMLConstants.SAML20P_NS, SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI));
+ bindingMap.put("Artifact", new Pair<>(SAMLConstants.SAML20P_NS, SAMLConstants.SAML2_ARTIFACT_BINDING_URI));
+ bindingMap.put("SOAP", new Pair<>(SAMLConstants.SAML20P_NS, SAMLConstants.SAML2_SOAP11_BINDING_URI));
+ bindingMap.put("PAOS", new Pair<>(SAMLConstants.SAML20P_NS, SAMLConstants.SAML2_PAOS_BINDING_URI));
+
+ bindingMap.put("POST1", new Pair<>(SAMLConstants.SAML11P_NS, SAMLConstants.SAML1_POST_BINDING_URI));
+ bindingMap.put("Artifact1", new Pair<>(SAMLConstants.SAML11P_NS, SAMLConstants.SAML1_ARTIFACT_BINDING_URI));
+ bindingMap.put("SOAP1", new Pair<>(SAMLConstants.SAML11P_NS, SAMLConstants.SAML1_SOAP11_BINDING_URI));
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/ArtifactResolutionServiceConverter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/ArtifactResolutionServiceConverter.java
new file mode 100644
index 000000000..edc8b5238
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/ArtifactResolutionServiceConverter.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.saml2.metadata.ArtifactResolutionService;
+
+import net.shibboleth.shared.annotation.constraint.Live;
+
+/**
+ * Support for parsing a binding/endpoint pair into a {@link ArtifactResolutionService}.
+ *
+ * @since 5.0.0
+ */
+public class ArtifactResolutionServiceConverter extends AbstractEndpointConverter<ArtifactResolutionService> {
+
+ /**
+ * Constructor.
+ */
+ public ArtifactResolutionServiceConverter() {
+ super((SAMLObjectBuilder<ArtifactResolutionService>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<ArtifactResolutionService>ensureBuilder(
+ ArtifactResolutionService.DEFAULT_ELEMENT_NAME));
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public ArtifactResolutionService apply(@Nullable final String value,
+ @Nullable @Live final List<String> protocols) {
+ return getProcessedEndpoint(protocols, value);
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AssertionConsumerServiceConverter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AssertionConsumerServiceConverter.java
new file mode 100644
index 000000000..7a852a231
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AssertionConsumerServiceConverter.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.saml2.metadata.AssertionConsumerService;
+
+import net.shibboleth.shared.annotation.constraint.Live;
+
+/**
+ * Support for parsing a binding/endpoint pair into a {@link AssertionConsumerService}.
+ *
+ * @since 5.0.0
+ */
+public class AssertionConsumerServiceConverter extends AbstractEndpointConverter<AssertionConsumerService> {
+
+ /**
+ * Constructor.
+ */
+ public AssertionConsumerServiceConverter() {
+ super((SAMLObjectBuilder<AssertionConsumerService>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<AssertionConsumerService>ensureBuilder(
+ AssertionConsumerService.DEFAULT_ELEMENT_NAME));
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public AssertionConsumerService apply(@Nullable final String value,
+ @Nullable @Live final List<String> protocols) {
+ return getProcessedEndpoint(protocols, value);
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AttributeServiceConverter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AttributeServiceConverter.java
new file mode 100644
index 000000000..bb2beba22
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/AttributeServiceConverter.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.saml2.metadata.AttributeService;
+
+import net.shibboleth.shared.annotation.constraint.Live;
+
+/**
+ * Support for parsing a binding/endpoint pair into a {@link AttributeService}.
+ *
+ * @since 5.0.0
+ */
+public class AttributeServiceConverter extends AbstractEndpointConverter<AttributeService> {
+
+ /**
+ * Constructor.
+ */
+ public AttributeServiceConverter() {
+ super((SAMLObjectBuilder<AttributeService>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<AttributeService>ensureBuilder(
+ AttributeService.DEFAULT_ELEMENT_NAME));
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public AttributeService apply(@Nullable final String value,
+ @Nullable @Live final List<String> protocols) {
+ return getProcessedEndpoint(protocols, value);
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/MetadataGenerator.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/MetadataGenerator.java
new file mode 100644
index 000000000..6c50f6355
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/MetadataGenerator.java
@@ -0,0 +1,47 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Interface to a component that generates SAML metadata.
+ *
+ * <p>TODO: this will eventually migrate into the API.</p>
+ *
+ * @since 5.0.0
+ */
+public interface MetadataGenerator {
+
+ /**
+ * Generate metadata using the supplied parameters into the supplied destination.
+ *
+ * <p>The writer must be open and will not be closed by this method.</p>
+ *
+ * @param params input parameters
+ * @param sink destination for output
+ *
+ * @throws IOException on error
+ */
+ public void generate(@Nonnull final MetadataGeneratorParameters params, @Nonnull final Writer sink)
+ throws IOException;
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/MetadataGeneratorParameters.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/MetadataGeneratorParameters.java
new file mode 100644
index 000000000..374f65d30
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/MetadataGeneratorParameters.java
@@ -0,0 +1,117 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.List;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.Namespace;
+import org.opensaml.saml.saml2.metadata.AttributeAuthorityDescriptor;
+import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+
+/**
+ * Inputs to metadata generation.
+ *
+ * <p>TODO: This will eventually migrate into the API.</p>
+ *
+ * @since 5.0.0
+ */
+public interface MetadataGeneratorParameters {
+
+ /**
+ * Get the unique ID.
+ *
+ * @return the unique ID
+ */
+ @Nullable String getEntityID();
+
+ /**
+ * Whether to omit the namespace declarations on the root element.
+ *
+ * @return true iff namespace declarations should be omitted
+ */
+ boolean isOmitNamespaceDeclarations();
+
+ /**
+ * Get a set of additional namespaces to declare on root element.
+ *
+ * @return additional namespaces
+ */
+ @Nullable Set<Namespace> getAdditionalNamespaces();
+
+ /**
+ * Get the SP role to generate.
+ *
+ * <p>Only the endpoints and any basic flags are extracted from the role.</p>
+ *
+ * @return SP role or null
+ */
+ @Nullable SPSSODescriptor getSPSSODescriptor();
+
+ /**
+ * Get the IdP role to generate.
+ *
+ * <p>Only the endpoints and any basic flags are extracted from the role.</p>
+ *
+ * @return IdP role or null
+ */
+ @Nullable IDPSSODescriptor getIDPSSODescriptor();
+
+ /**
+ * Get the AA role to generate.
+ *
+ * <p>Only the endpoints and any basic flags are extracted from the role.</p>
+ *
+ * @return AA role or null
+ */
+ @Nullable AttributeAuthorityDescriptor getAttributeAuthorityDescriptor();
+
+ /**
+ * Dual-use certificates.
+ *
+ * <p>Keys will be applied to all roles.</p>
+ *
+ * @return base64-encoded certificates
+ */
+ @Nonnull @Unmodifiable @NotLive List<String> getCertificates();
+
+ /**
+ * Signing-only certificate path(s).
+ *
+ * <p>Keys will be applied to all roles.</p>
+ *
+ * @return base64-encoded certificates
+ */
+ @Nonnull @Unmodifiable @NotLive List<String> getSigningCertificates();
+
+ /**
+ * Encryption-only certificate path(s).
+ *
+ * <p>Keys will be applied to all roles.</p>
+ *
+ * @return base64-encoded certificates
+ */
+ @Nonnull @Unmodifiable @NotLive List<String> getEncryptionCertificates();
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/SingleLogoutServiceConverter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/SingleLogoutServiceConverter.java
new file mode 100644
index 000000000..14032822e
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/SingleLogoutServiceConverter.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.saml2.metadata.SingleLogoutService;
+
+import net.shibboleth.shared.annotation.constraint.Live;
+
+/**
+ * Support for parsing a binding/endpoint pair into a {@link SingleLogoutService}.
+ *
+ * @since 5.0.0
+ */
+public class SingleLogoutServiceConverter extends AbstractEndpointConverter<SingleLogoutService> {
+
+ /**
+ * Constructor.
+ */
+ public SingleLogoutServiceConverter() {
+ super((SAMLObjectBuilder<SingleLogoutService>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<SingleLogoutService>ensureBuilder(
+ SingleLogoutService.DEFAULT_ELEMENT_NAME));
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public SingleLogoutService apply(@Nullable final String value,
+ @Nullable @Live final List<String> protocols) {
+ return getProcessedEndpoint(protocols, value);
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/SingleSignOnServiceConverter.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/SingleSignOnServiceConverter.java
new file mode 100644
index 000000000..4b8ff8cc0
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/SingleSignOnServiceConverter.java
@@ -0,0 +1,53 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.util.List;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.saml2.metadata.SingleSignOnService;
+
+import net.shibboleth.shared.annotation.constraint.Live;
+
+/**
+ * Support for parsing a binding/endpoint pair into a {@link SingleSignOnService}.
+ *
+ * @since 5.0.0
+ */
+public class SingleSignOnServiceConverter extends AbstractEndpointConverter<SingleSignOnService> {
+
+ /**
+ * Constructor.
+ */
+ public SingleSignOnServiceConverter() {
+ super((SAMLObjectBuilder<SingleSignOnService>)
+ XMLObjectProviderRegistrySupport.getBuilderFactory().<SingleSignOnService>ensureBuilder(
+ SingleSignOnService.DEFAULT_ELEMENT_NAME));
+ }
+
+ /** {@inheritDoc} */
+ @Nonnull public SingleSignOnService apply(@Nullable final String value,
+ @Nullable @Live final List<String> protocols) {
+ return getProcessedEndpoint(protocols, value);
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/TemplateMetadataGeneratorParameters.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/TemplateMetadataGeneratorParameters.java
new file mode 100644
index 000000000..636810e5c
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/TemplateMetadataGeneratorParameters.java
@@ -0,0 +1,40 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import javax.annotation.Nonnull;
+
+/**
+ * Extension interface with additional parameters specific to template-based
+ * implementations of metadata generation.
+ *
+ * <p>TODO: This will eventually migrate into the API.</p>
+ *
+ * @since 5.0.0
+ */
+public interface TemplateMetadataGeneratorParameters extends MetadataGeneratorParameters {
+
+ /**
+ * Get path to templates.
+ *
+ * @return template path
+ */
+ @Nonnull default String getTemplatePath() {
+ return "/templates/metadata";
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/VelocityMetadataGenerator.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/VelocityMetadataGenerator.java
new file mode 100644
index 000000000..60ede274b
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/VelocityMetadataGenerator.java
@@ -0,0 +1,121 @@
+/*
+ * 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 org.opensaml.saml.metadata.generator.impl;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.annotation.Nonnull;
+
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.core.xml.Namespace;
+import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.xmlsec.signature.support.SignatureConstants;
+
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.shared.component.AbstractIdentifiableInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.velocity.Template;
+
+/**
+ * Implementation of SAML metadata generation using Velocity.
+ *
+ * @since 5.0.0
+ */
+public class VelocityMetadataGenerator extends AbstractIdentifiableInitializableComponent implements MetadataGenerator {
+
+ /** Velocity engine. */
+ @NonnullAfterInit private VelocityEngine velocityEngine;
+
+ /**
+ * Set the Velocity engine to use.
+ *
+ * @param engine velocity engine
+ */
+ public void setVelocityEngine(@Nonnull final VelocityEngine engine) {
+ velocityEngine = Constraint.isNotNull(engine, "VelocityEngine cannot be null");
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doInitialize() throws ComponentInitializationException {
+ super.doInitialize();
+
+ if (velocityEngine == null) {
+ throw new ComponentInitializationException("VelocityEngine cannot be null");
+ }
+ }
+
+ /** {@inheritDoc} */
+ public void generate(@Nonnull final MetadataGeneratorParameters params, @Nonnull final Writer sink)
+ throws IOException {
+ try {
+ if (params instanceof TemplateMetadataGeneratorParameters downcast) {
+ Template.fromTemplateName(velocityEngine,
+ downcast.getTemplatePath() + "/EntityDescriptor.vm").merge(
+ getVelocityContext(downcast), sink);
+ } else {
+ throw new IllegalArgumentException("Parameters were not of the expected type");
+ }
+ } catch (final Exception e) {
+ if (e instanceof IOException io) {
+ throw io;
+ }
+ throw new IOException(e);
+ }
+ }
+
+ /**
+ * Builds the Velocity template context.
+ *
+ * @param params the input parameters
+ *
+ * @return the populated context
+ */
+ @Nonnull protected VelocityContext getVelocityContext(@Nonnull final TemplateMetadataGeneratorParameters params) {
+ final VelocityContext context = new VelocityContext();
+
+ context.put("params", params);
+
+ // Namespace handling.
+ if (!params.isOmitNamespaceDeclarations()) {
+ final Map<String,String> prefixMap = new HashMap<>();
+
+ prefixMap.put(SAMLConstants.SAML20MD_PREFIX, SAMLConstants.SAML20MD_NS);
+ prefixMap.put(SAMLConstants.SAML20_PREFIX, SAMLConstants.SAML20_NS);
+ prefixMap.put(SignatureConstants.XMLSIG_PREFIX, SignatureConstants.XMLSIG_NS);
+
+ final Set<Namespace> additionalNamespaces = params.getAdditionalNamespaces();
+ if (additionalNamespaces != null) {
+ for (final Namespace ns : additionalNamespaces) {
+ prefixMap.put(ns.getNamespacePrefix(), ns.getNamespaceURI());
+ }
+ }
+
+ context.put("namespaces", prefixMap);
+ }
+
+ return context;
+ }
+
+}
\ No newline at end of file
diff --git a/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/package-info.java b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/package-info.java
new file mode 100644
index 000000000..b8224509e
--- /dev/null
+++ b/opensaml-saml-impl/src/main/java/org/opensaml/saml/metadata/generator/impl/package-info.java
@@ -0,0 +1,24 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implementation of Velocity-based metadata generation.
+ */
+ at NonnullElements
+package org.opensaml.saml.metadata.generator.impl;
+
+import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/opensaml-saml-impl/src/main/resources/templates/metadata/AttributeAuthorityDescriptor.vm b/opensaml-saml-impl/src/main/resources/templates/metadata/AttributeAuthorityDescriptor.vm
new file mode 100644
index 000000000..d4d8b206e
--- /dev/null
+++ b/opensaml-saml-impl/src/main/resources/templates/metadata/AttributeAuthorityDescriptor.vm
@@ -0,0 +1,7 @@
+#set ($role = $params.AttributeAuthorityDescriptor)
+ <md:AttributeAuthorityDescriptor protocolSupportEnumeration="#foreach($p in $role.supportedProtocols)$p#if(!$foreach.last) #end#end">
+#parse("$params.templatePath/KeyDescriptors.vm")
+#foreach ($endpoint in $role.attributeServices)
+ <md:AttributeService Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+ </md:AttributeAuthorityDescriptor>
diff --git a/opensaml-saml-impl/src/main/resources/templates/metadata/EntityDescriptor.vm b/opensaml-saml-impl/src/main/resources/templates/metadata/EntityDescriptor.vm
new file mode 100644
index 000000000..0991c32ef
--- /dev/null
+++ b/opensaml-saml-impl/src/main/resources/templates/metadata/EntityDescriptor.vm
@@ -0,0 +1,13 @@
+<md:EntityDescriptor#if (!$params.omitNamespaceDeclarations)#foreach ($ns in $namespaces.entrySet()) xmlns:$ns.key="$ns.value"#end#end entityID="$params.entityID">
+
+#if ($params.IDPSSODescriptor)
+#parse("$params.templatePath/IDPSSODescriptor.vm")
+#end
+#if ($params.AttributeAuthorityDescriptor)
+#parse("$params.templatePath/AttributeAuthorityDescriptor.vm")
+#end
+#if ($params.SPSSODescriptor)
+#parse("$params.templatePath/SPSSODescriptor.vm")
+#end
+
+</md:EntityDescriptor>
diff --git a/opensaml-saml-impl/src/main/resources/templates/metadata/IDPSSODescriptor.vm b/opensaml-saml-impl/src/main/resources/templates/metadata/IDPSSODescriptor.vm
new file mode 100644
index 000000000..bb639ea4b
--- /dev/null
+++ b/opensaml-saml-impl/src/main/resources/templates/metadata/IDPSSODescriptor.vm
@@ -0,0 +1,13 @@
+#set ($role = $params.IDPSSODescriptor)
+ <md:IDPSSODescriptor protocolSupportEnumeration="#foreach($p in $role.supportedProtocols)$p#if(!$foreach.last) #end#end">
+#parse("$params.templatePath/KeyDescriptors.vm")
+#foreach ($endpoint in $role.artifactResolutionServices)
+ <md:ArtifactResolutionService index="$endpoint.index" Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+#foreach ($endpoint in $role.singleLogoutServices)
+ <md:SingleLogoutService Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+#foreach ($endpoint in $role.singleSignOnServices)
+ <md:SingleSignOnService Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+ </md:IDPSSODescriptor>
diff --git a/opensaml-saml-impl/src/main/resources/templates/metadata/KeyDescriptors.vm b/opensaml-saml-impl/src/main/resources/templates/metadata/KeyDescriptors.vm
new file mode 100644
index 000000000..38096a4cf
--- /dev/null
+++ b/opensaml-saml-impl/src/main/resources/templates/metadata/KeyDescriptors.vm
@@ -0,0 +1,30 @@
+#foreach ($cert in $params.certificates) <md:KeyDescriptor>
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>
+$cert
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+#end
+#foreach ($cert in $params.signingCertificates) <md:KeyDescriptor use="signing">
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>
+$cert
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+#end
+#foreach ($cert in $params.encryptionCertificates) <md:KeyDescriptor use="encryption">
+ <ds:KeyInfo>
+ <ds:X509Data>
+ <ds:X509Certificate>
+$cert
+ </ds:X509Certificate>
+ </ds:X509Data>
+ </ds:KeyInfo>
+ </md:KeyDescriptor>
+#end
diff --git a/opensaml-saml-impl/src/main/resources/templates/metadata/SPSSODescriptor.vm b/opensaml-saml-impl/src/main/resources/templates/metadata/SPSSODescriptor.vm
new file mode 100644
index 000000000..510a09cbf
--- /dev/null
+++ b/opensaml-saml-impl/src/main/resources/templates/metadata/SPSSODescriptor.vm
@@ -0,0 +1,13 @@
+#set ($role = $params.SPSSODescriptor)
+ <md:SPSSODescriptor protocolSupportEnumeration="#foreach($p in $role.supportedProtocols)$p#if(!$foreach.last) #end#end">
+#parse("$params.templatePath/KeyDescriptors.vm")
+#foreach ($endpoint in $role.artifactResolutionServices)
+ <md:ArtifactResolutionService index="$endpoint.index" Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+#foreach ($endpoint in $role.singleLogoutServices)
+ <md:SingleLogoutService Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+#foreach ($endpoint in $role.assertionConsumerServices)
+ <md:AssertionConsumerService index="$endpoint.index" Binding="$endpoint.binding" Location="$endpoint.location" />
+#end
+ </md:SPSSODescriptor>
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list