[java-idp-plugin-metadatagen] branch dev/JMETAGEN-5 updated: Fix various bugs and wire in certificate and endpoint support.

Scott Cantor cantor.2 at osu.edu
Thu Jul 6 19:38:29 UTC 2023


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch dev/JMETAGEN-5
in repository java-idp-plugin-metadatagen.

View the commit online:
http://git.shibboleth.net/view/?p=java-idp-plugin-metadatagen.git;a=commit;h=31184177d487093db16c371e422067fa23f49254

The following commit(s) were added to refs/heads/dev/JMETAGEN-5 by this push:
     new 3118417  Fix various bugs and wire in certificate and endpoint support.
3118417 is described below

commit 31184177d487093db16c371e422067fa23f49254
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Thu Jul 6 15:38:26 2023 -0400

    Fix various bugs and wire in certificate and endpoint support.
---
 .../plugin/metadatagen/impl/MetadataGenCLI.java    |  19 +-
 .../impl/MetadataGenCommandLineArguments.java      | 209 +++++++++++++++------
 .../AttributeAuthorityDescriptor.vm                |   2 +-
 .../metadatagen-templates/IDPSSODescriptor.vm      |   3 +-
 .../metadatagen-templates/KeyDescriptors.vm        |  30 +++
 .../metadatagen-templates/SPSSODescriptor.vm       |  17 +-
 .../metadatagen-templates/SingleLogoutServices.vm  |  12 ++
 .../plugin/metadatagen/impl/MetadataGenTest.java   |   6 +
 8 files changed, 218 insertions(+), 80 deletions(-)

diff --git a/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCLI.java b/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCLI.java
index b69898a..08ed7e6 100644
--- a/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCLI.java
+++ b/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCLI.java
@@ -469,24 +469,7 @@ public final class MetadataGenCLI extends AbstractIdPHomeAwareCommandLine<Metada
 //        return RC_OK;
 //    }
 
-    
-    
-    /**
-     * Load a certificate from a file in a standard format and produce a base64-encoded DER string.
-     * 
-     * @param file certificate file
-     * 
-     * @return encoded string
-     * 
-     * @throws CertificateException if unable to decode
-     * @throws EncodingException if unable to encode
-     */
-    @Nonnull private String getEncodedCertificate(@Nonnull final File file)
-            throws CertificateException, EncodingException {
-        final X509Certificate cert = X509Support.decodeCertificate(file);
-        return Base64Support.encode(cert.getEncoded(), true);
-    }
-    
+        
     /** {@inheritDoc} */
     @Override
     @Nonnull @Unmodifiable @NotLive protected List<Resource> getAdditionalSpringResources() {
diff --git a/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCommandLineArguments.java b/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCommandLineArguments.java
index fc88306..a1fc765 100644
--- a/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCommandLineArguments.java
+++ b/metadatagen-impl/src/main/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenCommandLineArguments.java
@@ -16,9 +16,13 @@
  */
 package net.shibboleth.idp.plugin.metadatagen.impl;
 
+import java.io.File;
 import java.io.PrintStream;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
 import java.util.ArrayList;
 import java.util.List;
+import java.util.stream.Collectors;
 
 import javax.annotation.Nonnull;
 import javax.annotation.Nullable;
@@ -29,6 +33,7 @@ import org.opensaml.saml.saml2.metadata.AssertionConsumerService;
 import org.opensaml.saml.saml2.metadata.AttributeService;
 import org.opensaml.saml.saml2.metadata.SingleLogoutService;
 import org.opensaml.saml.saml2.metadata.SingleSignOnService;
+import org.opensaml.security.x509.X509Support;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
@@ -36,8 +41,12 @@ import com.beust.jcommander.Parameter;
 
 import net.shibboleth.idp.cas.config.AbstractProtocolConfiguration;
 import net.shibboleth.idp.cli.AbstractIdPHomeAwareCommandLineArguments;
-import net.shibboleth.shared.annotation.constraint.Live;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.EncodingException;
+import net.shibboleth.shared.collection.CollectionSupport;
 import net.shibboleth.shared.primitive.StringSupport;
 
 /**
@@ -73,7 +82,7 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
     @Nullable private Logger log;
 
     /** The unique ID. */
-    @Parameter(names = {"--entityID", "--id"}, required=true, description="Unique ID for entity")
+    @Parameter(names = {"--entityID", "--client_id", "--id"}, required=true, description="Unique ID for entity")
     @Nullable private String entityID;
     
     /** Do we output SAML 2.0? */
@@ -112,12 +121,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
     @Parameter(names = {"--sso-soap"}, description="SingleSignOnService endpoint using SOAP binding")
     @Nullable private String ssoSoap;
 
-    @Parameter(names = {"--artifact-soap", "--artifact"}, description="ArtifactResolutionService endpoint using SOAP binding")
-    @Nullable private String artifactSoap;
-
     @Parameter(names = {"--attr-soap"}, description="AttributeService endpoint using SOAP binding")
     @Nullable private String attributeSoap;
 
+    @Parameter(names = {"--artifact-soap", "--artifact"}, description="ArtifactResolutionService endpoint(s) using SOAP binding")
+    @Nonnull private List<String> artifactSoap = new ArrayList<>();
+
     @Parameter(names = {"--logout-redirect", "-LR"}, description="SingleLogoutService endpoint(s) using HTTP-Redirect binding")
     @Nonnull private List<String> logoutRedirect = new ArrayList<>();
 
@@ -140,7 +149,7 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
     @Nonnull private List<String> acsPaos = new ArrayList<>();
     
     /** Path(s) to dual-use certificate(s). */
-    @Parameter(names = {"--cert", "-c"}, description="Path(s) to certificate(s) for signing and encryption")
+    @Parameter(names = {"--certificate", "--cert", "-c"}, description="Path(s) to certificate(s) for signing and encryption")
     @Nonnull private List<String> certificatePaths = new ArrayList<>();
 
     /** Path(s) to signing certificate(s). */
@@ -227,10 +236,10 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URL
      */
-    @Nullable String getSSORedirectEndpoint() {
-        return ssoRedirect;
+    @Nullable public String getSSORedirectEndpoint() {
+        return getProcessedEndpoint(ssoRedirect);
     }
 
     /**
@@ -238,10 +247,10 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URL
      */
-    @Nullable String getSSOPostEndpoint() {
-        return ssoPost;
+    @Nullable public String getSSOPostEndpoint() {
+        return getProcessedEndpoint(ssoPost);
     }
     
     /**
@@ -249,10 +258,10 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URL
      */
-    @Nullable String getSSOArtifactEndpoint() {
-        return ssoPost;
+    @Nullable public  String getSSOArtifactEndpoint() {
+        return getProcessedEndpoint(ssoArtifact);
     }
 
     /**
@@ -260,32 +269,34 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URL
      */
-    @Nullable String getSSOSoapEndpoint() {
-        return ssoPost;
+    @Nullable public String getSSOSoapEndpoint() {
+        return getProcessedEndpoint(ssoSoap);
     }
 
     /**
-     * Get endpoint expression for {@link ArtifactResolutionService} endpoint using SAML 2.0 SOAP binding.
+     * Get endpoint expression for {@link AttributeService} endpoint using SAML 2.0 SOAP binding.
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URL
      */
-    @Nullable String getArtifactSoapEndpoint() {
-        return artifactSoap;
+    @Nullable public String getAttributeSoapEndpoint() {
+        return getProcessedEndpoint(attributeSoap);
     }
 
     /**
-     * Get endpoint expression for {@link AttributeService} endpoint using SAML 2.0 SOAP binding.
+     * Get endpoint expression for {@link ArtifactResolutionService} endpoint(s) using SAML 2.0 SOAP binding.
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nullable String getAttributeSoapEndpoint() {
-        return attributeSoap;
+    @Nullable @Unmodifiable @NotLive public List<String> getArtifactSoapEndpoints() {
+        return artifactSoap.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -293,10 +304,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getLogoutRedirectEndpoints() {
-        return logoutRedirect;
+    @Nonnull @Unmodifiable @NotLive public List<String> getLogoutRedirectEndpoints() {
+        return logoutRedirect.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -304,10 +317,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getLogoutPostEndpoints() {
-        return logoutPost;
+    @Nonnull @Unmodifiable @NotLive public List<String> getLogoutPostEndpoints() {
+        return logoutPost.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -315,10 +330,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getLogoutArtifactEndpoints() {
-        return logoutArtifact;
+    @Nonnull @Unmodifiable @NotLive public List<String> getLogoutArtifactEndpoints() {
+        return logoutArtifact.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -326,10 +343,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getLogoutSoapEndpoints() {
-        return logoutSoap;
+    @Nonnull @Unmodifiable @NotLive public List<String> getLogoutSoapEndpoints() {
+        return logoutSoap.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -337,10 +356,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getACSPostEndpoints() {
-        return acsPost;
+    @Nonnull @Unmodifiable @NotLive public List<String> getACSPostEndpoints() {
+        return acsPost.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -348,10 +369,12 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getACSArtifactEndpoints() {
-        return acsPost;
+    @Nonnull @Unmodifiable @NotLive public List<String> getACSArtifactEndpoints() {
+        return acsArtifact.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
@@ -359,37 +382,69 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
      * 
      * <p>Endpoints may omit scheme but must specify port and full path.</p>
      * 
-     * @return argument value
+     * @return endpoint URLs
      */
-    @Nonnull @Live List<String> getACSPaosEndpoints() {
-        return acsPaos;
+    @Nonnull @Unmodifiable @NotLive public List<String> getACSPaosEndpoints() {
+        return acsPaos.stream()
+                .map(this::getProcessedEndpoint)
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
     }
 
     /**
-     * Dual-use certificate path(s).
+     * Dual-use certificates.
      * 
-     * @return argument value
+     * @return base64-encoded certificates
+     * 
+     * @throws CertificateException if unable to decode
+     * @throws EncodingException if unable to encode
      */
-    @Nullable @Live public List<String> getCertificatePaths() {
-        return certificatePaths;
+    @Nullable @NotLive public List<String> getCertificates() throws CertificateException, EncodingException {
+        final List<String> encoded = new ArrayList<>();
+        
+        for (final String c : certificatePaths) {
+            assert c != null;
+            encoded.add(getEncodedCertificate(c));
+        }
+        
+        return encoded;
     }
 
     /**
      * Signing-only certificate path(s).
      * 
-     * @return argument value
+     * @return base64-encoded certificates
+     * 
+     * @throws CertificateException if unable to decode
+     * @throws EncodingException if unable to encode
      */
-    @Nullable @Live public List<String> getSigningCertificatePaths() {
-        return signingPaths;
+    @Nullable @NotLive public List<String> getSigningCertificates() throws CertificateException, EncodingException {
+        final List<String> encoded = new ArrayList<>();
+        
+        for (final String c : signingPaths) {
+            assert c != null;
+            encoded.add(getEncodedCertificate(c));
+        }
+        
+        return encoded;
     }
 
     /**
      * Encryption-only certificate path(s).
      * 
-     * @return argument value
+     * @return base64-encoded certificates
+     * 
+     * @throws CertificateException if unable to decode
+     * @throws EncodingException if unable to encode
      */
-    @Nullable @Live public List<String> getEncryptionCertificatePaths() {
-        return encryptionPaths;
+    @Nullable @NotLive public List<String> getEncryptionCertificates() throws CertificateException, EncodingException {
+        final List<String> encoded = new ArrayList<>();
+        
+        for (final String c : encryptionPaths) {
+            assert c != null;
+            encoded.add(getEncodedCertificate(c));
+        }
+        
+        return encoded;
     }
 
     /**
@@ -466,7 +521,7 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
         out.println(String.format("  %-20s %s", "--oidc", "Output OIDC metadata."));
 
         out.println(String.format("  %-20s %s", "--sp", "Output SP role."));
-        out.println(String.format("  %-20s %s", "--idp", "Output IdP role."));
+        out.println(String.format("  %-20s %s", "--idp", "Ou            tput IdP role."));
         out.println(String.format("  %-20s %s", "--aa", "Output Attribute Authority role."));
 
         out.println(String.format("  %-20s %s", "--sso-redirect", "Endpoint for SAML 2.0 SSO HTTP-Redirect endpoint"));
@@ -486,7 +541,7 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
         out.println(String.format("  %-20s %s", "--acs-artifact", "Endpoint for SAML 2.0 ACS HTTP-Artifact endpoint"));
         out.println(String.format("  %-20s %s", "--ecp, --acs-paos", "Endpoint for SAML 2.0 ACS ECP/PAOS endpoint"));
 
-        out.println(String.format("  %-20s %s", "--cert, -c", "Path to dual-use certificate."));
+        out.println(String.format("  %-20s %s", "--certificate,  --cert, -c", "Path to dual-use certificate."));
         out.println(String.format("  %-20s %s", "--signing, -x", "Path to signing certificate."));
         out.println(String.format("  %-20s %s", "--encryption, -e", "Path to encryption certificate."));
         
@@ -495,4 +550,40 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
         out.println();
     }
     
+    /**
+     * Load a certificate from a file in a standard format and produce a base64-encoded DER string.
+     * 
+     * @param path certificate file path
+     * 
+     * @return encoded string
+     * 
+     * @throws CertificateException if unable to decode
+     * @throws EncodingException if unable to encode
+     */
+    @Nonnull private String getEncodedCertificate(@Nonnull final String path)
+            throws CertificateException, EncodingException {
+        final X509Certificate cert = X509Support.decodeCertificate(new File(path));
+        return Base64Support.encode(cert.getEncoded(), true);
+    }
+
+    /**
+     * 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 endpoint input expression
+     * 
+     * @return an absolute URL or null if input was null
+     */
+    @Nullable private String getProcessedEndpoint(@Nullable final String endpoint) {
+        if (endpoint == null) {
+            return null;
+        }
+        
+        if (endpoint.startsWith("https://") || endpoint.startsWith("http://")) {
+            return endpoint;
+        }
+        return "https://" + endpoint;
+    }
+    
 }
\ No newline at end of file
diff --git a/metadatagen-impl/src/main/resources/metadatagen-templates/AttributeAuthorityDescriptor.vm b/metadatagen-impl/src/main/resources/metadatagen-templates/AttributeAuthorityDescriptor.vm
index 338d8d1..2a2d21b 100644
--- a/metadatagen-impl/src/main/resources/metadatagen-templates/AttributeAuthorityDescriptor.vm
+++ b/metadatagen-impl/src/main/resources/metadatagen-templates/AttributeAuthorityDescriptor.vm
@@ -1,3 +1,3 @@
     <md:AttributeAuthorityDescriptor protocolSupportEnumeration="$args.protocolSupportEnumeration">
-
+#parse("/metadatagen-templates/KeyDescriptors.vm")
     </md:AttributeAuthorityDescriptor>
diff --git a/metadatagen-impl/src/main/resources/metadatagen-templates/IDPSSODescriptor.vm b/metadatagen-impl/src/main/resources/metadatagen-templates/IDPSSODescriptor.vm
index 2405eb5..b972947 100644
--- a/metadatagen-impl/src/main/resources/metadatagen-templates/IDPSSODescriptor.vm
+++ b/metadatagen-impl/src/main/resources/metadatagen-templates/IDPSSODescriptor.vm
@@ -1,3 +1,4 @@
     <md:IDPSSODescriptor protocolSupportEnumeration="$args.protocolSupportEnumeration">
-
+#parse("/metadatagen-templates/KeyDescriptors.vm")
+#parse("/metadatagen-templates/SingleLogoutServices.vm")
     </md:IDPSSODescriptor>
diff --git a/metadatagen-impl/src/main/resources/metadatagen-templates/KeyDescriptors.vm b/metadatagen-impl/src/main/resources/metadatagen-templates/KeyDescriptors.vm
new file mode 100644
index 0000000..0907e7d
--- /dev/null
+++ b/metadatagen-impl/src/main/resources/metadatagen-templates/KeyDescriptors.vm
@@ -0,0 +1,30 @@
+#foreach ($cert in $args.certificates)        <md:KeyDescriptor>
+            <ds:KeyInfo>
+                <ds:X509Data>
+                    <ds:X509Certificate>
+$cert
+                    </ds:X509Certificate>
+                </ds:X509Data>
+            </ds:KeyInfo>
+        </md:KeyDescriptor>
+#end
+#foreach ($cert in $args.signingCertificates)        <md:KeyDescriptor use="signing">
+            <ds:KeyInfo>
+                <ds:X509Data>
+                    <ds:X509Certificate>
+$cert
+                    </ds:X509Certificate>
+                </ds:X509Data>
+            </ds:KeyInfo>
+        </md:KeyDescriptor>
+#end
+#foreach ($cert in $args.encryptionCertificates)        <md:KeyDescriptor use="encryption">
+            <ds:KeyInfo>
+                <ds:X509Data>
+                    <ds:X509Certificate>
+$cert
+                    </ds:X509Certificate>
+                </ds:X509Data>
+            </ds:KeyInfo>
+        </md:KeyDescriptor>
+#end
diff --git a/metadatagen-impl/src/main/resources/metadatagen-templates/SPSSODescriptor.vm b/metadatagen-impl/src/main/resources/metadatagen-templates/SPSSODescriptor.vm
index 6971f0c..4e5c076 100644
--- a/metadatagen-impl/src/main/resources/metadatagen-templates/SPSSODescriptor.vm
+++ b/metadatagen-impl/src/main/resources/metadatagen-templates/SPSSODescriptor.vm
@@ -1,3 +1,18 @@
     <md:SPSSODescriptor protocolSupportEnumeration="$args.protocolSupportEnumeration">
-
+#parse("/metadatagen-templates/KeyDescriptors.vm")
+#foreach ($loc in $args.artifactSoapEndpoints)
+        <md:ArtifactResolutionService index="$foreach.count" Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="$loc" />
+#end
+#parse("/metadatagen-templates/SingleLogoutServices.vm")
+#set ($index = 0)
+#foreach ($loc in $args.ACSPostEndpoints)#set ( $index = $index + 1 )
+        <md:AssertionConsumerService index="$index" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="$loc" />
+#end
+#set ($index = $args.ACSPostEndpoints.size())
+#foreach ($loc in $args.ACSArtifactEndpoints)#set ( $index = $index + 1 )
+        <md:AssertionConsumerService index="$index" Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="$loc" />
+#end
+#foreach ($loc in $args.ACSPaosEndpoints)#set ( $index = $index + 1 )
+        <md:AssertionConsumerService index="$index" Binding="urn:oasis:names:tc:SAML:2.0:bindings:PAOS" Location="$loc" />
+#end
     </md:SPSSODescriptor>
diff --git a/metadatagen-impl/src/main/resources/metadatagen-templates/SingleLogoutServices.vm b/metadatagen-impl/src/main/resources/metadatagen-templates/SingleLogoutServices.vm
new file mode 100644
index 0000000..ef854c3
--- /dev/null
+++ b/metadatagen-impl/src/main/resources/metadatagen-templates/SingleLogoutServices.vm
@@ -0,0 +1,12 @@
+#foreach ($loc in $args.logoutRedirectEndpoints)
+        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect" Location="$loc" />
+#end
+#foreach ($loc in $args.logoutPostEndpoints)
+        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" Location="$loc" />
+#end
+#foreach ($loc in $args.logoutArtifactEndpoints)
+        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Artifact" Location="$loc" />
+#end
+#foreach ($loc in $args.logoutSoapEndpoints)
+        <md:SingleLogoutService Binding="urn:oasis:names:tc:SAML:2.0:bindings:SOAP" Location="$loc" />
+#end
diff --git a/metadatagen-impl/src/test/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenTest.java b/metadatagen-impl/src/test/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenTest.java
index c273d0e..63e6542 100644
--- a/metadatagen-impl/src/test/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenTest.java
+++ b/metadatagen-impl/src/test/java/net/shibboleth/idp/plugin/metadatagen/impl/MetadataGenTest.java
@@ -103,6 +103,12 @@ public class MetadataGenTest {
                         "--home", IDP_HOME,
                         "--sp",
                         "--entityID", "https://sp.example.org",
+                        "--cert", "/Users/scantor/Desktop/webauth2.crt",
+                        "--logout-redirect", "sp.example.org/Shibboleth.sso/SLO/Redirect",
+                        "--logout-redirect", "sp2.example.org/Shibboleth.ssoSLO/Redirect",
+                        "-h", "sp.example.org/Shibboleth.sso/SAML2/POST",
+                        "-h", "sp2.example.org/Shibboleth.sso/SAML2/POST",
+                        "--acs-paos", "sp.example.org/Shibboleth.sso/SAML2/ECP",
                         }),
             AbstractCommandLine.RC_OK);
     }

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list