[java-idp-plugin-metadatagen] branch dev/JMETAGEN-5 updated: Initial revamp of plugin around Velocity.
Scott Cantor
cantor.2 at osu.edu
Wed Jul 5 16:34:24 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=850c25c5c235c978a701eae1487c76e060c8bb4a
The following commit(s) were added to refs/heads/dev/JMETAGEN-5 by this push:
new 850c25c Initial revamp of plugin around Velocity.
850c25c is described below
commit 850c25c5c235c978a701eae1487c76e060c8bb4a
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jul 5 12:34:21 2023 -0400
Initial revamp of plugin around Velocity.
---
metadatagen-api/.checkstyle | 12 -
metadatagen-api/pom.xml | 51 --
.../shibboleth/idp/plugin/metadatagen/Version.java | 48 --
metadatagen-impl/.checkstyle | 2 +-
metadatagen-impl/pom.xml | 39 +-
.../plugin/metadatagen/impl/MetadataGenCLI.java | 818 +++++++++++----------
.../impl/MetadataGenCommandLineArguments.java | 459 +++++++++---
.../metadatagen-templates/EntityDescriptor.vm | 6 +
.../idp/plugin/metadatagen/conf/velocity.xml | 53 ++
.../idp/plugin/metadatagen/impl/plugin.properties | 2 +-
.../idp/plugin/metadatagen/metadatagen.xml | 23 -
.../plugin/metadatagen/impl/MetadataGenTest.java | 48 +-
.../src/test/resources/logback-test.xml | 6 +-
pom.xml | 6 -
.../checkstyle/checkstyle.xml | 0
15 files changed, 891 insertions(+), 682 deletions(-)
diff --git a/metadatagen-api/.checkstyle b/metadatagen-api/.checkstyle
deleted file mode 100644
index 42d2507..0000000
--- a/metadatagen-api/.checkstyle
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
- <local-check-config name="Shibboleth Checkstyle" location="/idp-plugin-metadatagen-parent/checkstyle.xml" type="project" description="">
- <additional-data name="cache-props-file-location" value="null_1312636288299_cache.properties"/>
- <additional-data name="cache-file-location" value="null_1312636288299_cache.xml"/>
- <additional-data name="protect-config-file" value="false"/>
- </local-check-config>
- <fileset name="all" enabled="true" check-config-name="Shibboleth Checkstyle" local="true">
- <file-match-pattern match-pattern="src/main/java/.*\.java$." include-pattern="true"/>
- </fileset>
-</fileset-config>
diff --git a/metadatagen-api/pom.xml b/metadatagen-api/pom.xml
deleted file mode 100644
index 7212b38..0000000
--- a/metadatagen-api/pom.xml
+++ /dev/null
@@ -1,51 +0,0 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
- <modelVersion>4.0.0</modelVersion>
-
- <parent>
- <groupId>net.shibboleth.idp.plugin.metadatagen</groupId>
- <artifactId>idp-plugin-metadatagen-parent</artifactId>
- <version>2.0.0-SNAPSHOT</version>
- </parent>
-
- <artifactId>idp-plugin-metadatagen-api</artifactId>
- <packaging>jar</packaging>
- <name>Shibboleth IdP :: Plugins :: metadatagen API</name>
- <description>IdP metadatagen plugin API.</description>
-
- <properties>
- <checkstyle.configLocation>${project.basedir}/../checkstyle.xml</checkstyle.configLocation>
- <automatic.module.name>net.shibboleth.idp.plugin.metadatagen.api</automatic.module.name>
- </properties>
-
- <dependencies>
- </dependencies>
-
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-jar-plugin</artifactId>
- <configuration>
- <archive>
- <index>true</index>
- <manifestEntries>
- <Main-Class>net.shibboleth.idp.plugin.metadatagen.Version</Main-Class>
- </manifestEntries>
- <manifestSections>
- <manifestSection>
- <name>org/example/com/metadatagen/</name>
- <manifestEntries>
- <Implementation-Title>${project.artifactId}</Implementation-Title>
- <Implementation-Version>${project.version}</Implementation-Version>
- <Implementation-Vendor>shibboleth.net</Implementation-Vendor>
- </manifestEntries>
- </manifestSection>
- </manifestSections>
- </archive>
- </configuration>
- </plugin>
- </plugins>
- </build>
-</project>
diff --git a/metadatagen-api/src/main/java/net/shibboleth/idp/plugin/metadatagen/Version.java b/metadatagen-api/src/main/java/net/shibboleth/idp/plugin/metadatagen/Version.java
deleted file mode 100644
index 2350b93..0000000
--- a/metadatagen-api/src/main/java/net/shibboleth/idp/plugin/metadatagen/Version.java
+++ /dev/null
@@ -1,48 +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.plugin.metadatagen;
-
-import javax.annotation.Nullable;
-
-/** Class for getting and printing the version of the IdP. */
-public final class Version {
-
- /** IdP version. */
- @Nullable private static final String VERSION = Version.class.getPackage().getImplementationVersion();
-
- /** Constructor. */
- private Version() {
- }
-
- /**
- * Main entry point to program.
- *
- * @param args command line arguments
- */
- public static void main(final String[] args) {
- System.out.println(VERSION);
- }
-
- /**
- * Get the version of the IdP.
- *
- * @return version of the IdP
- */
- @Nullable public static String getVersion() {
- return VERSION;
- }
-}
\ No newline at end of file
diff --git a/metadatagen-impl/.checkstyle b/metadatagen-impl/.checkstyle
index 42d2507..573e4e0 100644
--- a/metadatagen-impl/.checkstyle
+++ b/metadatagen-impl/.checkstyle
@@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<fileset-config file-format-version="1.2.0" simple-config="false" sync-formatter="false">
- <local-check-config name="Shibboleth Checkstyle" location="/idp-plugin-metadatagen-parent/checkstyle.xml" type="project" description="">
+ <local-check-config name="Shibboleth Checkstyle" location="/java-idp-plugin-metadatagen/resources/checkstyle/checkstyle.xml" type="project" description="">
<additional-data name="cache-props-file-location" value="null_1312636288299_cache.properties"/>
<additional-data name="cache-file-location" value="null_1312636288299_cache.xml"/>
<additional-data name="protect-config-file" value="false"/>
diff --git a/metadatagen-impl/pom.xml b/metadatagen-impl/pom.xml
index c5d3207..b288b0a 100644
--- a/metadatagen-impl/pom.xml
+++ b/metadatagen-impl/pom.xml
@@ -19,11 +19,6 @@
</properties>
<dependencies>
- <!-- compile time intra project dependencies -->
- <dependency>
- <groupId>net.shibboleth.idp.plugin.metadatagen</groupId>
- <artifactId>idp-plugin-metadatagen-api</artifactId>
- </dependency>
<!-- Service API and Plugin Description dependency -->
<dependency>
<groupId>${idp.groupId}</groupId>
@@ -47,6 +42,22 @@
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-saml-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-security-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>${opensaml.groupId}</groupId>
+ <artifactId>opensaml-xmlsec-api</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
<dependency>
<groupId>${shib-shared.groupId}</groupId>
<artifactId>shib-cli</artifactId>
@@ -57,7 +68,25 @@
<artifactId>shib-support</artifactId>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>${shib-shared.groupId}</groupId>
+ <artifactId>shib-velocity</artifactId>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity-engine-core</artifactId>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Test dependencies. -->
+ <dependency>
+ <groupId>${idp.groupId}</groupId>
+ <artifactId>idp-conf-impl</artifactId>
+ <scope>test</scope>
+ </dependency>
+
</dependencies>
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 bdc718b..b5aa173 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
@@ -22,15 +22,24 @@ import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintWriter;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
import java.time.Instant;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.VelocityEngine;
+import org.apache.velocity.context.Context;
import org.opensaml.core.xml.LangBearing;
import org.opensaml.saml.common.xml.SAMLConstants;
import org.opensaml.saml.ext.reqattr.RequestedAttributes;
@@ -49,47 +58,57 @@ import org.opensaml.saml.saml2.metadata.KeyDescriptor;
import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
import org.opensaml.saml.saml2.metadata.SingleLogoutService;
import org.opensaml.saml.saml2.metadata.SingleSignOnService;
+import org.opensaml.security.x509.X509Support;
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 org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
import org.springframework.beans.factory.NoSuchBeanDefinitionException;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
-import net.shibboleth.idp.Version;
import net.shibboleth.idp.cli.AbstractIdPHomeAwareCommandLine;
import net.shibboleth.idp.saml.xmlobject.ExtensionsConstants;
import net.shibboleth.idp.saml.xmlobject.Scope;
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.cli.AbstractCommandLine;
+import net.shibboleth.shared.codec.Base64Support;
+import net.shibboleth.shared.codec.EncodingException;
import net.shibboleth.shared.collection.CollectionSupport;
import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.velocity.Template;
import net.shibboleth.shared.xml.DOMTypeSupport;
import net.shibboleth.shared.xml.XMLConstants;
/**
- * Command Line to generate Metadata.
+ * Command Line to generate SAML metadata.
*/
public final class MetadataGenCLI extends AbstractIdPHomeAwareCommandLine<MetadataGenCommandLineArguments> {
+ /** VelocityEngine bean name. */
+ @Nonnull @NotEmpty private static String VELOCITY_ENGINE_BEAN_NAME = "shibboleth.VelocityEngine";
+
/** Class logger. */
@Nullable private Logger log;
- /** Certificate and other property driven data. */
- private MetadataGenParameters parameters;
-
/** Where we are outputting to? */
private PrintWriter output;
/** The processed arguments. */
private MetadataGenCommandLineArguments args;
- /** The DnsName (cached because we need it often). */
- @Nullable private String dnsName;
+ /** Velocity engine for output generation. */
+ private VelocityEngine velocityEngine;
+
+ /** Constructor. */
+ public MetadataGenCLI() {
+ setCaseSensitiveOptions(false);
+ }
/** {@inheritDoc} */
@Override
@@ -109,412 +128,408 @@ public final class MetadataGenCLI extends AbstractIdPHomeAwareCommandLine<Metada
/** {@inheritDoc} */
@Nonnull protected String getVersion() {
- return Version.getVersion();
- }
-
- /** {@inheritDoc} */
- @Nonnull protected List<Resource> getAdditionalSpringResources() {
- return CollectionSupport.singletonList(new ClassPathResource("net/shibboleth/idp/plugin/metadatagen/metadatagen.xml"));
+ return getClass().getPackage().getImplementationVersion();
}
- /**
- * Write out any <KeyDescriptor>Elements.
- * @param outputBackChannel Do we output the back channel certificates?
- */
- private void outputKeyDescriptors(final boolean outputBackChannel) {
- final List<List<String>> signing = new ArrayList<>(2);
- if (outputBackChannel) {
- final List<String> backCert = parameters.getBackchannelCert();
- if (backCert != null && !backCert.isEmpty()) {
- output.format(" <!-- First signing certificate is BackChannel, the Second is FrontChannel -->\n");
- signing.add(backCert);
- }
- }
- final List<String> signCert = parameters.getSigningCert();
- if (signCert != null && !signCert.isEmpty()) {
- signing.add(signCert);
- }
- outputKeyDescriptors(signing, "signing");
- outputKeyDescriptors(Collections.singletonList(parameters.getEncryptionCert()), "encryption");
- output.format("\n");
- }
+// /**
+// * Write out any <KeyDescriptor>Elements.
+// * @param outputBackChannel Do we output the back channel certificates?
+// */
+// private void outputKeyDescriptors(final boolean outputBackChannel) {
+// final List<List<String>> signing = new ArrayList<>(2);
+// if (outputBackChannel) {
+// final List<String> backCert = parameters.getBackchannelCert();
+// if (backCert != null && !backCert.isEmpty()) {
+// output.format(" <!-- First signing certificate is BackChannel, the Second is FrontChannel -->\n");
+// signing.add(backCert);
+// }
+// }
+// final List<String> signCert = parameters.getSigningCert();
+// if (signCert != null && !signCert.isEmpty()) {
+// signing.add(signCert);
+// }
+// outputKeyDescriptors(signing, "signing");
+// outputKeyDescriptors(Collections.singletonList(parameters.getEncryptionCert()), "encryption");
+// output.format("\n");
+// }
+//
+// /**
+// * Write out <KeyDescriptor>Elements. of a specific type
+// *
+// * @param certs the certificates
+// * @param use the type - signing or encryption
+// */
+// private void outputKeyDescriptors(@Nullable final List<List<String>> certs, @Nonnull @NotEmpty final String use) {
+//
+// if (null == certs || certs.isEmpty()) {
+// return;
+// }
+// for (final List<String> cert : certs) {
+// output.format(" <%s use=\"%s\">\n",KeyDescriptor.DEFAULT_ELEMENT_LOCAL_NAME, use);
+// output.format(" <%s:%s>\n", SignatureConstants.XMLSIG_PREFIX, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format(" <%s:%s>\n",
+// SignatureConstants.XMLSIG_PREFIX, X509Data.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format(" <%s:%s>\n",
+// SignatureConstants.XMLSIG_PREFIX, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format("%s\n",String.join("\n", cert));
+// output.format(" </%s:%s>\n",
+// SignatureConstants.XMLSIG_PREFIX, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format(" </%s:%s>\n",
+// SignatureConstants.XMLSIG_PREFIX, X509Data.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format(" </%s:%s>\n",SignatureConstants.XMLSIG_PREFIX, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format(" </%s>\n\n",KeyDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+// }
+//
+// /** Output the MDUI for one language.
+// * @param lang the language to emit
+// *
+// */
+// private void outputMDUI(final String lang) {
+// final Environment env = getApplicationContext().getEnvironment();
+// final String displayName = env.getProperty(MetadataGenCommandLineArguments.MDUI_DISPLAY_NAME_PREFIX+lang);
+// if (displayName != null) {
+// output.format(" <%s:%s %s:%s=\"%s\">%s</%s:%s>\n",
+// SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME,
+// XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
+// lang, displayName,
+// SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+// final String description = env.getProperty(MetadataGenCommandLineArguments.MDUI_DESCRIPTION_PREFIX+lang);
+// if (description != null) {
+// output.format(" <%s:%s %s:%s=\"%s\">%s</%s:%s>\n",
+// SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME,
+// XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
+// lang, description,
+// SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+// }
+//
+// /** Output Scope and MDUI.
+// * @param includeMDUI do we output the MDUI
+// */
+// private void outputExtensions(final boolean includeMDUI) {
+// final Environment env = getApplicationContext().getEnvironment();
+// final String scope = StringSupport.trimOrNull(env.getProperty("idp.scope"));
+// if (!includeMDUI && scope == null) {
+// return;
+// }
+// output.format(" <%s>\n", Extensions.DEFAULT_ELEMENT_LOCAL_NAME);
+// if (scope != null) {
+// output.format(" <%s:%s regexp=\"false\">%s</%s:%s>\n",
+// ExtensionsConstants.SHIB_MDEXT10_PREFIX, Scope.DEFAULT_ELEMENT_LOCAL_NAME,
+// scope,
+// ExtensionsConstants.SHIB_MDEXT10_PREFIX, Scope.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+//
+// if (includeMDUI) {
+// output.format(" <%s:%s>\n",
+// SAMLConstants.SAML20MDUI_PREFIX, UIInfo.DEFAULT_ELEMENT_LOCAL_NAME);
+// final String mduiLangs = env.getProperty(MetadataGenCommandLineArguments.MDUI_LANGS_PROPERTY);
+// if (mduiLangs == null) {
+// output.format("\n<!--\n Fill in the details for your IdP here\n\n");
+// output.format(" <%s:%s %s:%s=\"en\">A Name for the IdP</%s:%s>\n",
+// SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME,
+// XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
+// SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME);
+// output.format(" <%s:%s %s:%s=\"en\">A Description for the IdP</%s:%s>\n",
+// SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME,
+// XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
+// SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME);
+// } else {
+// for (final String lang:mduiLangs.split(" ")) {
+// outputMDUI(lang);
+// }
+// }
+// final String logoY = env.getProperty(MetadataGenCommandLineArguments.MDUI_LOGO_HEIGHT, "80");
+// final String logoX = env.getProperty(MetadataGenCommandLineArguments.MDUI_LOGO_WIDTH, "80");
+// final String logoPath = env.getProperty(MetadataGenCommandLineArguments.MDUI_LOGO_PATH, "/path/to/logo");
+// output.format(" <%s:%s height=\"%s\" width=\"%s\">https://%s%s</%s:%s>\n",
+// SAMLConstants.SAML20MDUI_PREFIX, Logo.DEFAULT_ELEMENT_LOCAL_NAME,
+// logoY, logoX, getDnsName(), logoPath,
+// SAMLConstants.SAML20MDUI_PREFIX, Logo.DEFAULT_ELEMENT_LOCAL_NAME);
+// if (mduiLangs == null) {
+// output.format("-->\n\n");
+// }
+// output.format(" </%s:%s>\n", SAMLConstants.SAML20MDUI_PREFIX, UIInfo.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+// output.format("\n </%s>\n\n", Extensions.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+//
+// /** Output Logout end points. */
+// private void outputLogoutEndpoints() {
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s/idp/profile/SAML2/Redirect/SLO\"/>\n",
+// SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_REDIRECT_BINDING_URI,
+// getDnsName());
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s/idp/profile/SAML2/POST/SLO\"/>\n",
+// SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_POST_BINDING_URI,
+// getDnsName());
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s/idp/profile/SAML2/POST/SLO-SimpleSign\"/>\n",
+// SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI,
+// getDnsName());
+//
+// final List<String> backCert = parameters.getBackchannelCert();
+// if (backCert != null && !backCert.isEmpty()) {
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s:8443/idp/profile/SAML2/SOAP/SLO\"/>\n",
+// SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_SOAP11_BINDING_URI,
+// getDnsName());
+// }
+// }
+//
+// /** Output Artifact Endpoints. */
+// private void outputArtifactEndpoints() {
+// if (args.isSaml1()) {
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s:8443/idp/profile/SAML1/SOAP/ArtifactResolution\" index=\"1\"/>\n",
+// ArtifactResolutionService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML1_SOAP11_BINDING_URI,
+// getDnsName());
+// }
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s:8443/idp/profile/SAML2/SOAP/ArtifactResolution\" index=\"2\"/>\n",
+// ArtifactResolutionService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_SOAP11_BINDING_URI,
+// getDnsName());
+// }
+//
+// /** Output SSO Endpoints. */
+// private void outputSSOEndpoints() {
+// if (args.isSaml1()) {
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s/idp/profile/Shibboleth/SSO\"/>\n",
+// SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
+// "urn:mace:shibboleth:1.0:profiles:AuthnRequest",
+// getDnsName());
+//
+// }
+// output.format(" <%s Binding=\"%s\""
+// + " %s:%s=\"true\""
+// + " Location=\"https://%s/idp/profile/SAML2/POST/SSO\"/>\n",
+// SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_POST_BINDING_URI,
+// SAMLConstants.SAML20PREQ_ATTRR_PREFIX, RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME,
+// getDnsName());
+// output.format(" <%s Binding=\"%s\""
+// + " %s:%s=\"true\""
+// + " Location=\"https://%s/idp/profile/SAML2/POST-SimpleSign/SSO\"/>\n",
+// SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI,
+// SAMLConstants.SAML20PREQ_ATTRR_PREFIX, RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME,
+// getDnsName());
+// output.format(" <%s Binding=\"%s\""
+// + " %s:%s=\"true\""
+// + " Location=\"https://%s/idp/profile/SAML2/Redirect/SSO\"/>\n",
+// SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_REDIRECT_BINDING_URI,
+// SAMLConstants.SAML20PREQ_ATTRR_PREFIX, RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME,
+// getDnsName());
+// }
+//
+// /**
+// * Write the <IDPSSODescriptor>.
+// */
+// private void outputIDPSSO() {
+// final List<String> protocols = new ArrayList<>(4);
+// if (!args.isSaml1() && !args.isSaml2()) {
+// return;
+// }
+// if (args.isSaml1()) {
+// protocols.add(SAMLConstants.SAML20P_NS);
+// }
+// if (args.isSaml2()) {
+// protocols.add(SAMLConstants.SAML20P_NS);
+// protocols.add(SAMLConstants.SAML11P_NS);
+// protocols.add("urn:mace:shibboleth:1.0");
+// }
+// output.format(" <%s protocolSupportEnumeration=\"%s\">\n",
+// IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
+// String.join(" ", protocols));
+//
+// outputExtensions(true);
+//
+// outputKeyDescriptors(true);
+//
+// if (args.isArtifact()) {
+// outputArtifactEndpoints();
+// }
+//
+// if (args.isLogout()) {
+// outputLogoutEndpoints();
+// }
+//
+// outputSSOEndpoints();
+//
+// output.format(" </%s>\n", IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+//
+// /**
+// * Write the <AttributeAuthorityDescriptor>.*/
+// private void outputAtttributeAuthorityDescriptor() {
+// final List<String> protocols;
+//
+// if (args.isSaml1()) {
+// if (args.isAttributeFetch()) {
+// // Both
+// protocols = Arrays.asList(SAMLConstants.SAML20P_NS, SAMLConstants.SAML11P_NS);
+// } else {
+// // SAML1 only
+// protocols = Collections.singletonList(SAMLConstants.SAML11P_NS);
+// }
+// } else if (args.isAttributeFetch()) {
+// // SAML2 only
+// protocols = Collections.singletonList(SAMLConstants.SAML20P_NS);
+// } else {
+// // Neither
+// return;
+// }
+//
+// output.format(" <%s protocolSupportEnumeration=\"%s\">\n",
+// AttributeAuthorityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
+// String.join(" ", protocols));
+//
+// outputExtensions(false);
+// outputKeyDescriptors(true);
+// if (args.isSaml1()) {
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s:8443/idp/profile/SAML1/SOAP/AttributeQuery\"/>\n",
+// AttributeService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML1_SOAP11_BINDING_URI,
+// getDnsName());
+// }
+// if (args.isAttributeFetch()) {
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s:8443/idp/profile/SAML2/SOAP/AttributeQuery\"/>\n",
+// AttributeService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_SOAP11_BINDING_URI,
+// getDnsName());
+// }
+// output.format(" </%s>\n", AttributeAuthorityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+//
+// /**
+// * Write the <SPSSODescriptor>.
+// */
+// private void outputSPSSO() {
+// if (!args.isSamlSP()) {
+// return;
+// }
+// output.format(" <%s protocolSupportEnumeration=\"%s\">\n",
+// SPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML20P_NS);
+//
+// outputKeyDescriptors(false);
+//
+// output.format(" <%s Binding=\"%s\""
+// + " Location=\"https://%s/idp/profile/Authn/SAML2/POST/SSO\" index=\"0\"/>\n",
+// AssertionConsumerService.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML2_POST_BINDING_URI,
+// getDnsName());
+//
+// output.format(" </%s>\n", SPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+// }
+//
+//
+// /** Output the metadata.
+// * @return true iff this worked.
+// */
+// private int outputMetadata() {
+// output.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
+// output.format(" <!--\n");
+// output.format(" This is example metadata only. Do *NOT* supply it as is without review,\n");
+// output.format(" and do *NOT* provide it in real time to your partners.\n");
+// output.format(" This metadata is not dynamic - run metadatagen again to recreate.\n");
+// output.format(" Created: %s\n -->\n", Instant.now().toString());
+// output.format("<%s xmlns=\"%s\" xmlns:%s=\"%s\"\n", EntityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
+// SAMLConstants.SAML20MD_NS,
+// SignatureConstants.XMLSIG_PREFIX, SignatureConstants.XMLSIG_NS);
+// output.format(" xmlns:%s=\"%s\" xmlns:%s=\"%s\"\n",
+// ExtensionsConstants.SHIB_MDEXT10_PREFIX, ExtensionsConstants.SHIB_MDEXT10_NS,
+// XMLConstants.XML_PREFIX, XMLConstants.XML_NS);
+// output.format(" xmlns:%s=\"%s\" xmlns:%s=\"%s\"\n",
+// SAMLConstants.SAML20MDUI_PREFIX, SAMLConstants.SAML20MDUI_NS,
+// SAMLConstants.SAML20PREQ_ATTRR_PREFIX, SAMLConstants.SAML20PREQ_ATTR_NS);
+// output.format(" validUntil=\"%s\" entityID=\"%s\">\n\n",
+// DOMTypeSupport.instantToString(Instant.now()),
+// getApplicationContext().getEnvironment().getProperty("idp.entityID", "idp.example.org"));
+// outputIDPSSO();
+// outputAtttributeAuthorityDescriptor();
+// outputSPSSO();
+// output.format("</EntityDescriptor>\n");
+// output.flush();
+// output.close();
+// return RC_OK;
+// }
+
+
/**
- * Write out <KeyDescriptor>Elements. of a specific type
- *
- * @param certs the certificates
- * @param use the type - signing or encryption
- */
- private void outputKeyDescriptors(@Nullable final List<List<String>> certs, @Nonnull @NotEmpty final String use) {
-
- if (null == certs || certs.isEmpty()) {
- return;
- }
- for (final List<String> cert : certs) {
- output.format(" <%s use=\"%s\">\n",KeyDescriptor.DEFAULT_ELEMENT_LOCAL_NAME, use);
- output.format(" <%s:%s>\n", SignatureConstants.XMLSIG_PREFIX, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format(" <%s:%s>\n",
- SignatureConstants.XMLSIG_PREFIX, X509Data.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format(" <%s:%s>\n",
- SignatureConstants.XMLSIG_PREFIX, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format("%s\n",String.join("\n", cert));
- output.format(" </%s:%s>\n",
- SignatureConstants.XMLSIG_PREFIX, X509Certificate.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format(" </%s:%s>\n",
- SignatureConstants.XMLSIG_PREFIX, X509Data.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format(" </%s:%s>\n",SignatureConstants.XMLSIG_PREFIX, KeyInfo.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format(" </%s>\n\n",KeyDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
- }
- }
-
- /** Output the MDUI for one language.
- * @param lang the language to emit
- *
- */
- private void outputMDUI(final String lang) {
- final Environment env = getApplicationContext().getEnvironment();
- final String displayName = env.getProperty(MetadataGenCommandLineArguments.MDUI_DISPLAY_NAME_PREFIX+lang);
- if (displayName != null) {
- output.format(" <%s:%s %s:%s=\"%s\">%s</%s:%s>\n",
- SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME,
- XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
- lang, displayName,
- SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME);
- }
- final String description = env.getProperty(MetadataGenCommandLineArguments.MDUI_DESCRIPTION_PREFIX+lang);
- if (description != null) {
- output.format(" <%s:%s %s:%s=\"%s\">%s</%s:%s>\n",
- SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME,
- XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
- lang, description,
- SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME);
- }
- }
-
- /** Output Scope and MDUI.
- * @param includeMDUI do we output the MDUI
+ * 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
*/
- private void outputExtensions(final boolean includeMDUI) {
- final Environment env = getApplicationContext().getEnvironment();
- final String scope = StringSupport.trimOrNull(env.getProperty("idp.scope"));
- if (!includeMDUI && scope == null) {
- return;
- }
- output.format(" <%s>\n", Extensions.DEFAULT_ELEMENT_LOCAL_NAME);
- if (scope != null) {
- output.format(" <%s:%s regexp=\"false\">%s</%s:%s>\n",
- ExtensionsConstants.SHIB_MDEXT10_PREFIX, Scope.DEFAULT_ELEMENT_LOCAL_NAME,
- scope,
- ExtensionsConstants.SHIB_MDEXT10_PREFIX, Scope.DEFAULT_ELEMENT_LOCAL_NAME);
- }
-
- if (includeMDUI) {
- output.format(" <%s:%s>\n",
- SAMLConstants.SAML20MDUI_PREFIX, UIInfo.DEFAULT_ELEMENT_LOCAL_NAME);
- final String mduiLangs = env.getProperty(MetadataGenCommandLineArguments.MDUI_LANGS_PROPERTY);
- if (mduiLangs == null) {
- output.format("\n<!--\n Fill in the details for your IdP here\n\n");
- output.format(" <%s:%s %s:%s=\"en\">A Name for the IdP</%s:%s>\n",
- SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME,
- XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
- SAMLConstants.SAML20MDUI_PREFIX, DisplayName.DEFAULT_ELEMENT_LOCAL_NAME);
- output.format(" <%s:%s %s:%s=\"en\">A Description for the IdP</%s:%s>\n",
- SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME,
- XMLConstants.XML_PREFIX, LangBearing.XML_LANG_ATTR_LOCAL_NAME,
- SAMLConstants.SAML20MDUI_PREFIX, Description.DEFAULT_ELEMENT_LOCAL_NAME);
- } else {
- for (final String lang:mduiLangs.split(" ")) {
- outputMDUI(lang);
- }
- }
- final String logoY = env.getProperty(MetadataGenCommandLineArguments.MDUI_LOGO_HEIGHT, "80");
- final String logoX = env.getProperty(MetadataGenCommandLineArguments.MDUI_LOGO_WIDTH, "80");
- final String logoPath = env.getProperty(MetadataGenCommandLineArguments.MDUI_LOGO_PATH, "/path/to/logo");
- output.format(" <%s:%s height=\"%s\" width=\"%s\">https://%s%s</%s:%s>\n",
- SAMLConstants.SAML20MDUI_PREFIX, Logo.DEFAULT_ELEMENT_LOCAL_NAME,
- logoY, logoX, getDnsName(), logoPath,
- SAMLConstants.SAML20MDUI_PREFIX, Logo.DEFAULT_ELEMENT_LOCAL_NAME);
- if (mduiLangs == null) {
- output.format("-->\n\n");
- }
- output.format(" </%s:%s>\n", SAMLConstants.SAML20MDUI_PREFIX, UIInfo.DEFAULT_ELEMENT_LOCAL_NAME);
- }
- output.format("\n </%s>\n\n", Extensions.DEFAULT_ELEMENT_LOCAL_NAME);
+ @Nonnull private String getEncodedCertificate(@Nonnull final File file)
+ throws CertificateException, EncodingException {
+ final X509Certificate cert = X509Support.decodeCertificate(file);
+ return Base64Support.encode(cert.getEncoded(), true);
}
-
- /** Output Logout end points. */
- private void outputLogoutEndpoints() {
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s/idp/profile/SAML2/Redirect/SLO\"/>\n",
- SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_REDIRECT_BINDING_URI,
- getDnsName());
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s/idp/profile/SAML2/POST/SLO\"/>\n",
- SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_POST_BINDING_URI,
- getDnsName());
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s/idp/profile/SAML2/POST/SLO-SimpleSign\"/>\n",
- SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI,
- getDnsName());
-
- final List<String> backCert = parameters.getBackchannelCert();
- if (backCert != null && !backCert.isEmpty()) {
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s:8443/idp/profile/SAML2/SOAP/SLO\"/>\n",
- SingleLogoutService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_SOAP11_BINDING_URI,
- getDnsName());
- }
- }
-
- /** Output Artifact Endpoints. */
- private void outputArtifactEndpoints() {
- if (args.isSaml1()) {
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s:8443/idp/profile/SAML1/SOAP/ArtifactResolution\" index=\"1\"/>\n",
- ArtifactResolutionService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML1_SOAP11_BINDING_URI,
- getDnsName());
- }
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s:8443/idp/profile/SAML2/SOAP/ArtifactResolution\" index=\"2\"/>\n",
- ArtifactResolutionService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_SOAP11_BINDING_URI,
- getDnsName());
- }
-
- /** Output SSO Endpoints. */
- private void outputSSOEndpoints() {
- if (args.isSaml1()) {
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s/idp/profile/Shibboleth/SSO\"/>\n",
- SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
- "urn:mace:shibboleth:1.0:profiles:AuthnRequest",
- getDnsName());
-
- }
- output.format(" <%s Binding=\"%s\""
- + " %s:%s=\"true\""
- + " Location=\"https://%s/idp/profile/SAML2/POST/SSO\"/>\n",
- SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_POST_BINDING_URI,
- SAMLConstants.SAML20PREQ_ATTRR_PREFIX, RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME,
- getDnsName());
- output.format(" <%s Binding=\"%s\""
- + " %s:%s=\"true\""
- + " Location=\"https://%s/idp/profile/SAML2/POST-SimpleSign/SSO\"/>\n",
- SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_POST_SIMPLE_SIGN_BINDING_URI,
- SAMLConstants.SAML20PREQ_ATTRR_PREFIX, RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME,
- getDnsName());
- output.format(" <%s Binding=\"%s\""
- + " %s:%s=\"true\""
- + " Location=\"https://%s/idp/profile/SAML2/Redirect/SSO\"/>\n",
- SingleSignOnService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_REDIRECT_BINDING_URI,
- SAMLConstants.SAML20PREQ_ATTRR_PREFIX, RequestedAttributes.SUPPORTS_REQUESTED_ATTRIBUTES_LOCAL_NAME,
- getDnsName());
+
+ /** {@inheritDoc} */
+ @Override
+ @Nonnull @Unmodifiable @NotLive protected List<Resource> getAdditionalSpringResources() {
+ final Resource internal = new ClassPathResource("/net/shibboleth/idp/plugin/metadatagen/conf/velocity.xml");
+
+ return Stream.concat(Stream.of(internal),
+ super.getAdditionalSpringResources().stream()).collect(
+ CollectionSupport.nonnullCollector(Collectors.toUnmodifiableList())).get();
}
/**
- * Write the <IDPSSODescriptor>.
+ * Builds the Velocity template context.
+ *
+ * @return the populated context
*/
- private void outputIDPSSO() {
- final List<String> protocols = new ArrayList<>(4);
- if (!args.isSaml1() && !args.isSaml2()) {
- return;
- }
- if (args.isSaml1()) {
- protocols.add(SAMLConstants.SAML20P_NS);
+ @Nonnull private VelocityContext getVelocityContext() {
+ final VelocityContext context = new VelocityContext();
+ context.put("entityID", args.getEntityID());
+ context.put("omitNamespaces", args.isOmitNamespaces());
+ if (!args.isOmitNamespaces()) {
+ final Map<String,String> prefixMap = new HashMap<>();
+ prefixMap.put(SAMLConstants.SAML20MD_PREFIX, SAMLConstants.SAML20MD_NS);
+ prefixMap.put(SAMLConstants.SAML20_PREFIX, SAMLConstants.SAML20_NS);
+ prefixMap.put(SignatureConstants.XMLSIG_PREFIX, SignatureConstants.XMLSIG_NS);
+ context.put("namespaces", prefixMap);
}
- if (args.isSaml2()) {
- protocols.add(SAMLConstants.SAML20P_NS);
- protocols.add(SAMLConstants.SAML11P_NS);
- protocols.add("urn:mace:shibboleth:1.0");
- }
- output.format(" <%s protocolSupportEnumeration=\"%s\">\n",
- IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
- String.join(" ", protocols));
-
- outputExtensions(true);
-
- outputKeyDescriptors(true);
-
- if (args.isArtifact()) {
- outputArtifactEndpoints();
- }
-
- if (args.isLogout()) {
- outputLogoutEndpoints();
- }
-
- outputSSOEndpoints();
-
- output.format(" </%s>\n", IDPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
+ return context;
}
/**
- * Write the <AttributeAuthorityDescriptor>.*/
- private void outputAtttributeAuthorityDescriptor() {
- final List<String> protocols;
-
- if (args.isSaml1()) {
- if (args.isAttributeFetch()) {
- // Both
- protocols = Arrays.asList(SAMLConstants.SAML20P_NS, SAMLConstants.SAML11P_NS);
- } else {
- // SAML1 only
- protocols = Collections.singletonList(SAMLConstants.SAML11P_NS);
- }
- } else if (args.isAttributeFetch()) {
- // SAML2 only
- protocols = Collections.singletonList(SAMLConstants.SAML20P_NS);
- } else {
- // Neither
- return;
- }
-
- output.format(" <%s protocolSupportEnumeration=\"%s\">\n",
- AttributeAuthorityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
- String.join(" ", protocols));
-
- outputExtensions(false);
- outputKeyDescriptors(true);
- if (args.isSaml1()) {
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s:8443/idp/profile/SAML1/SOAP/AttributeQuery\"/>\n",
- AttributeService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML1_SOAP11_BINDING_URI,
- getDnsName());
- }
- if (args.isAttributeFetch()) {
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s:8443/idp/profile/SAML2/SOAP/AttributeQuery\"/>\n",
- AttributeService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_SOAP11_BINDING_URI,
- getDnsName());
- }
- output.format(" </%s>\n", AttributeAuthorityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
- }
-
- /**
- * Write the <SPSSODescriptor>.
- */
- private void outputSPSSO() {
- if (!args.isSamlSP()) {
- return;
- }
- output.format(" <%s protocolSupportEnumeration=\"%s\">\n",
- SPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML20P_NS);
-
- outputKeyDescriptors(false);
-
- output.format(" <%s Binding=\"%s\""
- + " Location=\"https://%s/idp/profile/Authn/SAML2/POST/SSO\" index=\"0\"/>\n",
- AssertionConsumerService.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML2_POST_BINDING_URI,
- getDnsName());
-
- output.format(" </%s>\n", SPSSODescriptor.DEFAULT_ELEMENT_LOCAL_NAME);
- }
-
-
- /** Output the metadata.
- * @return true iff this worked.
- */
- private int outputMetadata() {
- output.format("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
- output.format(" <!--\n");
- output.format(" This is example metadata only. Do *NOT* supply it as is without review,\n");
- output.format(" and do *NOT* provide it in real time to your partners.\n");
- output.format(" This metadata is not dynamic - run metadatagen again to recreate.\n");
- output.format(" Created: %s\n -->\n", Instant.now().toString());
- output.format("<%s xmlns=\"%s\" xmlns:%s=\"%s\"\n", EntityDescriptor.DEFAULT_ELEMENT_LOCAL_NAME,
- SAMLConstants.SAML20MD_NS,
- SignatureConstants.XMLSIG_PREFIX, SignatureConstants.XMLSIG_NS);
- output.format(" xmlns:%s=\"%s\" xmlns:%s=\"%s\"\n",
- ExtensionsConstants.SHIB_MDEXT10_PREFIX, ExtensionsConstants.SHIB_MDEXT10_NS,
- XMLConstants.XML_PREFIX, XMLConstants.XML_NS);
- output.format(" xmlns:%s=\"%s\" xmlns:%s=\"%s\"\n",
- SAMLConstants.SAML20MDUI_PREFIX, SAMLConstants.SAML20MDUI_NS,
- SAMLConstants.SAML20PREQ_ATTRR_PREFIX, SAMLConstants.SAML20PREQ_ATTR_NS);
- output.format(" validUntil=\"%s\" entityID=\"%s\">\n\n",
- DOMTypeSupport.instantToString(Instant.now()),
- getApplicationContext().getEnvironment().getProperty("idp.entityID", "idp.example.org"));
- outputIDPSSO();
- outputAtttributeAuthorityDescriptor();
- outputSPSSO();
- output.format("</EntityDescriptor>\n");
- output.flush();
- output.close();
- return RC_OK;
- }
-
- /** Lookup the dns name with a default and cache it.
- * @return the dns name
- */
- @Nonnull String getDnsName() {
- if (dnsName == null) {
- dnsName = getApplicationContext().
- getEnvironment().
- getProperty(MetadataGenCommandLineArguments.DNS_NAME_PROPERTY, "idp.example.org");
- }
- assert dnsName != null;
- return dnsName;
- }
-
- /** Build the {@link MetadataGenCLI#parameters} object.
+ * Set up {@link MetadataGenCLI#output}.
*
- * This does a lot of work which migbt be expected to be in {@link MetadataGenCommandLineArguments#validate()},
- * However at that point we do not have access to properties which change things some what.
- * @return true iff this worked and if everything needed was there.
- */
- // Checkstyle: CyclomaticComplexity OFF
- private boolean populateParameters() {
- try {
- parameters = getApplicationContext().getBean(MetadataGenParameters.class);
- } catch (final NoSuchBeanDefinitionException e) {
- getLogger().error("Could not locate IdPConfiguration");
- return false;
- }
-
- final List<String> backCert = parameters.getBackchannelCert();
- final boolean hasBackChannel = backCert != null && !backCert.isEmpty();
- boolean worked = true;
- if (args.isArtifact() && !hasBackChannel) {
- getLogger().error("Must specify --backChannel <path> if +artifact speificied");
- worked = false;
- }
- if (args.isAttributeFetch() && !hasBackChannel) {
- getLogger().error("Must specify --backChannel <path> if +attributeFetch speificied");
- worked = false;
- }
- if (hasBackChannel && !args.isAttributeFetch() && !args.isArtifact() && !args.isSaml1()) {
- getLogger().error("--backChannel <path> requires +artifact and/or +attributeFetch and/or +saml1");
- worked = false;
- }
- return worked;
- }
- // Checkstyle: CyclomaticComplexity ON
-
-
- /** Set up {@link MetadataGenCLI#output}.
- * @return true iff this worked.
+ * @return true iff this worked
*/
private boolean setupWriter() {
- if (args.getOutput() == null) {
+ if (args.getOutputFile() == null) {
output = new PrintWriter(System.out);
} else {
- final File out = new File(args.getOutput());
+ final File out = new File(args.getOutputFile());
try {
final FileOutputStream outStream = new FileOutputStream(out);
output = new PrintWriter(new BufferedOutputStream(outStream));
} catch (final IOException e) {
- getLogger().error("Could not open {}", args.getOutput(), e);
+ getLogger().error("Could not open {}", args.getOutputFile(), e);
return false;
}
}
@@ -530,15 +545,28 @@ public final class MetadataGenCLI extends AbstractIdPHomeAwareCommandLine<Metada
if (ret != RC_OK) {
return ret;
}
+
if (!setupWriter()) {
return RC_IO;
}
- if (!populateParameters()) {
+
+ try {
+ velocityEngine = getApplicationContext().getBean(VELOCITY_ENGINE_BEAN_NAME, VelocityEngine.class);
+ } catch (final BeansException e) {
+ getLogger().error("Unable to acquire Velocity engine bean", e);
+ return RC_INIT;
+ }
+
+ try {
+ Template.fromTemplateName(velocityEngine,
+ "/metadatagen-templates/EntityDescriptor.vm").merge(getVelocityContext(), output);
+ } catch (final Exception e) {
+ getLogger().error("Error generating output", e);
return RC_IO;
}
- final int i = outputMetadata();
- this.output.close();
- return i;
+
+ output.close();
+ return RC_OK;
}
/**
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 99dd42b..c5a4d8c 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,27 +16,26 @@
*/
package net.shibboleth.idp.plugin.metadatagen.impl;
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
import java.io.PrintStream;
import java.util.ArrayList;
import java.util.List;
-import java.util.Properties;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
+import org.opensaml.saml.saml2.metadata.ArtifactResolutionService;
+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.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.beust.jcommander.Parameter;
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.collection.CollectionSupport;
/**
* Command line arguments for Metadata Generation.
@@ -70,133 +69,344 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
/** Logger. */
@Nullable private Logger log;
- /** Do we output SAML2. */
- @Parameter(names = { "+saml2", "+2", "+SAML2"} )
+ /** The unique ID. */
+ @Parameter(names = {"--entityID", "--id"}, required=true, description="Unique ID for entity")
+ @Nullable private String entityID;
+
+ /** Do we output SAML 2.0? */
+ @Parameter(names = {"--saml2"}, description="Include SAML 2.0 support?")
private boolean saml2;
- /** Do we NOT output SAML2. */
- @Parameter(names = { "-saml2", "-2", "-SAML2"} )
- private boolean noSaml2;
+ /** Do we output CAS? */
+ @Parameter(names = {"--cas"}, description="Include CAS support?")
+ private boolean cas;
+
+ /** Do we output OIDC? */
+ @Parameter(names = {"--oidc"}, description="Include OpenID/OAuth support?")
+ private boolean oidc;
+
+ /** Do we output an SP role? */
+ @Parameter(names = {"--sp"}, description="Include Service Provider role?")
+ private boolean sp;
+
+ /** Do we output an SP role? */
+ @Parameter(names = {"--idp"}, description="Include Identity Provider role?")
+ private boolean idp;
+
+ /** Do we output an AA role?.*/
+ @Parameter(names = {"--aa"}, description="Include Attribute Authority role?")
+ private boolean aa;
+
+ @Parameter(names = {"--sso-redirect"}, description="SingleSignOnService endpoint using HTTP-Redirect binding")
+ @Nullable private String ssoRedirect;
+
+ @Parameter(names = {"--sso-post"}, description="SingleSignOnService endpoint using HTTP-POST binding")
+ @Nullable private String ssoPost;
+
+ @Parameter(names = {"--sso-artifact"}, description="SingleSignOnService endpoint using HTTP-Artifact binding")
+ @Nullable private String ssoArtifact;
+
+ @Parameter(names = {"--sso-soap"}, description="SingleSignOnService endpoint using SOAP binding")
+ @Nullable private String ssoSoap;
- /** Do we output SAM1.?*/
- @Parameter(names = { "+saml1", "+1", "+SAML1"})
- private boolean saml1;
+ @Parameter(names = {"--artifact-soap", "--artifact"}, description="ArtifactResolutionService endpoint using SOAP binding")
+ @Nullable private String artifactSoap;
- /** Do we output for an SP.*/
- @Parameter(names = { "+samlSP", "+sp", "+SP", "+SAMLSP"})
- private boolean samlSP;
+ @Parameter(names = {"--attr-soap"}, description="AttributeService endpoint using SOAP binding")
+ @Nullable private String attributeSoap;
- /** Do we output logout.*/
- @Parameter(names = { "+logout", "+lo"})
- private boolean logout;
+ @Parameter(names = {"--logout-redirect", "-LR"}, description="SingleLogoutService endpoint(s) using HTTP-Redirect binding")
+ @Nonnull private List<String> logoutRedirect = new ArrayList<>();
- /** Do we output Artifact.*/
- @Parameter(names = { "+artifact", "+artefact"})
- private boolean artifact;
+ @Parameter(names = {"--logout-post", "-LP"}, description="SingleLogoutService endpoint(s) using HTTP-POST binding")
+ @Nonnull private List<String> logoutPost = new ArrayList<>();
- /** Do we output for an Attribute Fetch.*/
- @Parameter(names = { "+attributeFetch"})
- private boolean attributeFetch;
+ @Parameter(names = {"--logout-artifact", "-LA"}, description="SingleLogoutService endpoint(s) using HTTP-Artifact binding")
+ @Nonnull private List<String> logoutArtifact = new ArrayList<>();
- /** Certificate for (IdP) BackChannel (attribute, artifact, logout).*/
- @Parameter(names = { "--backChannel", "-bc"})
- @Nullable private String backChannelPath;
+ @Parameter(names = {"--logout-soap", "-LS"}, description="SingleLogoutService endpoint(s) using SOAP binding")
+ @Nonnull private List<String> logoutSoap = new ArrayList<>();
- /** DNS name (for back channel addresses). */
- @Parameter(names = { "--DNSName", "-d"})
- @Nullable private String dnsName;
+ @Parameter(names = {"--acs", "--acs-post", "-h"}, description="AssertionConsumerService endpoint(s) using HTTP-POST binding")
+ @Nonnull private List<String> acsPost = new ArrayList<>();
- /** Output.*/
- @Parameter(names = { "--output", "-o"})
- @Nullable private String output;
+ @Parameter(names = {"--acs-artifact"}, description="AssertionConsumerService endpoint(s) using HTTP-Artifact binding")
+ @Nonnull private List<String> acsArtifact = new ArrayList<>();
- /** Do we output SAML2 metadata?
- * @return what.
+ @Parameter(names = {"--acs-paos", "--ecp"}, description="AssertionConsumerService endpoint(s) using PAOS binding")
+ @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")
+ @Nonnull private List<String> certificatePaths = new ArrayList<>();
+
+ /** Path(s) to signing certificate(s). */
+ @Parameter(names = {"--signing", "-x"}, description="Path(s) to certificate(s) for signing only")
+ @Nonnull private List<String> signingPaths = new ArrayList<>();
+
+ /** Path(s) to encryption certificate(s). */
+ @Parameter(names = {"--encryption", "-e"}, description="Path(s) to certificate(s) for encryption only")
+ @Nonnull private List<String> encryptionPaths = new ArrayList<>();
+
+ /** Omit namespaces from root element? */
+ @Parameter(names = {"--omit-namespaces"}, description="Omit namespace declarations (assumes surrounding document context)")
+ private boolean omitNamespaces;
+
+ /** Output file path. */
+ @Parameter(names = {"--file", "-f"}, description="Path to output file (stdout otherwise)")
+ @Nullable private String outputFile;
+
+ /**
+ * Get the unique ID.
+ *
+ * @return argument value
*/
- public boolean isSaml2() {
+ @Nullable public String getEntityID() {
+ return entityID;
+ }
+
+ /**
+ * Do we output SAML 2.0 metadata?
+ *
+ * @return argument value
+ */
+ public boolean isSAML2() {
return saml2;
}
- /** Do we output SAML1 metadata?
- * @return what.
+ /**
+ * Do we output CAS metadata?
+ *
+ * @return argument value
*/
- public boolean isSaml1() {
- return saml1;
+ public boolean isCAS() {
+ return cas;
}
- /** Do we output SAML SP metadata.
- * @return what.
+ /**
+ * Do we output OIDC/OAuth metadata?
+ *
+ * @return argument value
*/
- public boolean isSamlSP() {
- return samlSP;
+ public boolean isOIDC() {
+ return oidc;
}
- /** Do we output Logout metadata?
- * @return what.
+ /**
+ * Do we output SP role?
+ *
+ * @return argument value
*/
- public boolean isLogout() {
- return logout;
+ public boolean isSP() {
+ return sp;
}
- /** Do we output Artifact metadata?
- * @return what.
+ /**
+ * Do we output IdP role?
+ *
+ * @return argument value
*/
- public boolean isArtifact() {
- return artifact;
+ public boolean isIDP() {
+ return idp;
}
- /** Do we output Attribute Fetch metadata?
- * @return what.
+ /**
+ * Do we output AA role?
+ *
+ * @return argument value
*/
- public boolean isAttributeFetch() {
- return attributeFetch;
+ public boolean isAA() {
+ return aa;
+ }
+
+ /**
+ * Get endpoint expression for {@link SingleSignOnService} endpoints using SAML 2.0 HTTP-Redirect binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nullable String getSSORedirectEndpoint() {
+ return ssoRedirect;
}
- /** Where to put the data.
- * @return where
+ /**
+ * Get endpoint expression for {@link SingleSignOnService} endpoint using SAML 2.0 HTTP-POST binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
*/
- @Nullable public String getOutput() {
- return output;
+ @Nullable String getSSOPostEndpoint() {
+ return ssoPost;
+ }
+
+ /**
+ * Get endpoint expression for {@link SingleSignOnService} endpoint using SAML 2.0 HTTP-Artifact binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nullable String getSSOArtifactEndpoint() {
+ return ssoPost;
}
/**
- * {@inheritDoc}
+ * Get endpoint expression for {@link SingleSignOnService} endpoint using SAML 2.0 SOAP binding.
*
- * We override this to add a property file of our own making for
- * the backchannel (if needed) and dnsname.
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
*/
- @Nonnull @Unmodifiable @NotLive public List<String> getPropertyFiles() {
- final List<String> fromCmdline = super.getPropertyFiles();
- if (dnsName == null && backChannelPath == null) {
- return fromCmdline;
- }
+ @Nullable String getSSOSoapEndpoint() {
+ return ssoPost;
+ }
- final Properties props = new Properties(2);
- if (dnsName != null) {
- props.setProperty(DNS_NAME_PROPERTY, dnsName);
- }
- if (backChannelPath != null) {
- props.setProperty(BACKCHANNEL_PROPERTY, backChannelPath);
- }
+ /**
+ * Get endpoint expression for {@link ArtifactResolutionService} endpoint using SAML 2.0 SOAP binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nullable String getArtifactSoapEndpoint() {
+ return artifactSoap;
+ }
- final List<String> result = new ArrayList<>(fromCmdline.size() + 1);
-
- try {
- final File file = File.createTempFile("MetadataGen", ".properties");
- file.deleteOnExit();
- try (final FileOutputStream out = new FileOutputStream(file)) {
- props.store(out, "created");
- }
- if (fromCmdline.isEmpty()) {
- return CollectionSupport.singletonList(file.getAbsolutePath());
- }
- result.addAll(fromCmdline);
- result.add(file.getAbsolutePath());
- } catch (final IOException e) {
- getLog().error("Could not generate property file", e);
- }
+ /**
+ * 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
+ */
+ @Nullable String getAttributeSoapEndpoint() {
+ return attributeSoap;
+ }
+
+ /**
+ * Get endpoint expression(s) for {@link SingleLogoutService} endpoint(s) using SAML 2.0 HTTP-Redirect binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getLogoutRedirectEndpoints() {
+ return logoutRedirect;
+ }
- return result;
+ /**
+ * Get endpoint expression(s) for {@link SingleLogoutService} endpoint(s) using SAML 2.0 HTTP-POST binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getLogoutPostEndpoints() {
+ return logoutPost;
+ }
+
+ /**
+ * Get endpoint expression(s) for {@link SingleLogoutService} endpoint(s) using SAML 2.0 HTTP-Artifact binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getLogoutArtifactEndpoints() {
+ return logoutArtifact;
+ }
+
+ /**
+ * Get endpoint expression(s) for {@link SingleLogoutService} endpoint(s) using SAML 2.0 SOAP binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getLogoutSoapEndpoints() {
+ return logoutSoap;
+ }
+
+ /**
+ * Get endpoint expression(s) for {@link AssertionConsumerService} endpoint(s) using SAML 2.0 HTTP-POST binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getACSPostEndpoints() {
+ return acsPost;
+ }
+
+ /**
+ * Get endpoint expression(s) for {@link AssertionConsumerService} endpoint(s) using SAML 2.0 HTTP-Artifact binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getACSArtifactEndpoints() {
+ return acsPost;
+ }
+
+ /**
+ * Get endpoint expression(s) for {@link AssertionConsumerService} endpoint(s) using SAML 2.0 PAOS binding.
+ *
+ * <p>Endpoints may omit scheme but must specify port and full path.</p>
+ *
+ * @return argument value
+ */
+ @Nonnull @Live List<String> getACSPaosEndpoints() {
+ return acsPaos;
+ }
+
+ /**
+ * Dual-use certificate path(s).
+ *
+ * @return argument value
+ */
+ @Nullable @Live public List<String> getCertificatePaths() {
+ return certificatePaths;
+ }
+
+ /**
+ * Signing-only certificate path(s).
+ *
+ * @return argument value
+ */
+ @Nullable @Live public List<String> getSigningCertificatePaths() {
+ return signingPaths;
+ }
+
+ /**
+ * Encryption-only certificate path(s).
+ *
+ * @return argument value
+ */
+ @Nullable @Live public List<String> getEncryptionCertificatePaths() {
+ return encryptionPaths;
+ }
+
+ /**
+ * Gets whether to omit namespaces on root element.
+ *
+ * <p>Used to optimize namespace declarations when generating batches.</p>
+ *
+ * @return argument value
+ */
+ public boolean isOmitNamespaces() {
+ return omitNamespaces;
+ }
+
+ /**
+ * Output file path (stdout used otherwise).
+ *
+ * @return argument value
+ */
+ @Nullable public String getOutputFile() {
+ return outputFile;
}
/** {@inheritDoc} */
@@ -212,35 +422,52 @@ public class MetadataGenCommandLineArguments extends AbstractIdPHomeAwareCommand
/** {@inheritDoc} */
@Override
public void validate() throws IllegalArgumentException {
- if (!saml2 && noSaml2) {
- saml2 = false;
- } else {
+ if (!saml2 && !cas && !oidc) {
saml2 = true;
}
+
+ if (!sp && !idp && !aa) {
+ sp = true;
+ }
}
/** {@inheritDoc} */
@Override
public void printHelp(@Nonnull final PrintStream out) {
super.printHelp(out);
- out.println(String.format(" %-20s %s", "+SAML1, +1",
- "Output SAML1 Metadata."));
- out.println(String.format(" %-20s %s", "-SAML2, -2",
- "do NOT Output SAML2 Metadata."));
- out.println(String.format(" %-20s %s", "+SP, +SAMLSP",
- "Output SAML2 SP Metadata."));
- out.println(String.format(" %-20s %s", "+logout",
- "Output Logout Metadata."));
- out.println(String.format(" %-20s %s", "+artifact",
- "Output SAML artifact Metadata (requires -bc),"));
- out.println(String.format(" %-20s %s", "+attributeFetch",
- "Output SAML attributeFetch Metadata (requires -bc)."));
- out.println(String.format(" %-20s %s", "-bc, --backchannel <Path>",
- "Path to backchannel certificate"));
- out.println(String.format(" %-20s %s", "-d, --DNSName name",
- "DNS name to use in back channel addresses (default idp.example.org)"));
- out.println(String.format(" %-20s %s", "--output, -o",
- "Output location."));
+ out.println(String.format(" %-20s %s", "--entityID, --id", "The entityID (or client_id, etc.)"));
+
+ out.println(String.format(" %-20s %s", "--saml2", "Output SAML 2.0 metadata."));
+ out.println(String.format(" %-20s %s", "--cas", "Output CAS metadata."));
+ 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", "--aa", "Output Attribute Authority role."));
+
+ out.println(String.format(" %-20s %s", "--sso-redirect", "Endpoint for SAML 2.0 SSO HTTP-Redirect endpoint"));
+ out.println(String.format(" %-20s %s", "--sso-post", "Endpoint for SAML 2.0 SSO HTTP-POST endpoint"));
+ out.println(String.format(" %-20s %s", "--sso-artifact", "Endpoint for SAML 2.0 SSO HTTP-Artifact endpoint"));
+ out.println(String.format(" %-20s %s", "--sso-soap", "Endpoint for SAML 2.0 SSO SOAP endpoint"));
+
+ out.println(String.format(" %-20s %s", "--artifact-soap, --artifact", "Endpoint for SAML 2.0 Artifact Resolution SOAP endpoint"));
+ out.println(String.format(" %-20s %s", "--attr-soap", "Endpoint for SAML 2.0 Attribute Query SOAP endpoint"));
+
+ out.println(String.format(" %-20s %s", "--logout-redirect", "Endpoint for SAML 2.0 SLO HTTP-Redirect endpoint"));
+ out.println(String.format(" %-20s %s", "--logout-post", "Endpoint for SAML 2.0 SLO HTTP-POST endpoint"));
+ out.println(String.format(" %-20s %s", "--logout-artifact", "Endpoint for SAML 2.0 SLO HTTP-Artifact endpoint"));
+ out.println(String.format(" %-20s %s", "--logout-soap", "Endpoint for SAML 2.0 SLO SOAP endpoint"));
+
+ out.println(String.format(" %-20s %s", "--acs, --acs-post, -h", "Endpoint for SAML 2.0 ACS HTTP-POST endpoint"));
+ 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", "--signing, -x", "Path to signing certificate."));
+ out.println(String.format(" %-20s %s", "--encryption, -e", "Path to encryption certificate."));
+
+ out.println(String.format(" %-20s %s", "--omit-namespaces", "Omit namespaces on root element."));
+ out.println(String.format(" %-20s %s", "--output, -o", "Output file path."));
out.println();
}
diff --git a/metadatagen-impl/src/main/resources/metadatagen-templates/EntityDescriptor.vm b/metadatagen-impl/src/main/resources/metadatagen-templates/EntityDescriptor.vm
new file mode 100644
index 0000000..9cf6857
--- /dev/null
+++ b/metadatagen-impl/src/main/resources/metadatagen-templates/EntityDescriptor.vm
@@ -0,0 +1,6 @@
+## Open up new EntityDescriptor
+<md:EntityDescriptor#if (!$omitNamespaces)#foreach ($ns in $namespaces.entrySet()) xmlns:$ns.key="$ns.value"#end#end entityID="${entityID}">
+
+## All the interior bits....
+
+</md:EntityDescriptor>
diff --git a/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/conf/velocity.xml b/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/conf/velocity.xml
new file mode 100644
index 0000000..449d116
--- /dev/null
+++ b/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/conf/velocity.xml
@@ -0,0 +1,53 @@
+<?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"
+
+ default-init-method="initialize"
+ default-destroy-method="destroy">
+
+ <!-- Needed to allow for auto-wiring of descriptors and other components. -->
+ <context:annotation-config />
+
+ <bean id="shibboleth.PropertySourcesPlaceholderConfigurer"
+ class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
+ p:placeholderPrefix="%{" p:placeholderSuffix="}" />
+
+ <!-- This bean MUST be called "conversionService" to work properly. -->
+ <bean id="conversionService" class="org.springframework.context.support.ConversionServiceFactoryBean">
+ <property name="converters">
+ <set>
+ <bean class="net.shibboleth.shared.spring.config.StringToIPRangeConverter" />
+ <bean class="net.shibboleth.shared.spring.config.BooleanToPredicateConverter" />
+ <bean class="net.shibboleth.shared.spring.config.StringBooleanToPredicateConverter" />
+ <bean class="net.shibboleth.shared.spring.config.StringToResourceConverter" />
+ <bean class="net.shibboleth.shared.spring.config.StringToDurationConverter" />
+ <bean class="net.shibboleth.shared.spring.config.StringToPeriodConverter" />
+ </set>
+ </property>
+ </bean>
+
+ <!-- This BeanPostProcessor auto-sets identifiable beans with the bean name (if not already set). -->
+ <bean id="shibboleth.IdentifiableBeanPostProcessor"
+ class="net.shibboleth.shared.spring.config.IdentifiableBeanPostProcessor" />
+
+ <util:map id="shibboleth.DefaultVelocityEngineProperties">
+ <entry key="parser.space_gobbling" value="%{idp.velocity.space.gobbling:bc}" />
+ <entry key="resource.loaders" value="file, classpath" />
+ <entry key="resource.loader.classpath.class" value="org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader" />
+ <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="%{idp.velocity.file.cache:false}" />
+ <entry key="runtime.strict_mode.enable" value="%{idp.velocity.runtime.strictmode:true}" />
+ </util:map>
+
+ <bean id="shibboleth.VelocityEngine" class="net.shibboleth.shared.spring.velocity.VelocityEngineFactoryBean"
+ p:velocityPropertiesMap="#{getObject('shibboleth.VelocityEngineProperties') ?: getObject('shibboleth.DefaultVelocityEngineProperties')}" />
+
+ </beans>
diff --git a/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/impl/plugin.properties b/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/impl/plugin.properties
index 4044597..a846f00 100644
--- a/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/impl/plugin.properties
+++ b/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/impl/plugin.properties
@@ -2,7 +2,7 @@
plugin.id = net.shibboleth.idp.plugin.metadatagen
# Only used when package manifest is not available
-plugin.version = 1.0.1
+plugin.version = 2.0.0
# No prereqs
#plugin.modules.required =
diff --git a/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/metadatagen.xml b/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/metadatagen.xml
deleted file mode 100644
index 98ad360..0000000
--- a/metadatagen-impl/src/main/resources/net/shibboleth/idp/plugin/metadatagen/metadatagen.xml
+++ /dev/null
@@ -1,23 +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"
- default-init-method="initialize"
- default-destroy-method="destroy">
-
- <bean
- class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
- p:placeholderPrefix="%{" p:placeholderSuffix="}" />
-
- <context:property-placeholder />
-
- <bean id="IdPConfiguration"
- class="net.shibboleth.idp.plugin.metadatagen.impl.MetadataGenParameters"
- p:encryptionCertResource="%{idp.encryption.cert}"
- p:signingCertResource="%{idp.signing.cert}"
- p:backchannelCertResource="#{ environment.containsProperty('idp.metadata.backchannel.cert') ? '%{idp.metadata.backchannel.cert:0}' : null}" />
-</beans>
\ No newline at end of file
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 1f73ed9..c273d0e 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
@@ -32,17 +32,16 @@ import org.testng.annotations.Test;
import net.shibboleth.shared.cli.AbstractCommandLine;
-
@SuppressWarnings("javadoc")
public class MetadataGenTest {
-
+
// To run the test
// 1) Set the next two static fields
// 2) Edit the setting of the property 'idp.metadata.backchannel.cert' in
// src/test/resources/net/shibboleth/idp/plugin/metadatagen/impl/extra2
- private final static String IDP_HOME = "H:/Downloads/idp";
+ private final static String IDP_HOME = "/Users/scantor/Documents/shibboleth5/java-identity-provider/idp-conf-impl/src/main/resources/net/shibboleth/idp/module";
private final boolean enabled = false;
-
+
@Test(enabled = enabled) public void test() throws IOException {
assertEquals(MetadataGenCLI.runMain(
new String[] {
@@ -57,20 +56,19 @@ public class MetadataGenTest {
}
@Test(enabled = enabled) public void testProps() throws IOException {
- final File file1 = Files.createTempFile(getClass().getName(), ".props").toFile();
- file1.deleteOnExit();
- final ClassPathResource res1 = new ClassPathResource("/net/shibboleth/idp/plugin/metadatagen/impl/extra1");
- try (final InputStream stream = res1.getInputStream(); final OutputStream out = new BufferedOutputStream(new FileOutputStream(file1))) {
- stream.transferTo(out);
- }
- final File file2 = Files.createTempFile(getClass().getName(), ".props").toFile();
- file2.deleteOnExit();
- final ClassPathResource res2 = new ClassPathResource("/net/shibboleth/idp/plugin/metadatagen/impl/extra2");
- try (final InputStream stream = res2.getInputStream(); final OutputStream out = new BufferedOutputStream(new FileOutputStream(file2))) {
- stream.transferTo(out);
- }
-
-
+ final File file1 = Files.createTempFile(getClass().getName(), ".props").toFile();
+ file1.deleteOnExit();
+ final ClassPathResource res1 = new ClassPathResource("/net/shibboleth/idp/plugin/metadatagen/impl/extra1");
+ try (final InputStream stream = res1.getInputStream(); final OutputStream out = new BufferedOutputStream(new FileOutputStream(file1))) {
+ stream.transferTo(out);
+ }
+ final File file2 = Files.createTempFile(getClass().getName(), ".props").toFile();
+ file2.deleteOnExit();
+ final ClassPathResource res2 = new ClassPathResource("/net/shibboleth/idp/plugin/metadatagen/impl/extra2");
+ try (final InputStream stream = res2.getInputStream(); final OutputStream out = new BufferedOutputStream(new FileOutputStream(file2))) {
+ stream.transferTo(out);
+ }
+
assertEquals(MetadataGenCLI.runMain(
new String[] {
"--home", IDP_HOME,
@@ -78,10 +76,9 @@ public class MetadataGenTest {
"+saml1",
"--propertyFiles", file1.getPath() +","+ file2.getPath(),
"+attributeFetch","+artifact", "+logout",
- }),
+ }),
AbstractCommandLine.RC_OK);
}
-
@Test(enabled = enabled) public void noBc() throws IOException {
assertEquals(MetadataGenCLI.runMain(
@@ -92,7 +89,6 @@ public class MetadataGenTest {
AbstractCommandLine.RC_OK);
}
-
@Test(enabled = enabled) public void help() throws IOException {
assertEquals(MetadataGenCLI.runMain(
new String[] {
@@ -101,4 +97,14 @@ public class MetadataGenTest {
AbstractCommandLine.RC_OK);
}
+ @Test(enabled = true) public void testSimple() {
+ assertEquals(MetadataGenCLI.runMain(
+ new String[] {
+ "--home", IDP_HOME,
+ "--sp",
+ "--entityID", "https://sp.example.org",
+ }),
+ AbstractCommandLine.RC_OK);
+ }
+
}
\ No newline at end of file
diff --git a/metadatagen-impl/src/test/resources/logback-test.xml b/metadatagen-impl/src/test/resources/logback-test.xml
index a58ce3f..1e2200b 100644
--- a/metadatagen-impl/src/test/resources/logback-test.xml
+++ b/metadatagen-impl/src/test/resources/logback-test.xml
@@ -1,8 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
- <logger name="net.shibboleth" level="ALL"/>
- <logger name="org.springframework" level="DEBUG"/>
+ <logger name="net.shibboleth" level="DEBUG"/>
+ <logger name="org.springframework" level="INFO"/>
<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
<encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
@@ -12,7 +12,7 @@
</appender>
<root>
- <level value="ALL" />
+ <level value="INFO" />
<appender-ref ref="STDOUT" />
</root>
diff --git a/pom.xml b/pom.xml
index 0a0ea43..22e8957 100644
--- a/pom.xml
+++ b/pom.xml
@@ -67,11 +67,6 @@
<dependencyManagement>
<!-- metadatagen project dependencies -->
<dependencies>
- <dependency>
- <groupId>net.shibboleth.idp.plugin.metadatagen</groupId>
- <artifactId>idp-plugin-metadatagen-api</artifactId>
- <version>${project.version}</version>
- </dependency>
<dependency>
<groupId>net.shibboleth.idp.plugin.metadatagen</groupId>
<artifactId>idp-plugin-metadatagen-impl</artifactId>
@@ -118,7 +113,6 @@
<modules>
<module>metadatagen-impl</module>
- <module>metadatagen-api</module>
<!-- All DIST modules must come after the -api and -impl modules -->
<module>metadatagen-dist</module>
</modules>
diff --git a/checkstyle.xml b/resources/checkstyle/checkstyle.xml
similarity index 100%
rename from checkstyle.xml
rename to resources/checkstyle/checkstyle.xml
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list