[java-identity-provider] branch main updated: IDP-2142 Use OpenSAML metadata generation code

Rod Widdowson rdw at steadingsoftware.com
Mon Jul 17 13:05:09 UTC 2023


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

rdw pushed a commit to branch main
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=7da2feb7aa7a24990f83234ec1abe29daa716a60

The following commit(s) were added to refs/heads/main by this push:
     new 7da2feb7a IDP-2142 Use OpenSAML metadata generation code
7da2feb7a is described below

commit 7da2feb7aa7a24990f83234ec1abe29daa716a60
Author: Rod Widdowson <rdw at steadingsoftware.com>
AuthorDate: Fri Jul 14 14:14:34 2023 +0100

    IDP-2142 Use OpenSAML metadata generation code
    
    https://shibboleth.atlassian.net/browse/IDP-2142
    
    First cut.  Just exports SAML2 SOAP Artifacts and
    Redirect, SimpleSign and Post SSO
---
 idp-installer/pom.xml                              |   5 +
 .../impl/InstalledMetadataParameters.java          | 340 ++++++++
 .../shibboleth/idp/installer/impl/V5Install.java   |  66 +-
 .../installer/metadata/impl/MetadataGenerator.java | 917 ---------------------
 .../metadata/impl/MetadataGeneratorParameters.java | 266 ------
 .../idp/installer/metadata/impl/package-info.java  |  24 -
 .../idp/installer/metadata-generator-ant.xml       |  19 -
 .../idp/installer/metadata-generator.xml           |  33 +-
 8 files changed, 410 insertions(+), 1260 deletions(-)

diff --git a/idp-installer/pom.xml b/idp-installer/pom.xml
index c5f63eb21..e587c6afa 100644
--- a/idp-installer/pom.xml
+++ b/idp-installer/pom.xml
@@ -74,6 +74,11 @@
             <artifactId>opensaml-saml-api</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-saml-impl</artifactId>
+            <scope>provided</scope>
+        </dependency>
         <dependency>
             <groupId>${opensaml.groupId}</groupId>
             <artifactId>opensaml-security-api</artifactId>
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstalledMetadataParameters.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstalledMetadataParameters.java
new file mode 100644
index 000000000..cc20e7988
--- /dev/null
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/InstalledMetadataParameters.java
@@ -0,0 +1,340 @@
+/*
+ * 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.installer.impl;
+
+import java.io.File;
+import java.io.IOException;
+import java.security.cert.CertificateException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.function.BiFunction;
+import java.util.stream.Collectors;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.core.xml.Namespace;
+import org.opensaml.core.xml.XMLObjectBuilderFactory;
+import org.opensaml.core.xml.config.XMLObjectProviderRegistrySupport;
+import org.opensaml.saml.common.SAMLObjectBuilder;
+import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.ext.saml2mdui.Logo;
+import org.opensaml.saml.ext.saml2mdui.impl.LogoBuilder;
+import org.opensaml.saml.metadata.generator.impl.ArtifactResolutionServiceConverter;
+import org.opensaml.saml.metadata.generator.impl.SingleLogoutServiceConverter;
+import org.opensaml.saml.metadata.generator.impl.SingleSignOnServiceConverter;
+import org.opensaml.saml.metadata.generator.impl.TemplateMetadataGeneratorParameters;
+import org.opensaml.saml.saml2.metadata.Endpoint;
+import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
+import org.opensaml.saml.saml2.metadata.IndexedEndpoint;
+import org.opensaml.security.x509.X509Support;
+import org.slf4j.Logger;
+
+import net.shibboleth.idp.saml.xmlobject.ExtensionsConstants;
+import net.shibboleth.shared.annotation.constraint.Live;
+import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
+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.collection.Pair;
+import net.shibboleth.shared.component.AbstractInitializableComponent;
+import net.shibboleth.shared.component.ComponentInitializationException;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.resource.Resource;
+
+/**
+ * Parameters to metadata generation
+ */
+public class InstalledMetadataParameters extends AbstractInitializableComponent implements TemplateMetadataGeneratorParameters {
+
+    /** Logger. */
+    private final Logger log = LoggerFactory.getLogger(InstalledMetadataParameters.class);
+
+    /**
+     * The file with the certificate the IDP uses to encrypt.
+     */
+    @Nullable private File encryptionCert;
+
+    /**
+     * The file with the certificate that TLS uses to 'sign'.
+     */
+    @Nullable private File backChannelCert;
+
+    /**
+     * The file with the certificate the IDP uses to sign.
+     */
+    @Nullable private File signingCert;
+
+    /** The entityID. */
+    @NonnullAfterInit private String entityID;
+
+    /** The DNS name. */
+    @NonnullAfterInit private String dnsName;
+
+    /** The scope. */
+    @Nullable private String scope;
+
+    /*
+     * Static settings.
+     */
+    /** logout services. */
+    final @Nonnull List<Pair<String, String>> logoutServices = CollectionSupport.singletonList(
+            new Pair<>("SOAP/","/idp/profile/SAML2/SOAP/ArtifactResolution"));
+
+    /** sso services. */
+    final @Nonnull List<Pair<String, String>> ssoServices = CollectionSupport.listOf(
+            new Pair<>("SimpleSign/","/idp/profile/SAML2/POST-SimpleSign/SSO"),
+            new Pair<>("Redirect/","/idp/profile/SAML2/Redirect/SSO"),
+            new Pair<>("POST/","idp/profile/SAML2/POST/SSO"));
+
+    /** artifact services. */
+    final @Nonnull List<Pair<String, String>> artifactServices = CollectionSupport.emptyList();
+
+    /** {@inheritDoc} */
+    protected void doInitialize() throws ComponentInitializationException {
+        if (entityID == null || entityID.isEmpty()) {
+            throw new ComponentInitializationException("Entity ID not specified");
+        }
+        if (dnsName == null || dnsName.isEmpty()) {
+            throw new ComponentInitializationException("DNS name not specified");
+        }
+    }
+
+    /**
+     * Set the encryption Certificate file.
+     *
+     * @param resource what to set.
+     */
+    public void setEncryptionCertResource(@Nonnull final Resource resource) {
+
+        try {
+            encryptionCert = resource.getFile();
+        } catch (final IOException e) {
+            log.error("Could not open encryption  cert", e);
+            encryptionCert = null;
+        }
+    }
+
+    /**
+     * Set the signing Certificate file.
+     *
+     * @param resource what to set.
+     */
+    public void setSigningCertResource(@Nonnull final Resource resource) {
+        try {
+            signingCert = resource.getFile();
+        } catch (final IOException e) {
+            log.error("Could not open signing cert", e);
+            signingCert = null;
+        }
+    }
+
+    /**
+     * Set the Backchannel Certificate.
+     *
+     * @param resource what to set.
+     */
+    public void setBackchannelCertResource(@Nonnull final Resource resource) {
+        try {
+            backChannelCert = resource.getFile();
+        } catch (final IOException e) {
+            log.error("Could not open back channel cert", e);
+            backChannelCert = null;
+        }
+    }
+
+    /**
+     * Load a certificate from a file in a standard format and produce a base64-encoded DER string.
+     *
+     * @param file certificate file
+     *
+     * @return encoded string
+     */
+    @Nullable private String getEncodedCertificate(@Nullable final File file) {
+        if (file == null) {
+            return null;
+        }
+        try {
+            final byte[] cert = X509Support.decodeCertificate(file).getEncoded();
+            assert cert != null;
+            return Base64Support.encode(cert, true);
+        } catch (final CertificateException | EncodingException e) {
+            log.warn("Unable to decode and re-encode certificate at path {}", file, e);
+            return null;
+        }
+    }
+
+    /**
+     * Sets the entityID.
+     *
+     * @param id what to set.
+     */
+    public void setEntityID(@Nonnull final String id) {
+        entityID = id;
+    }
+
+    /**
+     * Sets the dns name.
+     *
+     * @param name what to set.
+     */
+    public void setDnsName(@Nonnull final String name) {
+        dnsName = name;
+    }
+
+    /**
+     * Sets the scope.
+     *
+     * @param value what to set.
+     */
+    public void setScope(@Nullable final String value) {
+        scope = value;
+    }
+
+    // Methods for the interface
+
+    /** {@inheritDoc}     */
+    @Nullable
+    public String getEntityID() {
+        return entityID;
+    }
+
+    /** {@inheritDoc} */
+    @Nullable public Set<Namespace> getAdditionalNamespaces() {
+        final Set<Namespace> namespaces = new HashSet<>();
+        namespaces.add(new Namespace(SAMLConstants.SAML20MDUI_NS, SAMLConstants.SAML20MDUI_PREFIX));
+        if (scope != null) {
+            namespaces.add(new Namespace(ExtensionsConstants.SHIB_MDEXT10_NS, ExtensionsConstants.SHIB_MDEXT10_PREFIX));
+        }
+        return namespaces;
+    }
+
+    /**
+     * Convert the expressions into endpoints.
+     *
+     * @param <T> endpoint type
+     * @param converter endpoint converter
+     * @param protocols accumulator for protocol support values
+     * @param input raw argument list
+     *
+     * @return converted endpoints
+     */
+    @Nonnull private <T extends Endpoint> Collection<T> convertEndpoints(
+            @Nonnull final BiFunction<String,List<String>,T> converter,
+            @Nonnull @Live final List<String> protocols,
+            @Nonnull final Collection<Pair<String,String>> input) {
+        return input
+                .stream()
+                .map(p -> converter.apply(new StringBuffer(p.getFirst()).append(dnsName).append(p.getSecond()).toString(),
+                                          protocols))
+                .collect(CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
+    }
+
+    /** {@inheritDoc}     */
+    @Nullable
+    public IDPSSODescriptor getIDPSSODescriptor() {
+        final XMLObjectBuilderFactory bf = XMLObjectProviderRegistrySupport.getBuilderFactory();
+        final SAMLObjectBuilder<IDPSSODescriptor> idpSSOBuilder =
+                (SAMLObjectBuilder<IDPSSODescriptor>) bf.<IDPSSODescriptor>ensureBuilder(
+                        IDPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        final IDPSSODescriptor role = idpSSOBuilder.buildObject();
+
+        final List<String> protocols = new ArrayList<>();
+
+        role.getSingleLogoutServices().addAll(
+                convertEndpoints(new SingleLogoutServiceConverter(), protocols, logoutServices));
+        role.getSingleSignOnServices().addAll(
+                convertEndpoints(new SingleSignOnServiceConverter(), protocols, ssoServices));
+        role.getArtifactResolutionServices().addAll(
+                convertEndpoints(new ArtifactResolutionServiceConverter(), protocols, artifactServices));
+
+        int index = 1;
+        for (final IndexedEndpoint e : role.getArtifactResolutionServices()) {
+            e.setIndex(index++);
+        }
+          protocols.forEach(role::addSupportedProtocol);
+        return role;
+    }
+
+    /** {@inheritDoc}     */
+    @Nonnull @Unmodifiable @NotLive
+    public List<String> getSigningCertificates() {
+        final List<String> result = new ArrayList<>(2);
+        String cert = getEncodedCertificate(backChannelCert);
+        if (cert != null) {
+            result.add(cert);
+        }
+        cert = getEncodedCertificate(signingCert);
+        if (cert != null) {
+            result.add(cert);
+        }
+        return result;
+    }
+
+    /** {@inheritDoc}     */
+    @Nonnull @Unmodifiable @NotLive
+    public List<String> getEncryptionCertificates() {
+        final String cert = getEncodedCertificate(encryptionCert);
+        if (cert == null) {
+            return CollectionSupport.emptyList();
+        }
+        return CollectionSupport.singletonList(cert);
+    }
+
+    /** {@inheritDoc}     */
+    @Nullable
+    public String getLang() {
+        return "en";
+    }
+
+    /** {@inheritDoc}     */
+    @Nullable
+    public String getDisplayName() {
+        return new StringBuffer("A name for the IdP at ").append(dnsName).toString();
+    }
+
+    /** {@inheritDoc}     */
+    @Nullable
+    public String getDescription() {
+        return new StringBuffer("Enter a description for the IdP at ").append(dnsName).toString();
+    }
+
+    /** {@inheritDoc}     */
+    @Nullable
+    public Logo getLogo() {
+        final Logo result = new LogoBuilder().buildObject();
+        result.setHeight(80);
+        result.setWidth(80);
+        result.setURI(new StringBuffer("https://").append(dnsName).append("/path/to/logo.png").toString());
+        return result;
+    }
+
+    /** {@inheritDoc} */
+    @Nonnull @Unmodifiable @NotLive public List<String> getScopes() {
+        final String s = scope;
+        if (s == null) {
+            return CollectionSupport.emptyList();
+        }
+        return CollectionSupport.singletonList(s);
+    }
+}
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/V5Install.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/V5Install.java
index b787b6440..cdec6b6cf 100644
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/V5Install.java
+++ b/idp-installer/src/main/java/net/shibboleth/idp/installer/impl/V5Install.java
@@ -26,6 +26,7 @@ import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.Writer;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.time.Instant;
@@ -41,6 +42,10 @@ import javax.annotation.Nullable;
 
 import org.apache.hc.client5.http.classic.HttpClient;
 import org.apache.tools.ant.BuildException;
+import org.apache.velocity.app.VelocityEngine;
+import org.opensaml.core.config.InitializationException;
+import org.opensaml.core.config.InitializationService;
+import org.opensaml.saml.metadata.generator.impl.VelocityMetadataGenerator;
 import org.opensaml.security.httpclient.HttpClientSecurityParameters;
 import org.slf4j.Logger;
 import org.springframework.context.ApplicationContextInitializer;
@@ -52,8 +57,6 @@ import org.springframework.core.io.Resource;
 import net.shibboleth.idp.Version;
 import net.shibboleth.idp.installer.InstallerSupport;
 import net.shibboleth.idp.installer.PropertiesWithComments;
-import net.shibboleth.idp.installer.metadata.impl.MetadataGenerator;
-import net.shibboleth.idp.installer.metadata.impl.MetadataGeneratorParameters;
 import net.shibboleth.idp.installer.plugin.impl.PluginState;
 import net.shibboleth.idp.module.IdPModule;
 import net.shibboleth.idp.plugin.IdPPlugin;
@@ -87,9 +90,6 @@ public class V5Install {
     /** Key Manager. */
     @Nonnull private final KeyManagement keyManager;
 
-    /** What will generate metadata? */
-    @Nonnull private final MetadataGenerator metadataGenerator = new MetadataGenerator();
-
     /** The HttpClient to use.*/
     @Nonnull private final HttpClient httpClient;
 
@@ -101,7 +101,7 @@ public class V5Install {
      * @param installState The current install.
      * @param client {@link HttpClient} to use on any Plugin operations
      * @param securityParams {@link HttpClientSecurityParameters} to use on any Plugin operations
-     * 
+     *
      */
     public V5Install(@Nonnull final InstallerProperties props, @Nonnull final CurrentInstallState installState,
             @Nonnull final HttpClient client, @Nullable final HttpClientSecurityParameters securityParams) {
@@ -130,8 +130,8 @@ public class V5Install {
         generateMetadata();
         reprotect();
     }
-    
-    /** Check for any preconditions to the install. 
+
+    /** Check for any preconditions to the install.
      * @throws BuildException if one is broken.
      */
     protected void checkPreConditions() throws BuildException {
@@ -156,7 +156,7 @@ public class V5Install {
         }
     }
 
-    /** Report the to be installed and (if there is one) current versions. 
+    /** Report the to be installed and (if there is one) current versions.
      * Write to be installed version to the dist folder.
      * @throws BuildException if the write fails
      */
@@ -285,7 +285,7 @@ public class V5Install {
             final Path secrets = installerProps.getTargetDir().resolve("credentials").resolve("secrets.properties");
             try (final FileWriter fileWriter = new FileWriter(secrets.toFile());
                  final BufferedWriter out = new BufferedWriter(fileWriter)) {
-                
+
                 out.write("# This is a reserved spot for most properties containing passwords or other secrets.");
                 out.newLine();
                 out.write("# Created by install at " + Instant.now());
@@ -398,7 +398,7 @@ public class V5Install {
         }
     }
 
-    
+
     /** ReEnable modules which were already enabled.
      * @throws BuildException if badness occurs
      */
@@ -466,26 +466,42 @@ public class V5Install {
             log.debug("Metadata file {} exists", metadataFile.toString());
             return;
         }
+        try {
+            InitializationService.initialize();
+        } catch (InitializationException e) {
+            log.error("Could not intiailize opensaml", e);
+            throw new BuildException(e);
+        }
+
         final Resource resource = new ClassPathResource("net/shibboleth/idp/installer/metadata-generator.xml");
         final GenericApplicationContext context = new ApplicationContextBuilder()
-                .setName(MetadataGenerator.class.getName())
+                .setName(V5Install.class.getName())
                 .setServiceConfigurations(CollectionSupport.singletonList(resource))
                 .setContextInitializer(new Initializer())
                 .build();
 
-        final MetadataGeneratorParameters parameters = context.getBean("IdPConfiguration",
-                MetadataGeneratorParameters.class);
-
         log.info("Creating Metadata to {}", metadataFile);
+        final InstalledMetadataParameters parameters = context.getBean("IdPConfiguration", InstalledMetadataParameters.class);
+        parameters.setDnsName(installerProps.getHostName());
+        final VelocityEngine engine = context.getBean("VelocityEngine", VelocityEngine.class);
         log.debug("Parameters {}", parameters);
-        metadataGenerator.setOutput(metadataFile);
-        metadataGenerator.setParameters(parameters);
-        try {
-            metadataGenerator.initialize();
-        } catch (final ComponentInitializationException e) {
+        try (final Writer sink = new FileWriter(metadataFile)) {
+            sink.write("<!--\n This is example metadata only. Do *NOT* supply it as is without review,\n" +
+                    "and do *NOT* provide it in real time to your partners.\n" +
+                    "This metadata is not dynamic - it will not change as your configuration changes.\n" +
+                    "On Demand Metadata Generation available from the metadatagen plugin.\n-->\n");
+            final VelocityMetadataGenerator generator = new VelocityMetadataGenerator();
+            generator.setId("Installer Metadata Generator");
+            generator.setVelocityEngine(engine);
+            generator.initialize();
+            generator.generate(parameters, sink);
+        } catch (ComponentInitializationException e) {
+            log.error("Metadata Generator initialization failed", e);
+            throw new BuildException(e);
+        } catch (IOException e) {
+            log.error("Metadata Generator failed to write to", metadataFile, e);
             throw new BuildException(e);
         }
-        metadataGenerator.generate();
     }
 
     /** Set the protection on the files.
@@ -532,7 +548,7 @@ public class V5Install {
 
         /** Did we create idp-backchannel.*?*/
         private boolean createdBackchannel;
-        
+
         /** Did we create sealer.*?*/
         private boolean createdSealer;
 
@@ -552,7 +568,7 @@ public class V5Install {
 
         /**
          * Helper method for {@link #execute()} to generate a crt and key file.
-         * 
+         *
          * @param fileBase the partial file name
          * @return true iff the file pair was created
          * @throws BuildException if badness occurrs.
@@ -597,7 +613,7 @@ public class V5Install {
 
         /**
          * Helper method for {@link #execute()} to generate the backchannel keystore.
-         * 
+         *
          * @throws BuildException if badness occurs.
          */
         private void generateKeyStore() {
@@ -639,7 +655,7 @@ public class V5Install {
 
         /**
          * Helper method for {@link #execute()} to generate the Sealer.
-         * 
+         *
          * @throws BuildException if badness occurs.
          */
         private void generateSealer() {
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/MetadataGenerator.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/MetadataGenerator.java
deleted file mode 100644
index cbc6a1e04..000000000
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/MetadataGenerator.java
+++ /dev/null
@@ -1,917 +0,0 @@
-/*
- * 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.installer.metadata.impl;
-
-import java.io.BufferedWriter;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.time.Instant;
-import java.util.ArrayList;
-import java.util.EnumSet;
-import java.util.List;
-import java.util.Set;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import org.apache.tools.ant.BuildException;
-import org.opensaml.core.xml.LangBearing;
-import org.opensaml.saml.common.xml.SAMLConstants;
-import org.opensaml.saml.ext.reqattr.RequestedAttributes;
-import org.opensaml.saml.ext.saml2mdui.Description;
-import org.opensaml.saml.ext.saml2mdui.DisplayName;
-import org.opensaml.saml.ext.saml2mdui.Logo;
-import org.opensaml.saml.ext.saml2mdui.UIInfo;
-import org.opensaml.saml.saml2.core.Extensions;
-import org.opensaml.saml.saml2.metadata.ArtifactResolutionService;
-import org.opensaml.saml.saml2.metadata.AttributeAuthorityDescriptor;
-import org.opensaml.saml.saml2.metadata.AttributeService;
-import org.opensaml.saml.saml2.metadata.EntityDescriptor;
-import org.opensaml.saml.saml2.metadata.IDPSSODescriptor;
-import org.opensaml.saml.saml2.metadata.KeyDescriptor;
-import org.opensaml.saml.saml2.metadata.SingleLogoutService;
-import org.opensaml.saml.saml2.metadata.SingleSignOnService;
-import org.opensaml.xmlsec.signature.KeyInfo;
-import org.opensaml.xmlsec.signature.X509Certificate;
-import org.opensaml.xmlsec.signature.X509Data;
-import org.opensaml.xmlsec.signature.support.SignatureConstants;
-
-import net.shibboleth.idp.saml.xmlobject.ExtensionsConstants;
-import net.shibboleth.idp.saml.xmlobject.Scope;
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-import net.shibboleth.shared.annotation.constraint.NotEmpty;
-import net.shibboleth.shared.collection.CollectionSupport;
-import net.shibboleth.shared.component.AbstractInitializableComponent;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.logic.Constraint;
-import net.shibboleth.shared.xml.DOMTypeSupport;
-import net.shibboleth.shared.xml.XMLConstants;
-
-/**
- * This class gathers information which it then uses to generate IdP Metadata. Loosely based on the SP metadata
- * generator, and the V2 metadata.
- */
-public class MetadataGenerator extends AbstractInitializableComponent {
-
-    /**
-     * The end points we understand.
-     */
-    enum Endpoints {
-        /** IDPSSODescriptor. Artifact (SAML1). */
-        SAML1Artifact,
-        /** IDPSSODescriptor. Artifact (SAML2). */
-        SAML2Artifact,
-        /** IDPSSODescriptor. SLO (Redirect) */
-        RedirectSLO,
-        /** IDPSSODescriptor. SLO (Post) */
-        POSTSLO,
-        /** IDPSSODescriptor. SLO (Post Simple Sign) */
-        POSTSimpleSignSLO,
-        /** IDPSSODescriptor. SLO (Soap) */
-        SOAPSLO,
-        /** IDPSSODescriptor. SSO (Shibboleth protocol)*/
-        ShibbolethSSO,
-        /** IDPSSODescriptor. SSO (SAML2 Post)*/
-        POSTSSO,
-        /** IDPSSODescriptor. SSO (SAML2 Post Simple Sign)*/
-        POSTSimpleSignSSO,
-        /** IDPSSODescriptor. SSO (SAML2 Redirectr)*/
-        RedirectSSO,
-        /** AttributeAuthorityDescriptor. (SAML1=)*/
-        SAML1Query,
-        /** AttributeAuthorityDescriptor. (SAML2) */
-        SAML2Query,
-    }
-
-    /**
-     * Those endpoints which require a backchannel.
-     */
-    @Nonnull private static final Set<Endpoints> BACKCHANNEL_ENDPOINTS = CollectionSupport.setOf(
-            Endpoints.SAML1Artifact, Endpoints.SAML2Artifact, Endpoints.SOAPSLO, Endpoints.SAML1Query,
-            Endpoints.SAML2Query);
-
-    /**
-     * the Artifact endpoints.
-     */
-    @Nonnull private static final Set<Endpoints> ARTIFACT_ENDPOINTS = CollectionSupport.setOf(Endpoints.SAML1Artifact,
-            Endpoints.SAML2Artifact);
-
-    /**
-     * the SSO endpoints.
-     */
-    @Nonnull private static final Set<Endpoints> SSO_ENDPOINTS = CollectionSupport.setOf(Endpoints.ShibbolethSSO,
-            Endpoints.POSTSSO, Endpoints.POSTSimpleSignSSO, Endpoints.RedirectSSO);
-
-    /**
-     * the SLO endpoints.
-     */
-    @Nonnull private static final Set<Endpoints> SLO_ENDPOINTS = CollectionSupport.setOf(Endpoints.RedirectSLO,
-            Endpoints.POSTSLO, Endpoints.POSTSimpleSignSLO, Endpoints.SOAPSLO);
-
-    /**
-     * AttributeAuthority endpoints.
-     */
-    @Nonnull private static final Set<Endpoints> AA_ENDPOINTS = CollectionSupport.setOf(Endpoints.SAML1Query,
-            Endpoints.SAML2Query);
-
-    /**
-     * Which endpoints to generate.
-     */
-    @NonnullAfterInit private EnumSet<Endpoints> endpoints;
-
-    /**
-     * Whether to comment out the SAML2 AA endpoint.
-     */
-    private boolean saml2AttributeQueryCommented = true;
-
-    /**
-     * Whether to comment out the SAML2 SLO endpoints.
-     */
-    private boolean saml2LogoutCommented = true;
-
-    /** Whether SAML1 is commented out. */
-    private boolean saml1Commented = true;
-
-    /** Comment depth. */
-    private int commentDepth;
-
-    /**
-     * Where to write to - as {@link BufferedWriter}.
-     */
-    @NonnullAfterInit private BufferedWriter writer;
-
-    /**
-     * Where to write to - as {@link File}.
-     */
-    @Nullable private File output;
-
-    /** The parameters. */
-    private MetadataGeneratorParameters params;
-
-    /** {@inheritDoc} */
-    protected void doInitialize() throws ComponentInitializationException {
-        try {
-            final FileOutputStream outStream;
-            outStream = new FileOutputStream(output);
-            writer = new BufferedWriter(new OutputStreamWriter(outStream));
-        } catch (final FileNotFoundException e) {
-            throw new ComponentInitializationException(e);
-        }
-        endpoints = EnumSet.allOf(Endpoints.class);
-    }
-
-    /** Set where to write the metadata.
-     * @param file what to set.
-     */
-    public void setOutput(@Nonnull final File file) {
-        checkSetterPreconditions();
-        output = Constraint.isNotNull(file, "provided file must be nonnull");
-    }
-
-    /** Set a description of the IdP.
-     * @param what what to set.  This component does not have to be initialized.
-     */
-    public void setParameters(@Nonnull final MetadataGeneratorParameters what) {
-        checkSetterPreconditions();
-        params = Constraint.isNotNull(what, "provided params must be nonnull");
-    }
-
-    /**
-     * remove back channel endpoints.
-     */
-    public void removeBackChannel() {
-        endpoints.removeAll(BACKCHANNEL_ENDPOINTS);
-    }
-
-    /**
-     * Get the Endpoints.
-     *
-     * @return Returns the Endpoints
-     */
-    public EnumSet<Endpoints> getEndpoints() {
-        return endpoints;
-    }
-
-    /**
-     * Set the Endpoints.
-     *
-     * @param points what to set.
-     */
-    public void setEndpoints(@Nonnull final EnumSet<Endpoints> points) {
-        endpoints = Constraint.isNotNull(points, "supplied endpoints should not be null");
-    }
-
-    /**
-     * Returns whether to comment the SAML2 AA endpoint.
-     *
-     * @return whether to comment the SAML2 AA endpoint
-     */
-    public boolean isSAML2AttributeQueryCommented() {
-        return saml2AttributeQueryCommented;
-    }
-
-    /**
-     * Sets whether to comment the SAML2 AA endpoint.
-     *
-     * @param asComment whether to comment or not.
-     */
-    public void setSAML2AttributeQueryCommented(final boolean asComment) {
-        saml2AttributeQueryCommented = asComment;
-    }
-
-    /**
-     * Returns whether to comment SAML1 endpoints.
-     *
-     * @return whether to comment SAML1 endpoints
-     */
-    public boolean isSAML1Commented() {
-        return saml1Commented;
-    }
-
-    /**
-     * Sets whether to comment the comment SAML1 endpoints.
-     *
-     * @param asComment whether to comment or not.
-     */
-    public void setSAML1Commented(final boolean asComment) {
-        saml1Commented= asComment;
-    }
-
-
-    /**
-     * Returns whether to comment the SAML2 Logout endpoints.
-     *
-     * @return whether to comment the SAML2 Logout endpoints
-     */
-    public boolean isSAML2LogoutCommented() {
-        return saml2LogoutCommented;
-    }
-
-    /**
-     * Sets whether to comment the SAML2 Logout endpoints.
-     *
-     * @param asComment whether to comment or not
-     */
-    public void setSAML2LogoutCommented(final boolean asComment) {
-        saml2LogoutCommented = asComment;
-    }
-
-    /** Generate the metadata given the parameters.
-     * @throws BuildException if badness occurs.
-     */
-    public void generate() throws BuildException {
-        checkComponentActive();
-        try {
-            writer.write("<?xml version=\"1.0\" encoding=\"UTF-8\"?>");
-            writer.newLine();
-            writeComments();
-            writer.write("<");
-            writer.write(EntityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write(' ');
-            writeNameSpace(null, SAMLConstants.SAML20MD_NS);
-            writeNameSpace(SignatureConstants.XMLSIG_PREFIX, SignatureConstants.XMLSIG_NS);
-            writeNameSpace(ExtensionsConstants.SHIB_MDEXT10_PREFIX, ExtensionsConstants.SHIB_MDEXT10_NS);
-            writeNameSpace(XMLConstants.XML_PREFIX, XMLConstants.XML_NS);
-            writeNameSpace(SAMLConstants.SAML20MDUI_PREFIX, SAMLConstants.SAML20MDUI_NS);
-            writeNameSpace(SAMLConstants.SAML20PREQ_ATTRR_PREFIX, SAMLConstants.SAML20PREQ_ATTR_NS);
-
-            writer.write(" validUntil=\"" + DOMTypeSupport.instantToString(Instant.now()) + "\"");
-
-            writer.write(" entityID=\"");
-            writer.write(params.getEntityID());
-            writer.write("\">");
-            writer.newLine();
-            writer.newLine();
-
-
-            writeIDPSSO();
-            writer.newLine();
-            writer.newLine();
-            writeAttributeAuthorityDescriptor();
-            writer.newLine();
-            writer.write("</EntityDescriptor>");
-            writer.newLine();
-            writer.flush();
-            writer.close();
-        } catch (final IOException e) {
-            try {
-                writer.close();
-            } catch (final IOException e1) {
-                // Ignore
-            }
-            throw new BuildException(e);
-        }
-    }
-
-    /**
-     * Add appropriate comments to metadata header.
-     *
-     * @throws IOException if badness occurs in the writer
-     */
-    protected void writeComments() throws IOException {
-        openComment();
-        writer.newLine();
-        writer.write("     This is example metadata only. Do *NOT* supply it as is without review,");
-        writer.newLine();
-        writer.write("     and do *NOT* provide it in real time to your partners.");
-        writer.newLine();
-        writer.newLine();
-        writer.write("     This metadata is not dynamic - it will not change as your configuration changes.");
-        writer.write("     On Demand Metadata Generation available from the metadatagen plugin.");
-        writer.newLine();
-        closeComment();
-        writer.newLine();
-    }
-
-    /**
-     * Writeout a prefix/namespace pair.
-     *
-     * @param prefix the prefix, or null
-     * @param name the namespace
-     * @throws IOException if badness happens
-     */
-    protected void writeNameSpace(@Nullable final String prefix, @Nonnull final String name) throws IOException {
-        writer.write(" xmlns");
-        if (null != prefix) {
-            writer.write(':');
-            writer.write(prefix);
-        }
-        writer.write("=\"");
-        writer.write(name);
-        writer.write("\"");
-    }
-
-    /**
-     * Write the <IDPSSODescriptor>.
-     *
-     * @throws IOException if badness happens
-     */
-    protected void writeIDPSSO() throws IOException {
-        final List<String> protocols;
-        if (isSAML1Commented()) {
-            protocols = CollectionSupport.singletonList(SAMLConstants.SAML20P_NS);
-        } else {
-            protocols = CollectionSupport.listOf(SAMLConstants.SAML20P_NS, SAMLConstants.SAML11P_NS, "urn:mace:shibboleth:1.0");
-        }
-
-        writeRoleDescriptor(IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME, protocols); 
-        writer.newLine();
-        openExtensions();
-        writeScope();
-        writeMDUI();
-        closeExtensions();
-        writer.newLine();
-        writeKeyDescriptors();
-        for (final Endpoints endpoint : ARTIFACT_ENDPOINTS) {
-            if (getEndpoints().contains(endpoint)) {
-                outputEndpoint(endpoint);
-            }
-        }
-        writer.newLine();
-        if (isSAML2LogoutCommented()) {
-            openComment();
-            writer.newLine();
-        }
-        for (final Endpoints endpoint : SLO_ENDPOINTS) {
-            if (getEndpoints().contains(endpoint)) {
-                outputEndpoint(endpoint);
-            }
-        }
-        if (isSAML2LogoutCommented()) {
-            closeComment();
-            writer.newLine();
-        }
-
-        writer.newLine();
-        for (final Endpoints endpoint : SSO_ENDPOINTS) {
-            if (getEndpoints().contains(endpoint)) {
-                outputEndpoint(endpoint);
-            }
-        }
-        writer.newLine();
-        writer.write("    </");
-        writer.write(IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write(">");
-        writer.newLine();
-    }
-
-    /**
-     * Write the <AttributeAuthorityDescriptor>.
-     *
-     * @throws IOException if badness happens
-     */
-    private void writeAttributeAuthorityDescriptor() throws IOException {
-        if (isSAML2AttributeQueryCommented() && isSAML1Commented()) {
-            openComment();
-        }
-        final List<String> protocols;
-        if (isSAML2AttributeQueryCommented()) {
-            protocols = CollectionSupport.singletonList(SAMLConstants.SAML11P_NS);
-        } else {
-            protocols = CollectionSupport.listOf(SAMLConstants.SAML20P_NS, SAMLConstants.SAML11P_NS);
-        }
-        writeRoleDescriptor(AttributeAuthorityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME, protocols);
-        writer.newLine();
-        openExtensions();
-        writeScope();
-        closeExtensions();
-        writer.newLine();
-        writeKeyDescriptors();
-        for (final Endpoints endpoint : AA_ENDPOINTS) {
-            if (getEndpoints().contains(endpoint)) {
-                outputEndpoint(endpoint);
-            }
-        }
-        writer.newLine();
-        writer.write("    </");
-        writer.write(AttributeAuthorityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        if (isSAML2AttributeQueryCommented() && isSAML1Commented()) {
-            closeComment();
-        }
-        writer.newLine();
-    }
-
-    /**
-     * Write out an role descriptor.
-     *
-     * @param name the name
-     * @param protocols the supported protocols
-     * @throws IOException when badness happebns
-     */
-    protected void writeRoleDescriptor(final String name, final List<String> protocols) throws IOException {
-        writer.write("    <");
-        writer.write(name);
-        writer.write(" protocolSupportEnumeration=\"");
-        boolean first = true;
-        for (final String protocol : protocols) {
-            if (!first) {
-                writer.write(" ");
-            }
-            writer.write(protocol);
-            first = false;
-        }
-        writer.write("\">");
-        writer.newLine();
-    }
-
-    /**
-     * Write the open <Extensions> elements.
-     *
-     * @throws IOException if badness happens
-     */
-    protected void openExtensions() throws IOException {
-
-        writer.write("        <");
-        writer.write(Extensions.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-    }
-
-    /**
-     * Write out the close <\Extensions> Element.
-     *
-     * @throws IOException if badness happens
-     */
-    protected void closeExtensions() throws IOException {
-
-        writer.write("        </");
-        writer.write(Extensions.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-    }
-
-    /**
-     * Write out the <shibmd:Scope> element.
-     *
-     * @throws IOException if badness happens
-     */
-    protected void writeScope() throws IOException {
-        final String scope = params.getScope();
-        if (null == scope || scope.isEmpty()) {
-            return;
-        }
-
-        writer.write("            <");
-        writeNameSpaceQualified(ExtensionsConstants.SHIB_MDEXT10_PREFIX, Scope.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write(" regexp=\"false\">");
-        writer.write(params.getScope());
-        writer.write("</");
-        writeNameSpaceQualified(ExtensionsConstants.SHIB_MDEXT10_PREFIX, Scope.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-    }
-
-    /**
-     * Write out the <mdui:UIINFO> element and children.
-     *
-     * @throws IOException if badness happens
-     */
-    protected void writeMDUI() throws IOException {
-        openComment();
-        writer.newLine();
-        writer.write("    Fill in the details for your IdP here ");
-        writer.newLine();
-        writer.newLine();
-
-        writer.write("            <");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, UIInfo.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-
-        // DisplayName
-        writer.write("                <");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write(' ');
-        writeLangAttribute("en");
-        writer.write('>');
-        writer.write("A Name for the IdP at ");
-        writer.write(params.getDnsName());
-        writer.write("</");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-
-        // Description
-        writer.write("                <");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write(' ');
-        writeLangAttribute("en");
-        writer.write('>');
-        writer.write("Enter a description of your IdP at ");
-        writer.write(params.getDnsName());
-        writer.write("</");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-
-        // Logo
-        writer.write("                <");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, Logo.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write(" height=\"80\" width=\"80\">");
-        writer.write("https://");
-        writer.write(params.getDnsName());
-        writer.write("/Path/To/Logo.png");
-        writer.write("</");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, Logo.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-
-        writer.write("            </");
-        writeNameSpaceQualified(SAMLConstants.SAML20MDUI_PREFIX, UIInfo.DEFAULT_ELEMENT_LOCAL_NAME);
-        writer.write('>');
-        writer.newLine();
-
-        closeComment();
-        writer.newLine();
-    }
-
-    /**
-     * Write the language attribute.
-     *
-     * @param language which languages
-     * @throws IOException if badness happens
-     */
-    protected void writeLangAttribute(final String language) throws IOException {
-        writeNameSpaceQualified(XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME);
-        writer.write("=\"");
-        writer.write(language);
-        writer.write('"');
-    }
-
-    /**
-     * Write out any <KeyDescriptor>Elements.
-     *
-     * @throws IOException if badness happens
-     */
-    protected void writeKeyDescriptors() throws IOException {
-        final List<List<String>> signing = new ArrayList<>(2);
-        final List<String> backchannelCert = params.getBackchannelCert();
-        if (backchannelCert != null && !backchannelCert.isEmpty()) {
-            writer.write("        ");
-            openComment();
-            writer.write(" First signing certificate is BackChannel, the Second is FrontChannel");
-            closeComment();
-            writer.newLine();
-            signing.add(backchannelCert);
-        }
-        final List<String> signingCert = params.getSigningCert();
-        if (signingCert!= null && !signingCert.isEmpty()) {
-            signing.add(signingCert);
-        }
-        writeKeyDescriptors(signing, "signing");
-        
-        final List<String> encryption = params.getEncryptionCert();
-        if (encryption != null) {
-            writeKeyDescriptors(CollectionSupport.singletonList(encryption), "encryption");
-        }
-        writer.newLine();
-    }
-
-    /**
-     * Write out <KeyDescriptor>Elements. of a specific type
-     *
-     * @param certs the certificates
-     * @param use the type - signing or encryption
-     * @throws IOException if badness happens
-     */
-    protected void writeKeyDescriptors(@Nullable final List<List<String>> certs, @Nonnull @NotEmpty final String use)
-            throws IOException {
-
-        if (null == certs || certs.isEmpty()) {
-            return;
-        }
-        for (final List<String> cert : certs) {
-            writer.write("        <");
-            writer.write(KeyDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write(" use=\"");
-            writer.write(use);
-            writer.write("\">");
-            writer.newLine();
-            writer.write("            <");
-            writeNameSpaceQualified(SignatureConstants.XMLSIG_PREFIX, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-            writer.write("                    <");
-            writeNameSpaceQualified(SignatureConstants.XMLSIG_PREFIX, X509Data.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-            writer.write("                        <");
-            writeNameSpaceQualified(SignatureConstants.XMLSIG_PREFIX, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-            for (final String certLine : cert) {
-                writer.write(certLine);
-                writer.newLine();
-            }
-            writer.write("                        </");
-            writeNameSpaceQualified(SignatureConstants.XMLSIG_PREFIX, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-            writer.write("                    </");
-            writeNameSpaceQualified(SignatureConstants.XMLSIG_PREFIX, X509Data.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-            writer.write("            </");
-            writeNameSpaceQualified(SignatureConstants.XMLSIG_PREFIX, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-            writer.newLine();
-            writer.write("        </");
-            writer.write(KeyDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
-            writer.write('>');
-            writer.newLine();
-        }
-    }
-
-    /**
-     * Output the SAML for a single endpoint.
-     *
-     * @param endpoint the type
-     * @throws IOException if badness happens.
-     */
-    // Checkstyle: MethodLength|CyclomaticComplexity OFF
-    protected void outputEndpoint(final Endpoints endpoint) throws IOException {
-        switch (endpoint) {
-            case SAML1Artifact:
-                writer.write("        ");
-                if (isSAML1Commented()) {
-                    openComment();
-                }
-                writer.write("<");
-                writer.write(ArtifactResolutionService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML1_SOAP11_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write(":8443/idp/profile/SAML1/SOAP/ArtifactResolution\"");
-                writer.write(" index=\"1\"/>");
-                writer.newLine();
-                if (isSAML1Commented()) {
-                    closeComment();
-                }
-                break;
-
-            case SAML2Artifact:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(ArtifactResolutionService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_SOAP11_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write(":8443/idp/profile/SAML2/SOAP/ArtifactResolution\"");
-                writer.write(" index=\"2\"/>");
-                writer.newLine();
-                break;
-
-            case RedirectSLO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/SAML2/Redirect/SLO\"/>");
-                writer.newLine();
-                break;
-
-            case POSTSLO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_POST_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/SAML2/POST/SLO\"/>");
-                writer.newLine();
-                break;
-
-            case POSTSimpleSignSLO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/SAML2/POST-SimpleSign/SLO\"/>");
-                writer.newLine();
-                break;
-
-            case SOAPSLO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_SOAP11_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write(":8443/idp/profile/SAML2/SOAP/SLO\"/>");
-                writer.newLine();
-                break;
-
-            case ShibbolethSSO:
-                writer.write("        ");
-                if (isSAML1Commented()) {
-                    openComment();
-                }
-                writer.write("<");
-                writer.write(SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"urn:mace:shibboleth:1.0:profiles:AuthnRequest\"");
-                writer.write(" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/Shibboleth/SSO\"/>");
-                writer.newLine();
-                if (isSAML1Commented()) {
-                    closeComment();
-                }
-                break;
-
-            case POSTSSO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_POST_BINDING_URI);
-                writer.write("\" ");
-                writeNameSpaceQualified(SAMLConstants.SAML20PREQ_ATTRR_PREFIX,
-                        RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME);
-                writer.write("=\"true\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/SAML2/POST/SSO\"/>");
-                writer.newLine();
-                break;
-
-            case POSTSimpleSignSSO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI);
-                writer.write("\" ");
-                writeNameSpaceQualified(SAMLConstants.SAML20PREQ_ATTRR_PREFIX,
-                        RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME);
-                writer.write("=\"true\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/SAML2/POST-SimpleSign/SSO\"/>");
-                writer.newLine();
-                break;
-
-            case RedirectSSO:
-                writer.write("        ");
-                writer.write("<");
-                writer.write(SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_REDIRECT_BINDING_URI);
-                writer.write("\" ");
-                writeNameSpaceQualified(SAMLConstants.SAML20PREQ_ATTRR_PREFIX,
-                        RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME);
-                writer.write("=\"true\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write("/idp/profile/SAML2/Redirect/SSO\"/>");
-                writer.newLine();
-                break;
-
-            case SAML1Query:
-                writer.write("        ");
-                if (isSAML1Commented()) {
-                    openComment();
-                }
-                writer.write("<");
-                writer.write(AttributeService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML1_SOAP11_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write(":8443/idp/profile/SAML1/SOAP/AttributeQuery\"/>");
-                if (isSAML1Commented()) {
-                    closeComment();
-                }
-                writer.newLine();
-                break;
-
-            case SAML2Query:
-                writer.write("        ");
-                if (isSAML2AttributeQueryCommented()) {
-                    openComment();
-                }
-                writer.write("<");
-                writer.write(AttributeService.DEFAULT_ELEMENT_LOCAL_NAME);
-                writer.write(" Binding=\"");
-                writer.write(SAMLConstants.SAML2_SOAP11_BINDING_URI);
-                writer.write("\" Location=\"https://");
-                writer.write(params.getDnsName());
-                writer.write(":8443/idp/profile/SAML2/SOAP/AttributeQuery\"/>");
-                if (isSAML2AttributeQueryCommented()) {
-                    closeComment();
-                    writer.newLine();
-                    writer.write("        ");
-                    openComment();
-                    writer.write(" If you uncomment the above you should add " + SAMLConstants.SAML20P_NS
-                            + " to the protocolSupportEnumeration above");
-                    closeComment();
-                }
-                writer.newLine();
-                break;
-
-            default:
-                break;
-        }
-    }
-
-    /**
-     * Write a namespace:identifier pair.
-     *
-     * @param nameSpace the namespace
-     * @param what the identifier
-     * @throws IOException if badness happens
-     */
-    protected void writeNameSpaceQualified(@Nonnull final String nameSpace, final String what) throws IOException {
-        writer.write(nameSpace);
-        writer.write(':');
-        writer.write(what);
-    }
-
-    /** Add an open comment.  If we are nested closes the previous one.
-     * @throws IOException if badness happens
-     */
-    private synchronized void openComment() throws IOException {
-        if (commentDepth > 0) {
-            writer.write("--> ");
-        }
-        writer.write("<!--");
-        commentDepth++;
-    }
-
-    /** Add a close  comment.  If we are nested reopens the previous one.
-     * @throws IOException if badness happens
-     */
-    private synchronized void closeComment() throws IOException {
-        writer.write("--> ");
-        commentDepth--;
-        if (commentDepth > 0) {
-            writer.write(" <!--");
-        }
-    }
-}
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/MetadataGeneratorParameters.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/MetadataGeneratorParameters.java
deleted file mode 100644
index 0f9dab109..000000000
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/MetadataGeneratorParameters.java
+++ /dev/null
@@ -1,266 +0,0 @@
-/*
- * 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.installer.metadata.impl;
-
-import java.io.BufferedReader;
-import java.io.File;
-import java.io.FileReader;
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
-
-import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
-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.component.AbstractInitializableComponent;
-import net.shibboleth.shared.component.ComponentInitializationException;
-import net.shibboleth.shared.resource.Resource;
-
-/**
- * Parameters to metadata generation
- */
-public class MetadataGeneratorParameters extends AbstractInitializableComponent {
-
-    /**
-     * The file with the certificate the IDP uses to encrypt.
-     */
-    @Nullable private File encryptionCert;
-
-    /**
-     * The strings with the encryption cert in them (to allow for multiline output).
-     */
-    @Nullable private List<String> encryptionCerts;
-
-    /**
-     * The file with the certificate that TLS uses to 'sign'.
-     */
-    @Nullable private File backChannelCert;
-
-    /**
-     * The strings with the back channel cert in them (to allow for multiline output).
-     */
-    @Nullable private List<String> backChannelCerts;
-
-    /**
-     * The file with the certificate the IDP uses to sign.
-     */
-    @Nullable private File signingCert;
-
-    /**
-     * The strings with the signing certs in them (to allow for multiline output).
-     */
-    @Nullable private List<String> signingCerts;
-
-    /** The entityID. */
-    @NonnullAfterInit private String entityID;
-
-    /** The DNS name. */
-    @NonnullAfterInit private String dnsName;
-
-    /** The scope. */
-    @Nullable private String scope;
-
-    /** {@inheritDoc} */
-    protected void doInitialize() throws ComponentInitializationException {
-        try {
-            encryptionCerts = getCertificateContents(encryptionCert);
-            signingCerts = getCertificateContents(signingCert);
-            backChannelCerts = getCertificateContents(backChannelCert);
-        } catch (final IOException e) {
-            throw new ComponentInitializationException(e);
-        }
-        if (entityID == null || entityID.isEmpty()) {
-            throw new ComponentInitializationException("Entity ID not specified");
-        }
-        if (dnsName == null || dnsName.isEmpty()) {
-            throw new ComponentInitializationException("DNS name not specified");
-        }
-    }
-
-    /**
-     * Get the (mutli-line) string representations of the encryption certs.
-     *
-     * @return Returns the encryption cert or null if none available.
-     */
-    @Nullable public List<String> getEncryptionCert() {
-        return encryptionCerts;
-    }
-
-    /**
-     * Set the encryption Certificate file.
-     *
-     * @param resource what to set.
-     */
-    public void setEncryptionCertResource(@Nonnull final Resource resource) {
-
-        try {
-            encryptionCert = resource.getFile();
-        } catch (final IOException e) {
-            encryptionCert = null;
-        }
-    }
-
-    /**
-     * Get the (mutli-line) string representation of the signing cert.
-     *
-     * @return Returns the signing cert or null if none available.
-     */
-    @Nullable public List<String> getSigningCert() {
-        return signingCerts;
-    }
-
-    /**
-     * Set the signing Certificate file.
-     *
-     * @param resource what to set.
-     */
-    public void setSigningCertResource(@Nonnull final Resource resource) {
-        try {
-            signingCert = resource.getFile();
-        } catch (final IOException e) {
-            signingCert = null;
-        }
-    }
-
-    /**
-     * Get the (mutli-line)string representation of the back channel cert.
-     *
-     * @return Returns the back channel cert or null if non available.
-     */
-    @Nullable public List<String> getBackchannelCert() {
-        return backChannelCerts;
-    }
-
-    /**
-     * Set the Backchannel Certificate file.
-     *
-     * @param file what to set.
-     */
-    public void setBackchannelCert(@Nullable final File file) {
-        backChannelCert = file;
-    }
-    
-    /**
-     * Set the Backchannel Certificate.
-     *
-     * @param resource what to set.
-     */
-    public void setBackchannelCertResource(@Nonnull final Resource resource) {
-        try {
-            backChannelCert = resource.getFile();
-        } catch (final IOException e) {
-            backChannelCert = null;
-        } 
-    }
-
-
-    /**
-     * Open the file and return the contents and a list of lines.
-     *
-     * @param file the file
-     * @return the contents
-     * 
-     * @throws IOException if badness occurrs
-     */
-    @Nullable @Unmodifiable @NotLive private List<String> getCertificateContents(final File file) throws IOException {
-        if (null == file || !file.exists()) {
-            return null;
-        }
-
-        try (final FileReader fr = new FileReader(file);
-                final BufferedReader reader = new BufferedReader(fr)) {
-            final List<String> output = new ArrayList<>();
-            String s = reader.readLine();
-            while (s != null) {
-                output.add(s);
-                s = reader.readLine();
-            }
-            if ((output.size() > 0) && output.get(0).startsWith("----")) {
-                output.remove(0);
-            }
-            final int last = output.size() - 1;
-            if (last <= 0) {
-                return null;
-            }
-            if (output.get(last).startsWith("----")) {
-                output.remove(last);
-            }
-            return output;
-        }
-    }
-
-    /**
-     * Returns the entityID.
-     *
-     * @return the entityID.
-     */
-    @Nonnull @NotEmpty public String getEntityID() {
-        assert entityID != null;
-        return entityID;
-    }
-
-    /**
-     * Sets the entityID.
-     *
-     * @param id what to set.
-     */
-    public void setEntityID(@Nonnull final String id) {
-        entityID = id;
-    }
-
-    /**
-     * Returns the dnsName (for use in endpoints).
-     *
-     * @return the dnsname.
-     */
-    @Nonnull @NotEmpty public String getDnsName() {
-        assert dnsName != null;
-        return dnsName;
-    }
-
-    /**
-     * Sets the dns name.
-     *
-     * @param name what to set.
-     */
-    public void setDnsName(@Nonnull final String name) {
-        dnsName = name;
-    }
-
-    /**
-     * Returns the scope used.
-     *
-     * @return the scope.
-     */
-    @Nullable public String getScope() {
-        return scope;
-    }
-
-    /**
-     * Sets the scope.
-     *
-     * @param value what to set.
-     */
-    public void setScope(@Nullable final String value) {
-        scope = value;
-    }
-}
diff --git a/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/package-info.java b/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/package-info.java
deleted file mode 100644
index 9fb4c8fd4..000000000
--- a/idp-installer/src/main/java/net/shibboleth/idp/installer/metadata/impl/package-info.java
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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 to contain classes to do with the one off metadata generation.
- */
- at NonnullElements
-package net.shibboleth.idp.installer.metadata.impl;
-
-import net.shibboleth.shared.annotation.constraint.NonnullElements;
diff --git a/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator-ant.xml b/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator-ant.xml
deleted file mode 100644
index f9d393ce3..000000000
--- a/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator-ant.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
-	xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	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">
-	<bean
-		class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
-		p:placeholderPrefix="%{" p:placeholderSuffix="}" />
-
-    <context:property-placeholder />
-
-	<bean id="IdPConfiguration"
-		class="net.shibboleth.idp.installer.metadata.impl.MetadataGeneratorParameters"
-		p:encryptionCertResource="%{idp.encryption.cert}" p:signingCertResource="%{idp.signing.cert}"
-		p:entityID="%{idp.entityID}" p:scope="%{idp.scope}" />
-</beans>
\ No newline at end of file
diff --git a/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator.xml b/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator.xml
index d9f814fdc..1ac927780 100644
--- a/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator.xml
+++ b/idp-installer/src/main/resources/net/shibboleth/idp/installer/metadata-generator.xml
@@ -1,19 +1,34 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <beans xmlns="http://www.springframework.org/schema/beans"
-	xmlns:context="http://www.springframework.org/schema/context"
-	xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
-	xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:util="http://www.springframework.org/schema/util" xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:c="http://www.springframework.org/schema/c" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    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"
     default-destroy-method="destroy">
 
-	<bean id="IdPConfiguration"
-		class="net.shibboleth.idp.installer.metadata.impl.MetadataGeneratorParameters"
-		p:encryptionCertResource="%{idp.encryption.cert}"
+    <bean id="IdPConfiguration"
+        class="net.shibboleth.idp.installer.impl.InstalledMetadataParameters"
+        p:encryptionCertResource="%{idp.encryption.cert}"
         p:signingCertResource="%{idp.signing.cert}"
         p:backchannelCertResource="%{idp.backchannel.cert}"
         p:dnsName="%{idp.dnsname}"
-		p:entityID="%{idp.entityID}" p:scope="%{idp.scope}" />
-</beans>
\ No newline at end of file
+        p:entityID="%{idp.entityID}" p:scope="%{idp.scope}" />
+        
+    <util:map id="VelocityEngineProperties">
+        <entry key="parser.space_gobbling" value="%{idp.velocity.space.gobbling:bc}" />
+        <entry key="resource.loaders" value="file, classpath, string" />
+        <entry key="resource.loader.classpath.class" value="org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" />
+        <entry key="resource.loader.string.class" value="org.apache.velocity.runtime.resource.loader.StringResourceLoader" />
+        <entry key="resource.loader.file.class" value="org.apache.velocity.runtime.resource.loader.FileResourceLoader" />
+        <entry key="resource.loader.file.path" value="#{'%{idp.views:%{idp.home}/views}'.trim()}" />
+        <entry key="resource.loader.file.cache" value="false" />
+        <entry key="runtime.strict_mode.enable" value="%{idp.velocity.runtime.strictmode:false}" />
+    </util:map>
+
+    <bean id="VelocityEngine" class="net.shibboleth.shared.spring.velocity.VelocityEngineFactoryBean"
+        p:velocityPropertiesMap-ref="VelocityEngineProperties" />
+
+</beans>

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


More information about the commits mailing list