[java-oidfed-common] 05/05: Initial version of the oidfed/test-trust-chain-resolution admin flow

Codeberg noreply at shibboleth.net
Fri May 22 10:52:52 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-oidfed-common.

View the commit online:
https://codeberg.org/Shibboleth/java-oidfed-common/commit/4edf0265ad5e547248a11b2447b9571791405285

commit 4edf0265ad5e547248a11b2447b9571791405285
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Fri May 22 13:52:16 2026 +0300

    Initial version of the oidfed/test-trust-chain-resolution admin flow
    
    - CLI interface via bin/test-trust-chain-resolution.(sh/bat)
      - '-id'/'--entityID' is the only mandatory parameter
    - Intial flow tests
---
 .../META-INF/net.shibboleth.idp/postconfig.xml     |  17 +++
 .../test-trust-chain-resolution-beans.xml          |  61 +++++++++
 .../test-trust-chain-resolution-flow.xml           |  56 ++++++++
 .../admin/oidfed/test-trust-chain-resolution.vm    |  50 +++++++
 .../flow/TestTrustChainResolutionFlowTest.java     | 142 ++++++++++++++++++++
 oidfed-common-impl/pom.xml                         |  10 ++
 .../cli/TestTrustChainResolutionArguments.java     | 149 +++++++++++++++++++++
 .../oidfed/bin/test-trust-chain-resolution.bat     |   4 +
 .../oidfed/bin/test-trust-chain-resolution.sh      |   9 ++
 .../net/shibboleth/oidfed/module.properties        |  11 ++
 10 files changed, 509 insertions(+)

diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index ee919fc..28f8e06 100644
--- a/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -1050,6 +1050,23 @@
         class="net.shibboleth.oidfed.profile.navigate.DefaultTrustAnchorHintsLookupStrategy"
         p:trustAnchorsCache-ref="shibboleth.oidfed.LocalTrustAnchorsMetadataCache"/>
 
+    <bean parent="shibboleth.AdminFlow"
+            c:id="http://shibboleth.net/ns/profiles/oidfed/test-trust-chain-resolution"
+            p:loggingId="%{idp.oidfed.admin.trustchains.logging:ClientManagement}"
+            p:policyName="%{idp.oidfed.admin.trustchains.accessPolicy:AccessByIPAddress}"
+            p:nonBrowserSupported="%{idp.oidfed.admin.trustchains.nonBrowserSupported:true}"
+            p:authenticated="%{idp.oidfed.admin.trustchains.authenticated:false}"
+            p:resolveAttributes="%{idp.oidfed.admin.trustchains.resolveAttributes:false}">
+        <property name="postAuthenticationFlows">
+            <bean parent="shibboleth.CommaDelimStringArray"
+                c:_0="#{'%{idp.oidfed.admin.trustchains.postAuthenticationFlows:}'.trim()}" />
+        </property>
+        <property name="defaultAuthenticationMethodsByString">
+            <bean parent="shibboleth.CommaDelimStringArray"
+                c:_0="#{'%{idp.oidfed.admin.trustchains.defaultAuthenticationMethods:}'.trim()}" />
+         </property>
+    </bean>
+
     <import resource="${idp.home}/conf/oidfed/oidfed-trustchain-resolver.xml"/>
 
 </beans>
\ No newline at end of file
diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml
new file mode 100644
index 0000000..ba8058a
--- /dev/null
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-beans.xml
@@ -0,0 +1,61 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans
+    xmlns="http://www.springframework.org/schema/beans"
+    xmlns:c="http://www.springframework.org/schema/c"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:util="http://www.springframework.org/schema/util"
+    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">
+
+    <!-- Profile ID for flow. -->    
+    <bean id="shibboleth.AdminProfileId" class="java.lang.String"
+        c:_0="http://shibboleth.net/ns/profiles/oidfed/test-trust-chain-resolution" />
+
+    <!-- Profile counter name. -->
+    <bean id="shibboleth.metrics.ProfileCounter" class="java.lang.String" c:_0="net.shibboleth.idp.profiles.oidfed.test-trust-chain-resolution" />
+
+    <bean id="shibboleth.AdminOperationLookupStrategy" parent="shibboleth.Functions.Constant" c:target="execute" />
+    
+    <bean id="shibboleth.AdminResourceLookupStrategy" parent="shibboleth.Functions.Constant"
+        c:target="oidfed/test-trust-chain-resolution" />
+    
+    <bean id="shibboleth.oidfed.trust-chain-resolver.EntityIDLookupStrategy"
+        parent="shibboleth.Functions.Expression"
+        c:expression="#custom.apply(#input)">
+        <property name="customObject">
+            <bean class="net.shibboleth.idp.profile.context.navigate.SpringFlowScopeLookupFunction"
+                c:_0="entityID" />
+        </property>
+    </bean>
+
+    <bean id="shibboleth.oidfed.DefaultPreSelectedTrustChainIDsLookupStrategy"
+        parent="shibboleth.Functions.Constant"
+        c:target="#{null}"/>
+
+    <bean id="UseResolverApiCondition"
+        parent="shibboleth.Conditions.Expression"
+        c:expression="'true'.equalsIgnoreCase(#custom.get().getParameter('useResolverApi'))"
+        p:customObject-ref="shibboleth.HttpServletRequestSupplier" />
+
+    <bean id="FallbackToLocalResolutionCondition"
+        parent="shibboleth.Conditions.Expression"
+        c:expression="'true'.equalsIgnoreCase(#custom.get().getParameter('fallbackToLocalResolution'))"
+        p:customObject-ref="shibboleth.HttpServletRequestSupplier" />
+
+    <bean id="oidc.messageEncoderFactory"
+        class="net.shibboleth.oidc.profile.encoding.impl.OIDCResponseEncoderFactory"
+        p:messageEncoder-ref="oidc.nimbusEncoder" scope="prototype" />
+
+    <bean id="oidc.nimbusEncoder" class="net.shibboleth.oidc.profile.encoding.impl.SimpleNimbusResponseEncoder"
+        scope="prototype" p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" init-method=""/>
+
+    <bean id="EncodeMessage" class="org.opensaml.profile.action.impl.EncodeMessage" scope="prototype"
+        p:messageEncoderFactory-ref="oidc.messageEncoderFactory"
+        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
+
+</beans>
diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-flow.xml b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-flow.xml
new file mode 100644
index 0000000..8e6caf6
--- /dev/null
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/admin/oidfed/test-trust-chain-resolution/test-trust-chain-resolution-flow.xml
@@ -0,0 +1,56 @@
+<flow xmlns="http://www.springframework.org/schema/webflow"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+    parent="admin.abstract,oidfed/resolve-trust-chains">
+
+    <!-- Start action. -->
+
+    <on-start>
+        <evaluate expression="'ResponseView'" result="flowScope.ErrorState"/>
+        <evaluate expression="'ResponseView'" result="flowScope.AuditedErrorState"/>
+        <evaluate expression="T(net.shibboleth.shared.primitive.StringSupport).trimOrNull(externalContext.getNativeRequest().getParameter('entityID'))" result="flowScope.entityID" />
+        <evaluate expression="T(net.shibboleth.shared.primitive.StringSupport).trimOrNull(externalContext.getNativeRequest().getParameter('includeJWT'))" result="flowScope.includeJWT" />
+        <evaluate expression="T(net.shibboleth.shared.primitive.StringSupport).trimOrNull(externalContext.getNativeRequest().getParameter('includeMetadata'))" result="flowScope.includeMetadata" />
+        <evaluate expression="T(net.shibboleth.shared.primitive.StringSupport).trimOrNull(externalContext.getNativeRequest().getParameter('useResolverApi'))" result="flowScope.useResolverApi" />
+    </on-start>
+    
+    <action-state id="InitializeProfileRequestContext">
+        <evaluate expression="InitializeProfileRequestContext" />
+        <evaluate expression="PopulateMetricContext" />
+        <evaluate expression="FlowStartPopulateAuditContext" />
+        <evaluate expression="'proceed'" />
+        
+        <!-- Branch to determine if authentication is required. -->
+        <transition on="proceed" to="DoAdminPreamble" />
+    </action-state>
+
+    <!-- Resume actual flow processing. -->
+
+    <action-state id="DoProfileWork">
+        <evaluate expression="CheckAccess" />
+        <evaluate expression="'proceed'" />
+        <transition on="proceed" to="ChooseResolutionMethod">
+            <set name="flowScope.transitionAfterTrustChainResolution" value="'ResponseView'" />
+            <set name="flowScope.transitionOnNoTrustChainsResolved" value="'ResponseView'" />
+            <evaluate expression="opensamlProfileRequestContext.ensureInboundMessageContext()"/>
+        </transition>
+    </action-state>
+    
+    <end-state id="ResponseView" view="admin/oidfed/test-trust-chain-resolution">
+        <on-entry>
+            <evaluate expression="WriteAuditLog" />
+            <evaluate expression="environment" result="requestScope.environment" />
+            <evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
+            <evaluate expression="opensamlProfileRequestContext.ensureInboundMessageContext().ensureSubcontext(T(net.shibboleth.oidfed.profile.context.RelyingPartyTrustChainContext))" result="requestScope.trustChaintContext" />
+            <evaluate expression="T(org.opensaml.core.xml.util.XMLObjectSupport)" result="requestScope.XMLObjectSupport" />
+            <evaluate expression="T(net.shibboleth.shared.xml.SerializeSupport)" result="requestScope.SerializeSupport" />
+            <evaluate expression="T(net.shibboleth.shared.codec.HTMLEncoder)" result="requestScope.encoder" />
+            <evaluate expression="flowRequestContext.getExternalContext().getNativeRequest()" result="requestScope.request" />
+            <evaluate expression="flowRequestContext.getExternalContext().getNativeResponse()" result="requestScope.response" />
+            <evaluate expression="flowRequestContext.getActiveFlow().getApplicationContext().containsBean('shibboleth.CustomViewContext') ? flowRequestContext.getActiveFlow().getApplicationContext().getBean('shibboleth.CustomViewContext') : null" result="requestScope.custom" />
+        </on-entry>
+    </end-state>
+
+    <bean-import resource="test-trust-chain-resolution-beans.xml" />
+
+</flow>
diff --git a/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm
new file mode 100644
index 0000000..dce384c
--- /dev/null
+++ b/oidfed-common-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/views/admin/oidfed/test-trust-chain-resolution.vm
@@ -0,0 +1,50 @@
+##
+## Velocity Template for test-trust-chain-resolution Utility Output
+##
+## Velocity context will contain the following properties
+## flowRequestContext - the Spring Web Flow RequestContext
+## request - HttpServletRequest
+## response - HttpServletResponse
+## profileRequestContext
+## trustChaintContext
+## includeJWT
+## includeMetadata
+## SerializeSupport
+## environment - Spring Environment object for property resolution
+## custom - arbitrary object injected by deployer
+##
+[#if ($trustChaintContext and $trustChaintContext.getPolicyCompliantTrustChains() and !$trustChaintContext.getPolicyCompliantTrustChains().isEmpty())
+
+#foreach ($policyCompliantChain in $trustChaintContext.getPolicyCompliantTrustChains())
+    {
+        "trust_chain" : [
+#foreach ($entityStatement in $policyCompliantChain.getTrustChain())
+            {
+#if ($entityStatement.getSubject().equals($entityStatement.getIssuer()))
+                "type": "entity_configuration",
+#else
+                "type": "subordinate_statement",
+                "issuer": "$entityStatement.getIssuer()",
+#end
+                "subject" : "$entityStatement.getSubject()",
+                "issuedAt" : "$entityStatement.getParsedPayload().getIssuedAt()",
+                "expiresAt" : "$entityStatement.getParsedPayload().getExpiration()"#if($includeJWT),
+                "rawJwt" : "$entityStatement.getJwt().serialize()"#end
+            }#if( $foreach.hasNext ),#end
+#end
+        ],
+        "metadata_entities" : [
+#foreach ($metadataKey in $policyCompliantChain.getMetadata().getAllClaims().keySet())
+            "$metadataKey"#if( $foreach.hasNext ),#end
+#end   
+        ]#if($includeMetadata),
+        "metadata_details" : [
+#foreach ($metadataKey in $policyCompliantChain.getMetadata().getAllClaims().keySet())
+            "$metadataKey": $policyCompliantChain.getMetadata().getAllClaims().get($metadataKey)#if( $foreach.hasNext ),#end
+#end
+        ]
+#end
+    }#if( $foreach.hasNext ),#end
+#end
+#end]
+$response.setContentType("application/json")
\ No newline at end of file
diff --git a/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java
new file mode 100644
index 0000000..0a750e6
--- /dev/null
+++ b/oidfed-common-conf-impl/src/test/java/net/shibboleth/oidfed/flow/TestTrustChainResolutionFlowTest.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed 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.oidfed.flow;
+
+import static org.testng.Assert.assertEquals;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URI;
+import java.time.Instant;
+import java.util.List;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+
+import org.springframework.webflow.execution.FlowExecutionOutcome;
+import org.springframework.webflow.executor.FlowExecutionResult;
+import org.testng.Assert;
+import org.testng.annotations.Test;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.nimbusds.jose.JWSAlgorithm;
+import com.nimbusds.jose.jwk.JWKSet;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientMetadata;
+
+import net.shibboleth.oidfed.test.TrustChainTestUtil;
+import net.shibboleth.shared.collection.CollectionSupport;
+
+/**
+ * Admin test-trust-chain-resolution flow test.
+ */
+public class TestTrustChainResolutionFlowTest extends AbstractFederationFlowTest {
+
+    /** The flow id. */
+    @Nonnull public static final String FLOW_ID = "admin/oidfed/test-trust-chain-resolution";
+
+    /** Constructor. */
+    public TestTrustChainResolutionFlowTest() {
+        super(FLOW_ID, "ResponseView");
+    }
+
+    /**
+     * Test the flow without any parameters.
+     * 
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testWithNoParameters() throws Exception {
+        request.setMethod("GET");
+        final String entityId = super.uniqueClientId();
+
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setRedirectionURI(new URI(redirectUri));
+        metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+
+        final String rpEntityConfiguration = rpEntityConfiguration(entityId, metadata, List.of(Map.of(
+                "trust_mark_type", "https://example.org/email-allowing-trust-mark",
+                "trust_mark", trustMark)), leafKey);
+        rpConfigureMockHttpClient(entityId, rpEntityConfiguration);
+        try {
+            mapResponse(entityConfigurationUrl(trustMarkIssuerId),
+                    mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
+                    mockResponse(subordinateStatement(trustMarkIssuerId,
+                            Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
+            mapResponse(trustMarkStatusEndpoint, mockResponse(200, "application/trust-mark-status-response+jwt",
+                    trustMarkStatusResponse(trustMarkIssuerId, trustMark, "active", trustMarkIssuerKey)));
+        } catch (UnsupportedOperationException | IOException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+
+        final FlowExecutionOutcome outcome = result.getOutcome();
+        assertEquals(outcome.getId(), "ResponseView");
+        assertResponseArraySize(0);
+    }
+
+    /**
+     * Test the flow without any parameters.
+     * 
+     * @throws Exception if an error occurs
+     */
+    @Test
+    public void testWithOnlyEntityIDParameter() throws Exception {
+        request.setMethod("GET");
+        final String entityId = super.uniqueClientId();
+        request.addParameter("entityID", entityId);
+
+        final String trustMark = TrustChainTestUtil.trustMark(JWSAlgorithm.RS256, trustMarkIssuerKey, trustMarkIssuerId,
+                entityId, "https://example.org/email-allowing-trust-mark", Instant.now().plusSeconds(300)).serialize();
+        final OIDCClientMetadata metadata = new OIDCClientMetadata();
+        metadata.setRedirectionURI(new URI(redirectUri));
+        metadata.setJWKSet(new JWKSet(rpKey.toPublicJWK()));
+
+        final String rpEntityConfiguration = rpEntityConfiguration(entityId, metadata, List.of(Map.of(
+                "trust_mark_type", "https://example.org/email-allowing-trust-mark",
+                "trust_mark", trustMark)), leafKey);
+        rpConfigureMockHttpClient(entityId, rpEntityConfiguration);
+        try {
+            mapResponse(entityConfigurationUrl(trustMarkIssuerId),
+                    mockResponse(trustMarkIssuerConfiguration(trustMarkIssuerId)));
+            mapResponse(subordinateStatementUrl(anchorFetchEndpoint, trustMarkIssuerId),
+                    mockResponse(subordinateStatement(trustMarkIssuerId,
+                            Map.of("federation_entity", CollectionSupport.emptyMap()), trustMarkIssuerKey)));
+            mapResponse(trustMarkStatusEndpoint, mockResponse(200, "application/trust-mark-status-response+jwt",
+                    trustMarkStatusResponse(trustMarkIssuerId, trustMark, "active", trustMarkIssuerKey)));
+        } catch (UnsupportedOperationException | IOException e) {
+            Assert.fail("Could not initialize mock HTTP client", e);
+        }
+
+        final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
+
+        final FlowExecutionOutcome outcome = result.getOutcome();
+        assertEquals(outcome.getId(), "ResponseView");
+        assertResponseArraySize(1);
+    }
+
+    protected void assertResponseArraySize(final int expected) {
+        final ObjectMapper objectMapper = new ObjectMapper();
+        try {
+            Assert.assertEquals(objectMapper.readValue(response.getContentAsString(), List.class).size(), expected);
+        } catch (JsonProcessingException | UnsupportedEncodingException e) {
+            Assert.fail("Could not deserialize response", e);
+        }
+    }
+}
diff --git a/oidfed-common-impl/pom.xml b/oidfed-common-impl/pom.xml
index 008ee7a..ddc22b0 100644
--- a/oidfed-common-impl/pom.xml
+++ b/oidfed-common-impl/pom.xml
@@ -70,6 +70,11 @@
             <groupId>${idp.groupId}</groupId>
             <artifactId>idp-admin-impl</artifactId>
             <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>${idp.groupId}</groupId>
+            <artifactId>idp-cli</artifactId>
+            <scope>provided</scope>
         </dependency>
          <dependency>
             <groupId>${opensaml.groupId}</groupId>
@@ -151,6 +156,11 @@
             <artifactId>jackson-core</artifactId>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>com.beust</groupId>
+            <artifactId>jcommander</artifactId>
+            <scope>provided</scope>
+        </dependency>
 	</dependencies>
 	
 </project>
diff --git a/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/cli/TestTrustChainResolutionArguments.java b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/cli/TestTrustChainResolutionArguments.java
new file mode 100644
index 0000000..e284642
--- /dev/null
+++ b/oidfed-common-impl/src/main/java/net/shibboleth/oidfed/cli/TestTrustChainResolutionArguments.java
@@ -0,0 +1,149 @@
+/*
+ * Licensed 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.oidfed.cli;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.slf4j.Logger;
+
+import com.beust.jcommander.Parameter;
+
+import net.shibboleth.idp.cli.AbstractCommandLineArguments;
+import net.shibboleth.shared.primitive.LoggerFactory;
+
+/** Command line processing for test-trust-chain-resolution flow. */
+public class TestTrustChainResolutionArguments extends AbstractCommandLineArguments {
+
+    /** Logger. */
+    @Nullable private Logger log;
+
+    /** The URL parameter name for the entity ID whose trust chains are to be resolved. */
+    public static final String URL_PARAM_ENTITY_ID = "entityID";
+
+    /** The URL parameter name for the flag to signal full JWT details to be included. */
+    public static final String URL_PARAM_INCLUDE_JWT = "includeJWT";
+
+    /** The URL parameter name for the flag to signal full metadata details to be included. */
+    public static final String URL_PARAM_INCLUDE_METADATA = "includeMetadata";
+
+    /** The URL parameter name for the flag to signal use resolver API for resolution. */
+    public static final String URL_PARAM_USE_RESOLVER_API = "useResolverApi";
+
+    /** The URL parameter name for the flag to fallback to local resolution if resolver API fails. */
+    public static final String URL_PARAM_FALLBACK_TO_LOCAL = "fallbackToLocalResolution";
+
+    /** Metadata policy to embed in the token. */
+    @Parameter(names = {"-id", "--entityID"}, required = false, description = "Entity ID to be resolved")
+    @Nullable private String entityId;
+    
+    /** Flag to signal full JWT details to be included. */
+    @Parameter(names = {"-jwt", "--includeJwt"}, required = false,
+            description = "Flag to include raw entity statement JWTs in the response")
+    private boolean includeJwt;
+
+    /** Flag to signal full metadata to be included. */
+    @Parameter(names = {"-metadata", "--includeMetadata"}, required = false,
+            description = "Flag to include full metadata details in the response")
+    private boolean includeMetadata;
+
+    /** Flag to signal use resolver API for resolution. */
+    @Parameter(names = {"-api", "--useResolverApi"}, required = false,
+            description = "Flag to use resolve API for trust chain resolution")
+    private boolean useResolverApi;
+
+    /** Flag to signal fallback to local resolution if resolver API fails. */
+    @Parameter(names = {"-fallback", "--fallbackToLocalResolution"}, required = false,
+            description = "Flag to fallback to local resolution if resolve API resolution fails")
+    private boolean fallbackToLocal;
+
+    /** {@inheritDoc} */
+    @Override
+    public void validate() {
+        if (entityId == null) {
+            throw new IllegalArgumentException("Use of entityId is required");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected StringBuilder doBuildURL(@Nonnull final StringBuilder builder) {
+
+        if (getPath() == null) {
+            builder.append("/profile/admin/oidfed/test-trust-chain-resolution");
+        }
+
+        try {
+            appendSeparator(builder)
+            .append(URL_PARAM_ENTITY_ID + "=")
+            .append(URLEncoder.encode(entityId, "UTF-8"));
+
+            if (includeJwt) {
+                builder.append("&" + URL_PARAM_INCLUDE_JWT + "=true");
+            }
+            if (includeMetadata) {
+                builder.append("&" + URL_PARAM_INCLUDE_METADATA + "=true");
+            }
+            if (useResolverApi) {
+                builder.append("&" + URL_PARAM_USE_RESOLVER_API + "=true");
+            }
+            if (fallbackToLocal) {
+                builder.append("&" + URL_PARAM_FALLBACK_TO_LOCAL + "=true");
+            }
+
+            
+        } catch (final UnsupportedEncodingException e) {
+            // UTF-8 is a required encoding.
+            throw new RuntimeException("URL encoding failed", e);
+        }
+
+        return builder;
+     }
+    
+    /**
+     * Append the proper parameter separator to the builder.
+     * 
+     * @param builder input builder
+     * 
+     * @return the input
+     */
+    @Nonnull private StringBuilder appendSeparator(@Nonnull final StringBuilder builder) {
+        
+        if (builder.toString().contains("?")) {
+            builder.append('&');
+        } else {
+            builder.append('?');
+        }
+        
+        return builder;
+    }
+
+    /**
+     * Get logger to use.
+     * 
+     * @return logger
+     */
+    public @Nonnull Logger getLog() {
+        if (log == null) {
+            log = LoggerFactory.getLogger(TestTrustChainResolutionArguments.class);
+        }
+        assert log != null;
+        return log;
+    }
+
+}
\ No newline at end of file
diff --git a/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/bin/test-trust-chain-resolution.bat b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/bin/test-trust-chain-resolution.bat
new file mode 100644
index 0000000..26a686d
--- /dev/null
+++ b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/bin/test-trust-chain-resolution.bat
@@ -0,0 +1,4 @@
+ at echo off
+setlocal
+
+"%~dp0\runclass.bat" -Dnet.shibboleth.idp.cli.arguments=net.shibboleth.oidfed.cli.TestTrustChainResolutionArguments net.shibboleth.idp.cli.CLI %*
diff --git a/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/bin/test-trust-chain-resolution.sh b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/bin/test-trust-chain-resolution.sh
new file mode 100644
index 0000000..6dd0f3a
--- /dev/null
+++ b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/bin/test-trust-chain-resolution.sh
@@ -0,0 +1,9 @@
+#!/usr/bin/env bash
+
+declare LOCATION
+
+LOCATION=$(dirname $0)
+
+$LOCATION/runclass.sh \
+    -Dnet.shibboleth.idp.cli.arguments=net.shibboleth.oidfed.cli.TestTrustChainResolutionArguments \
+    net.shibboleth.idp.cli.CLI "$@"
diff --git a/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/module.properties b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/module.properties
index 2035cba..0607293 100644
--- a/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/module.properties
+++ b/oidfed-common-impl/src/main/resources/net/shibboleth/oidfed/module.properties
@@ -23,3 +23,14 @@ idp.oidfed.common.3.replace = false
 idp.oidfed.common.4.src =  /net/shibboleth/oidfed/conf/oidfed/oidfed-entity-configuration-claims.xml
 idp.oidfed.common.4.dest = conf/oidfed/oidfed-entity-configuration-claims.xml
 idp.oidfed.common.4.replace = false
+
+idp.oidfed.common.5.src = /net/shibboleth/oidfed/bin/test-trust-chain-resolution.sh
+idp.oidfed.common.5.dest = bin/test-trust-chain-resolution.sh
+idp.oidfed.common.5.exec = true
+idp.oidfed.common.5.replace = true
+idp.oidfed.common.5.windows = false
+
+idp.oidfed.common.6.src = /net/shibboleth/oidfed/bin/test-trust-chain-resolution.bat
+idp.oidfed.common.6.dest = bin/test-trust-chain-resolution.bat
+idp.oidfed.common.6.replace = true
+idp.oidfed.common.6.nonwindows = false

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


More information about the commits mailing list