[java-identity-provider] branch main updated: IDP-2126 - Admin flow to report on config settings

Scott Cantor cantor.2 at osu.edu
Mon Jun 12 16:20:30 UTC 2023


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

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

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

The following commit(s) were added to refs/heads/main by this push:
     new 6ec010d19 IDP-2126 - Admin flow to report on config settings
6ec010d19 is described below

commit 6ec010d19f1689141b89a30c0735a3dbd52606c0
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Mon Jun 12 12:19:36 2023 -0400

    IDP-2126 - Admin flow to report on config settings
    
    https://shibboleth.atlassian.net/browse/IDP-2126
---
 idp-admin-impl/pom.xml                             |   9 +
 .../idp/admin/impl/DumpConfigRequest.java          |  99 +++++++
 .../idp/admin/impl/DumpConfigRequestDecoder.java   | 159 ++++++++++++
 .../shibboleth/idp/admin/impl/OutputConfig.java    | 284 +++++++++++++++++++++
 .../shibboleth/idp/admin/impl/OutputMetrics.java   |   9 +-
 .../config/AuthenticationProfileConfiguration.java |   7 +
 .../cas/config/AbstractProtocolConfiguration.java  |   2 +
 .../idp/cas/config/LoginConfiguration.java         |   2 +
 .../idp/cas/config/ValidateConfiguration.java      |   4 +
 .../net/shibboleth/idp/conf/admin-system.xml       |  17 ++
 .../net/shibboleth/idp/conf/webflow-config.xml     |   1 +
 .../idp/flows/admin/dumpconfig-beans.xml           |  96 +++++++
 .../shibboleth/idp/flows/admin/dumpconfig-flow.xml |  65 +++++
 .../idp/module/conf/admin/admin.properties         |   8 +
 .../InterceptorAwareProfileConfiguration.java      |   3 +
 .../config/BrowserSSOProfileConfiguration.java     |  11 +-
 .../profile/config/ECPProfileConfiguration.java    |   2 +
 .../impl/SingleLogoutProfileConfiguration.java     |   3 +-
 18 files changed, 773 insertions(+), 8 deletions(-)

diff --git a/idp-admin-impl/pom.xml b/idp-admin-impl/pom.xml
index 607ce0352..8401a0d9c 100644
--- a/idp-admin-impl/pom.xml
+++ b/idp-admin-impl/pom.xml
@@ -27,6 +27,11 @@
             <artifactId>idp-admin-api</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>idp-cas-api</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>idp-core</artifactId>
@@ -48,6 +53,10 @@
             <artifactId>shib-profile-api</artifactId>
         </dependency>
 
+        <dependency>
+            <groupId>${opensaml.groupId}</groupId>
+            <artifactId>opensaml-messaging-api</artifactId>
+        </dependency>
         <dependency>
             <groupId>${opensaml.groupId}</groupId>
             <artifactId>opensaml-profile-api</artifactId>
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/DumpConfigRequest.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/DumpConfigRequest.java
new file mode 100644
index 000000000..85c1b3c2c
--- /dev/null
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/DumpConfigRequest.java
@@ -0,0 +1,99 @@
+/*
+ * 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.admin.impl;
+
+import javax.annotation.Nonnull;
+import javax.annotation.concurrent.ThreadSafe;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.StringSupport;
+
+import com.google.common.base.MoreObjects;
+
+/**
+ * Object representing a request to mock a profile request to obtain the effective configuration.
+ * 
+ * @since 5.0.0
+ */
+ at ThreadSafe
+public class DumpConfigRequest {
+
+    /** Profile identifier to simulate a response for. */
+    @Nonnull @NotEmpty private final String profileId;
+
+    /** Protocol identifier for metadata access. */
+    @Nonnull @NotEmpty private final String protocolId;
+
+    /** The ID of the requester. */
+    @Nonnull @NotEmpty private final String requesterId;
+
+    /**
+     * Constructor.
+     * 
+     * @param profile profile ID
+     * @param protocol protocol ID for metadata access
+     * @param requester ID of requester
+     */
+    public DumpConfigRequest(@Nonnull final String profile, @Nonnull final String protocol,
+            @Nonnull final String requester) {
+        
+        profileId = Constraint.isNotNull(StringSupport.trimOrNull(profile), "Profile ID cannot be null or empty");
+        protocolId = Constraint.isNotNull(StringSupport.trimOrNull(protocol), "Protocol cannot be null or empty");
+        requesterId = Constraint.isNotNull(StringSupport.trimOrNull(requester),
+                "Requester name cannot be null or empty");
+    }
+
+    /**
+     * Get the profile to simulate.
+     * 
+     * @return profile ID to simulate
+     */
+    @Nonnull @NotEmpty public String getProfileId() {
+        return profileId;
+    }
+
+    /**
+     * Get the protocol for metadata access.
+     * 
+     * @return protocol for metadata access
+     */
+    @Nonnull @NotEmpty public String getProtocolId() {
+        return protocolId;
+    }
+
+    /**
+     * Get the ID of the requesting relying party.
+     * 
+     * @return ID of the requesting relying party
+     */
+    @Nonnull @NotEmpty public String getRequesterId() {
+        return requesterId;
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    public String toString() {
+        return MoreObjects.toStringHelper(this)
+                .add("profileId", profileId)
+                .add("protocolId", protocolId)
+                .add("requesterId", requesterId)
+                .toString();
+    }
+    
+}
\ No newline at end of file
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/DumpConfigRequestDecoder.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/DumpConfigRequestDecoder.java
new file mode 100644
index 000000000..e980b17bd
--- /dev/null
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/DumpConfigRequestDecoder.java
@@ -0,0 +1,159 @@
+/*
+ * 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.admin.impl;
+
+import javax.annotation.Nonnull;
+
+import org.opensaml.messaging.context.MessageContext;
+import org.opensaml.messaging.decoder.MessageDecodingException;
+import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
+import org.opensaml.saml.common.messaging.context.SAMLPeerEntityContext;
+import org.opensaml.saml.common.messaging.context.SAMLProtocolContext;
+import org.opensaml.saml.common.xml.SAMLConstants;
+import org.opensaml.saml.saml2.metadata.SPSSODescriptor;
+
+import jakarta.servlet.http.HttpServletRequest;
+import net.shibboleth.idp.cas.config.AbstractProtocolConfiguration;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+import net.shibboleth.shared.primitive.StringSupport;
+
+/**
+ * Decodes an incoming configuration reporting message.
+ */
+public class DumpConfigRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+
+    /** Name of the query parameter carrying the profile: {@value} . */
+    @Nonnull @NotEmpty public static final String PROFILE_PARAM = "profile";
+
+    /** Name of the query parameter carrying the protocol: {@value} . */
+    @Nonnull @NotEmpty public static final String PROTOCOL_PARAM = "protocol";
+
+    /** Name of the query parameter for the SAML 1 protocol: {@value} . */
+    @Nonnull @NotEmpty public static final String SAML1_PARAM = "saml1";
+
+    /** Name of the query parameter for the SAML 2 protocol: {@value} . */
+    @Nonnull @NotEmpty public static final String SAML2_PARAM = "saml2";
+
+    /** Name of the query parameter for the CAS protocol: {@value} . */
+    @Nonnull @NotEmpty public static final String CAS_PARAM = "cas";
+
+    /** Name of the query parameter for the OIDC protocol: {@value} . */
+    @Nonnull @NotEmpty public static final String OIDC_PARAM = "oidc";
+
+    /** Name of the query parameter carrying the requester: {@value} . */
+    @Nonnull @NotEmpty public static final String REQUESTER_ID_PARAM = "requester";
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doDecode() throws MessageDecodingException {
+        final HttpServletRequest request = getHttpServletRequest();
+        if (request == null) {
+            throw new MessageDecodingException("Unable to locate HttpServletRequest");
+        }
+        
+        final String profile = getProfileId(request);
+        final DumpConfigRequest message = new DumpConfigRequest(profile, getProtocolId(request),
+                getRequesterId(request));
+        final MessageContext messageContext = new MessageContext();
+        messageContext.setMessage(message);
+        setMessageContext(messageContext);
+        
+        final SAMLPeerEntityContext peerCtx = new SAMLPeerEntityContext();
+        // TODO: allow for IdP role...
+        peerCtx.setRole(SPSSODescriptor.DEFAULT_ELEMENT_NAME);
+        peerCtx.setEntityId(message.getRequesterId());
+        messageContext.addSubcontext(peerCtx, true);
+        
+        messageContext.ensureSubcontext(SAMLProtocolContext.class).setProtocol(message.getProtocolId());
+    }
+
+    /**
+     * Get the profile ID.
+     * 
+     * @param request current HTTP request
+     * 
+     * @return the profile ID
+     * 
+     * @throws MessageDecodingException thrown if the request does not contain a profile ID
+     */
+    @Nonnull @NotEmpty protected String getProfileId(@Nonnull final HttpServletRequest request)
+            throws MessageDecodingException {
+        final String id = StringSupport.trimOrNull(request.getParameter(PROFILE_PARAM));
+        if (id == null) {
+            throw new MessageDecodingException("Request did not contain the " + PROFILE_PARAM + " query parameter.");
+        }
+        
+        if (id.startsWith("http")) {
+            return id;
+        } else if (id.startsWith("/")) {
+            return "http://shibboleth.net/ns/profiles" + id;
+        } else {
+            return "http://shibboleth.net/ns/profiles/" + id;
+        }
+    }
+
+    /**
+     * Get the ID of the requester.
+     * 
+     * @param request current HTTP request
+     * 
+     * @return the ID of the requester
+     * 
+     * @throws MessageDecodingException thrown if the request does not contain a requester name
+     */
+    @Nonnull @NotEmpty protected String getRequesterId(@Nonnull final HttpServletRequest request)
+            throws MessageDecodingException {
+        final String name = StringSupport.trimOrNull(request.getParameter(REQUESTER_ID_PARAM));
+        if (name == null) {
+            throw new MessageDecodingException("Request did not contain the " + REQUESTER_ID_PARAM
+                    + " query parameter.");
+        }
+        return name;
+    }
+
+    /**
+     * Get the protocol string used for metadata access.
+     * 
+     * @param request current HTTP request
+     * 
+     * @return the protocol
+     * 
+     * @throws MessageDecodingException if unable to determine the protocol 
+     */
+    @Nonnull @NotEmpty protected String getProtocolId(@Nonnull final HttpServletRequest request)
+            throws MessageDecodingException {
+        final String protocol = StringSupport.trimOrNull(request.getParameter(PROTOCOL_PARAM));
+        if (protocol != null) {
+            return protocol;
+        }
+        
+        if (request.getParameter(SAML1_PARAM) != null) {
+            return SAMLConstants.SAML11P_NS;
+        } else if (request.getParameter(SAML2_PARAM) != null) {
+            return SAMLConstants.SAML20P_NS;
+        } else if (request.getParameter(CAS_PARAM) != null) {
+            return AbstractProtocolConfiguration.PROTOCOL_URI;
+        } else if (request.getParameter(OIDC_PARAM) != null) {
+            return "http://openid.net/specs/openid-connect-core-1_0.html";
+        }
+        
+        throw new MessageDecodingException("Request did not contain the " + PROTOCOL_PARAM
+                + " query parameter.");
+    }
+
+}
\ No newline at end of file
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputConfig.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputConfig.java
new file mode 100644
index 000000000..13ce3455d
--- /dev/null
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputConfig.java
@@ -0,0 +1,284 @@
+/*
+ * 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.admin.impl;
+
+import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.time.Duration;
+import java.time.Instant;
+import java.util.Map;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.function.Function;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.navigate.ChildContextLookup;
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.springframework.core.annotation.AnnotationUtils;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
+
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.IdPEventIds;
+import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.profile.context.RelyingPartyContext;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
+import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.annotation.constraint.NotLive;
+import net.shibboleth.shared.annotation.constraint.NullableElements;
+import net.shibboleth.shared.annotation.constraint.Unmodifiable;
+import net.shibboleth.shared.component.IdentifiableComponent;
+import net.shibboleth.shared.logic.Constraint;
+import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.primitive.StringSupport;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+/**
+ * Action that outputs the settings from the effective {@link ProfileConfiguration} and so on.
+ * 
+ * <p>On success, a 200 HTTP status is returned. On failure, a non-successful HTTP status is returned.</p>
+ * 
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @event {@link IdPEventIds#INVALID_RELYING_PARTY_CTX}
+ * @event {@link IdPEventIds#INVALID_RELYING_PARTY_CONFIG}
+ * @event {@link IdPEventIds#INVALID_PROFILE_CONFIG}
+ * @event {@link EventIds#IO_ERROR}
+ * 
+ * @since 5.0.0
+ */
+public class OutputConfig extends AbstractProfileAction {
+    
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(OutputConfig.class);
+    
+    /** Value for Access-Control-Allow-Origin header, if any. */
+    @Nullable private String allowedOrigin;
+    
+    /** Name of JSONP callback function, if any. */
+    @Nullable private String jsonpCallbackName;
+    
+    /** Lookup strategy for {@link RelyingPartyContext}. */
+    @Nonnull private Function<ProfileRequestContext,RelyingPartyContext> relyingPartyContextLookupStrategy;
+    
+    /** Relying party context. */
+    @NonnullBeforeExec private RelyingPartyContext relyingPartyContext;
+    
+    /** Constructor. */
+    public OutputConfig() {
+        relyingPartyContextLookupStrategy = new ChildContextLookup<>(RelyingPartyContext.class);
+    }
+    
+    /**
+     * Set the value of the Access-Control-Allow-Origin CORS header, if any.
+     * 
+     * @param origin header value
+     */
+    public void setAllowedOrigin(@Nullable final String origin) {
+        checkSetterPreconditions();
+        
+        allowedOrigin = StringSupport.trimOrNull(origin);
+    }
+    
+    /**
+     * Set a JSONP callback function to wrap the result in, if any.
+     * 
+     * @param callbackName callback function name.
+     */
+    public void setJSONPCallbackName(@Nullable final String callbackName) {
+        checkSetterPreconditions();
+        
+        jsonpCallbackName = StringSupport.trimOrNull(callbackName);
+    }
+    
+    /**
+     * Set the lookup strategy to locate the {@link RelyingPartyContext}.
+     * 
+     * @param strategy lookup strategy
+     */
+    public void setRelyingPartyContextLookupStrategy(
+            @Nonnull final Function<ProfileRequestContext,RelyingPartyContext> strategy) {
+        checkSetterPreconditions();
+        
+        relyingPartyContextLookupStrategy = Constraint.isNotNull(strategy,
+                "RelyingPartyContext lookup strategy cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        }
+        
+        relyingPartyContext = relyingPartyContextLookupStrategy.apply(profileRequestContext);
+        if (relyingPartyContext == null) {
+            log.warn("{} No RelyingPartyContext available", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CTX);
+            return false;
+        } else if (relyingPartyContext.getConfiguration() == null) {
+            log.warn("{} No RelyingPartyConfiguration available", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_RELYING_PARTY_CONFIG);
+            return false;
+        } else if (relyingPartyContext.getProfileConfig() == null) {
+            log.warn("{} No ProfileConfiguration available", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, IdPEventIds.INVALID_PROFILE_CONFIG);
+            return false;
+        }
+        
+        final HttpServletResponse response = getHttpServletResponse();
+        if (response == null) {
+            log.warn("{} No HttpServletResponse available", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
+                
+        try {
+            final HttpServletResponse response = getHttpServletResponse();
+            assert response != null;
+            response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
+            response.setStatus(HttpServletResponse.SC_OK);
+            if (allowedOrigin != null) {
+                response.setHeader("Access-Control-Allow-Origin", allowedOrigin);
+            }
+            
+            final ObjectMapper mapper = new ObjectMapper();
+            
+            mapper.registerModule(new JavaTimeModule());
+            // These don't do much of anything, except the first one I think.
+            mapper.configure(SerializationFeature.WRITE_DURATIONS_AS_TIMESTAMPS, false);
+            mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
+            mapper.configure(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS, false);
+            
+            if (jsonpCallbackName != null) {
+                response.setContentType("application/javascript");
+                mapper.writer().writeValue(response.getOutputStream(), getConfig(profileRequestContext));
+            } else {
+                response.setContentType("application/json");
+                mapper.writer().writeValue(response.getOutputStream(), getConfig(profileRequestContext));
+            }
+        } catch (final IOException e) {
+            log.error("{} I/O error responding to request", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, EventIds.IO_ERROR);
+        }
+    }
+    
+    /**
+     * Extract configuration settings into a map to output.
+     * 
+     * @param profileRequestContext profile request context
+     * 
+     * @return configuration settings map
+     */
+    @Nonnull @NullableElements private Map<String,Object> getConfig(
+            @Nonnull final ProfileRequestContext profileRequestContext) {
+        
+        final Map<String,Object> settings = new HashMap<>();
+        
+        settings.put("RelyingPartyConfiguration",
+                getSettings(profileRequestContext, relyingPartyContext.ensureConfiguration()));
+
+        settings.put("ProfileConfiguration",
+                getSettings(profileRequestContext, relyingPartyContext.ensureProfileConfig()));
+
+        return settings;
+    }
+    
+    /**
+     * Interrogate a target object for configuration settings, extract them, and return in a map.
+     * 
+     * @param profileRequestContext profile request context
+     * @param target target object
+     * 
+     * @return map of settings
+     */
+// Checkstyle: CyclomaticComplexity OFF
+    @Nonnull @NullableElements @Unmodifiable @NotLive
+    private Map<String,Object> getSettings(@Nonnull final ProfileRequestContext profileRequestContext,
+            @Nonnull final Object target) {
+        final Map<String,Object> settings = new HashMap<>();
+
+        // Specially handle ID property.
+        if (target instanceof IdentifiableComponent comp) {
+            settings.put("id", comp.getId());
+        }
+        
+        final Method[] methods = target.getClass().getMethods();
+        for (final Method m : methods) {
+            assert m != null;
+            // The Spring method deals with the lack of inheritance on method-level annotations.
+            final ConfigurationSetting annotation = AnnotationUtils.findAnnotation(m, ConfigurationSetting.class);
+            if (annotation == null || annotation.name() == null || annotation.name().isEmpty()) {
+                continue;
+            }
+            final Class<?>[] paramTypes = m.getParameterTypes();
+            if (paramTypes.length == 1 && paramTypes[0].isAssignableFrom(ProfileRequestContext.class)) {
+                try {
+                    final Object ret = m.invoke(target, profileRequestContext);
+                    if (ret == null) {
+                        continue;
+                    }
+                    if (ret instanceof IdentifiableComponent comp) {
+                        settings.put(annotation.name(), comp.getId());
+                    } else if (ret instanceof Collection<?> c) {
+                        if (!c.isEmpty()) {
+                            settings.put(annotation.name(), ret);
+                        }
+                    } else if (isPrimitive(ret)) {
+                        settings.put(annotation.name(), ret);
+                    } else {
+                        settings.put(annotation.name(), ret.getClass().getName());
+                    }
+                } catch (final IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
+                    log.error("{} Error introspecting configuration setting '{}'", getLogPrefix(), annotation.name(),
+                            e);
+                }
+            }
+        }
+        
+        return settings;
+    }
+// Checkstyle: CyclomaticComplexity ON    
+
+    private boolean isPrimitive(@Nullable final Object o) {
+        return o instanceof Boolean
+                || o instanceof Integer
+                || o instanceof Long
+                || o instanceof Double
+                || o instanceof String
+                || o instanceof Duration
+                || o instanceof Instant;
+    }
+    
+}
\ No newline at end of file
diff --git a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputMetrics.java b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputMetrics.java
index e6e588a32..01a9e4bdc 100644
--- a/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputMetrics.java
+++ b/idp-admin-impl/src/main/java/net/shibboleth/idp/admin/impl/OutputMetrics.java
@@ -224,14 +224,10 @@ public class OutputMetrics extends AbstractProfileAction {
 
     /** {@inheritDoc} */
     @Override
-    protected boolean doPreExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
+    protected boolean doPreExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         
         if (!super.doPreExecute(profileRequestContext)) {
             return false;
-        } else if (getHttpServletResponse() == null) {
-            log.debug("{} No HttpServletResponse available", getLogPrefix());
-            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
-            return false;
         }
         
         final SpringRequestContext springRequestContext =
@@ -248,6 +244,7 @@ public class OutputMetrics extends AbstractProfileAction {
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
             return false;
         }
+        
         final HttpServletResponse response = getHttpServletResponse();
         if (response == null) {
             log.warn("{} No HttpServletResponse available", getLogPrefix());
@@ -270,7 +267,7 @@ public class OutputMetrics extends AbstractProfileAction {
     }
 
     /** {@inheritDoc} */
-    @Override protected void doExecute(final @Nonnull ProfileRequestContext profileRequestContext) {
+    @Override protected void doExecute(@Nonnull final ProfileRequestContext profileRequestContext) {
         
         MetricFilter filter = ALL_METRICS.equals(metricId) ? MetricFilter.ALL : metricFilterMap.get(metricId);
         if (filter == null) {
diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java
index c4c52a754..af4136a26 100644
--- a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/config/AuthenticationProfileConfiguration.java
@@ -27,6 +27,7 @@ import javax.annotation.Nullable;
 import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NonNegative;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotLive;
@@ -42,6 +43,7 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * 
      * @return  default authentication methods to use
      */
+    @ConfigurationSetting(name="defaultAuthenticationMethods")
     @Nonnull @NonnullElements @NotLive @Unmodifiable List<Principal> getDefaultAuthenticationMethods(
             @Nullable final ProfileRequestContext profileRequestContext);
         
@@ -56,6 +58,7 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * 
      * @return  a set of authentication flow IDs to allow 
      */
+    @ConfigurationSetting(name="authenticationFlows")
     @Nonnull @NonnullElements @NotLive @Unmodifiable Set<String> getAuthenticationFlows(
             @Nullable final ProfileRequestContext profileRequestContext);
 
@@ -70,6 +73,7 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * 
      * @return  a set of interceptor flow IDs to enable
      */
+    @ConfigurationSetting(name="postAuthenticationFlows")
     @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getPostAuthenticationFlows(
             @Nullable final ProfileRequestContext profileRequestContext);
 
@@ -82,6 +86,7 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * 
      * @since 4.0.0
      */
+    @ConfigurationSetting(name="forceAuthn")
     boolean isForceAuthn(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
@@ -95,6 +100,7 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
      * 
      * @since 4.0.0
      */
+    @ConfigurationSetting(name="proxyCount")
     @NonNegative @Nullable Integer getProxyCount(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
@@ -108,4 +114,5 @@ public interface AuthenticationProfileConfiguration extends ProfileConfiguration
     default boolean isLocal() {
         return false;
     }
+
 }
\ No newline at end of file
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/AbstractProtocolConfiguration.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/AbstractProtocolConfiguration.java
index 2b38ae23f..2441319eb 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/AbstractProtocolConfiguration.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/AbstractProtocolConfiguration.java
@@ -31,6 +31,7 @@ import org.opensaml.security.config.SecurityConfiguration;
 import net.shibboleth.idp.cas.ticket.TicketIdentifierGenerationStrategy;
 import net.shibboleth.idp.profile.config.AbstractInterceptorAwareProfileConfiguration;
 import net.shibboleth.profile.config.AttributeResolvingProfileConfiguration;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.component.InitializableComponent;
 import net.shibboleth.shared.logic.Constraint;
@@ -95,6 +96,7 @@ public abstract class AbstractProtocolConfiguration extends AbstractInterceptorA
      * 
      * @return ticket validity period
      */
+    @ConfigurationSetting(name="ticketValidityPeriod")
     @Nonnull public Duration getTicketValidityPeriod(@Nullable final ProfileRequestContext profileRequestContext) {
         
         final Duration ticketTTL = ticketValidityPeriodLookupStrategy.apply(profileRequestContext);
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java
index 27d9f4361..ccbbddd0a 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/LoginConfiguration.java
@@ -31,6 +31,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.idp.saml.authn.principal.AuthnContextClassRefPrincipal;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NonNegative;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
@@ -230,6 +231,7 @@ public class LoginConfiguration extends AbstractProtocolConfiguration
      * 
      * @since 4.2.0
      */
+    @ConfigurationSetting(name="storeConsentInTickets")
     public boolean isStoreConsentInTickets(@Nullable final ProfileRequestContext profileRequestContext) {
         return storeConsentInTicketsPredicate.test(profileRequestContext);
     }
diff --git a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/ValidateConfiguration.java b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/ValidateConfiguration.java
index 45c636398..b6abbedd2 100644
--- a/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/ValidateConfiguration.java
+++ b/idp-cas-api/src/main/java/net/shibboleth/idp/cas/config/ValidateConfiguration.java
@@ -28,6 +28,7 @@ import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.idp.cas.service.DefaultServiceComparator;
 import net.shibboleth.idp.cas.ticket.TicketIdentifierGenerationStrategy;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.logic.FunctionSupport;
@@ -95,6 +96,7 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * 
      * @return PGTIOU ticket ID generator
      */
+    @ConfigurationSetting(name="pGTIOUGenerator")
     @Nonnull public IdentifierGenerationStrategy getPGTIOUGenerator(
             @Nullable final ProfileRequestContext profileRequestContext) {
         
@@ -131,6 +133,7 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * 
      * @return ticket requester/validator comparator
      */
+    @ConfigurationSetting(name="serviceComparator")
     @Nonnull public Comparator<String> getServiceComparator(
             @Nullable final ProfileRequestContext profileRequestContext) {
         return Constraint.isNotNull(
@@ -167,6 +170,7 @@ public class ValidateConfiguration extends AbstractProtocolConfiguration {
      * 
      * @return attribute name
      */
+    @ConfigurationSetting(name="userAttribute")
     @Nullable public String getUserAttribute(@Nullable final ProfileRequestContext profileRequestContext) {
         return userAttributeLookupStrategy.apply(profileRequestContext);
     }
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
index e6342106b..9144a917a 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/admin-system.xml
@@ -92,6 +92,23 @@
         </property>
     </bean>
 
+    <bean parent="shibboleth.AdminFlow"
+            c:id="http://shibboleth.net/ns/profiles/dumpconfig"
+            p:loggingId="%{idp.dumpconfig.logging:DumpConfig}"
+            p:policyName="%{idp.dumpconfig.accessPolicy:AccessByIPAddress}"
+            p:nonBrowserSupported="%{idp.dumpconfig.nonBrowserSupported:false}"
+            p:authenticated="%{idp.dumpconfig.authenticated:false}"
+            p:resolveAttributes="%{idp.dumpconfig.resolveAttributes:false}">
+        <property name="postAuthenticationFlows">
+            <bean parent="shibboleth.CommaDelimStringArray"
+                c:_0="#{'%{idp.dumpconfig.postAuthenticationFlows:}'.trim()}" />
+        </property>
+        <property name="defaultAuthenticationMethodsByString">
+            <bean parent="shibboleth.CommaDelimStringArray"
+                c:_0="#{'%{idp.dumpconfig.defaultAuthenticationMethods:}'.trim()}" />
+        </property>
+    </bean>
+
     <bean parent="shibboleth.AdminFlow"
             c:id="http://shibboleth.net/ns/profiles/mdquery"
             p:loggingId="%{idp.mdquery.logging:MetadataQuery}"
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml
index a5831dcbb..118511500 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/conf/webflow-config.xml
@@ -25,6 +25,7 @@
                 <!-- Administrative and debugging flows. -->
                 <entry key="admin/hello" value="classpath:/net/shibboleth/idp/flows/admin/hello-flow.xml" />
                 <entry key="admin/resolvertest" value="classpath:/net/shibboleth/idp/flows/admin/resolvertest-flow.xml" />
+                <entry key="admin/dumpconfig" value="classpath:/net/shibboleth/idp/flows/admin/dumpconfig-flow.xml" />
                 <entry key="admin/reload-service" value="classpath:/net/shibboleth/idp/flows/admin/reload-service-flow.xml" />
                 <entry key="admin/reload-metadata" value="classpath:/net/shibboleth/idp/flows/admin/reload-metadata-flow.xml" />
                 <entry key="admin/lockout" value="classpath:/net/shibboleth/idp/flows/admin/lockout-flow.xml" />
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/dumpconfig-beans.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/dumpconfig-beans.xml
new file mode 100644
index 000000000..b9450806b
--- /dev/null
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/dumpconfig-beans.xml
@@ -0,0 +1,96 @@
+<?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">
+
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
+        p:placeholderPrefix="%{" p:placeholderSuffix="}" />
+
+    <!-- Profile ID for flow. -->
+    <bean id="shibboleth.AdminProfileId" class="java.lang.String"
+        c:_0="http://shibboleth.net/ns/profiles/dumpconfig" />
+
+    <!-- Profile counter name. -->
+    <bean id="shibboleth.metrics.ProfileCounter" class="java.lang.String" c:_0="net.shibboleth.idp.profiles.dumpconfig" />
+
+    <!-- Default operation/resource suppliers for access checks. -->
+    
+    <bean id="shibboleth.AdminOperationLookupStrategy" parent="shibboleth.Functions.Constant" c:target="read" />
+        
+    <bean id="shibboleth.AdminResourceLookupStrategy" parent="shibboleth.Functions.Constant" c:target="dumpconfig" />
+        
+    <bean id="DecodeMessage" class="org.opensaml.profile.action.impl.DecodeMessage" scope="prototype">
+        <constructor-arg>
+            <bean class="%{idp.dumpconfig.decoderClass:net.shibboleth.idp.admin.impl.DumpConfigRequestDecoder}" scope="prototype"
+                p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />    
+        </constructor-arg>
+    </bean>
+    
+    <bean id="PostDecodePopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext">
+        <property name="fieldExtractors">
+            <map>
+                <entry>
+                    <key>
+                        <util:constant static-field="net.shibboleth.idp.saml.profile.SAMLAuditFields.PROTOCOL"/>
+                    </key>
+                    <bean parent="shibboleth.Functions.Compose">
+                        <constructor-arg name="g">
+                            <bean parent="shibboleth.Functions.Compose">
+                                <constructor-arg name="g">
+                                    <bean class="org.opensaml.saml.common.messaging.context.navigate.SAMLProtocolContextProtocolFunction" />
+                                </constructor-arg>
+                                <constructor-arg name="f">
+                                    <ref bean="shibboleth.ChildLookup.SAMLProtocolContext" />
+                                </constructor-arg>
+                            </bean>
+                        </constructor-arg>
+                        <constructor-arg name="f">
+                            <ref bean="shibboleth.MessageContextLookup.Inbound" />
+                        </constructor-arg>
+                    </bean>
+                </entry>
+            </map>
+        </property>
+    </bean>
+    
+    <bean id="SAMLMetadataLookup"
+            class="net.shibboleth.idp.profile.impl.WebFlowMessageHandlerAdaptor" scope="prototype"
+            c:executionDirection="INBOUND">
+        <constructor-arg name="messageHandler">
+            <bean class="org.opensaml.saml.common.binding.impl.SAMLMetadataLookupHandler" scope="prototype">
+                <property name="roleDescriptorResolver">
+                    <bean class="org.opensaml.saml.metadata.resolver.impl.PredicateRoleDescriptorResolver"
+                        c:mdResolver-ref="shibboleth.MetadataResolver" />
+                </property>
+            </bean>
+        </constructor-arg>
+    </bean>
+    
+    <bean id="InitializeRelyingPartyContexFromSAMLPeer"
+        class="net.shibboleth.idp.saml.profile.impl.InitializeRelyingPartyContextFromSAMLPeer" scope="prototype" />
+
+    <bean id="SelectRelyingPartyConfiguration"
+        class="net.shibboleth.idp.profile.impl.SelectRelyingPartyConfiguration" scope="prototype"
+        p:relyingPartyConfigurationResolver-ref="shibboleth.RelyingPartyResolverService" />
+    
+    <bean id="SelectProfileConfiguration"
+        class="net.shibboleth.idp.profile.impl.SelectProfileConfiguration" scope="prototype" />
+    
+    <bean id="PostLookupPopulateAuditContext" parent="shibboleth.AbstractPopulateAuditContext"
+        p:fieldExtractors="#{getObject('shibboleth.PostLookupAuditExtractors') ?: getObject('shibboleth.DefaultPostLookupAuditExtractors')}" />
+        
+    <bean id="OutputConfig" class="net.shibboleth.idp.admin.impl.OutputConfig" scope="prototype"
+        p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
+
+    <bean id="RecordResponseComplete" class="net.shibboleth.idp.profile.impl.RecordResponseComplete" scope="prototype" />
+
+</beans>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/dumpconfig-flow.xml b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/dumpconfig-flow.xml
new file mode 100644
index 000000000..386656705
--- /dev/null
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/flows/admin/dumpconfig-flow.xml
@@ -0,0 +1,65 @@
+<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">
+    
+    <!-- Start action. -->
+
+    <action-state id="InitializeProfileRequestContext">
+        <evaluate expression="InitializeProfileRequestContext" />
+        <evaluate expression="FlowStartPopulateAuditContext" />
+        <evaluate expression="'proceed'" />
+        
+        <transition on="proceed" to="DecodeMessage" />
+    </action-state>
+
+    <action-state id="DecodeMessage">
+        <evaluate expression="DecodeMessage" />
+        <evaluate expression="PostDecodePopulateAuditContext" />
+        <evaluate expression="'proceed'" />
+        
+        <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="ContinueDecoding" />
+    </action-state>
+    
+    <action-state id="ContinueDecoding">
+        <on-entry>
+            <!-- Clear any user authentication/attribute state. -->
+            <evaluate expression="opensamlProfileRequestContext.clearSubcontexts()" />
+            <evaluate expression="opensamlProfileRequestContext.setProfileId(opensamlProfileRequestContext.ensureInboundMessageContext().ensureMessage().getProfileId())" />
+        </on-entry>
+        
+        <evaluate expression="SAMLMetadataLookup" />
+
+        <evaluate expression="InitializeRelyingPartyContexFromSAMLPeer" />
+        <evaluate expression="SelectRelyingPartyConfiguration" />
+        <evaluate expression="SelectProfileConfiguration" />
+
+        <evaluate expression="PostLookupPopulateAuditContext" />
+
+        <evaluate expression="OutputConfig" />
+        <evaluate expression="RecordResponseComplete" />
+        <evaluate expression="'proceed'" />
+        
+        <transition on="proceed" to="end" />
+    </action-state>
+    
+    <!-- Successful terminal state (success meaning outbound message encoded). -->
+
+    <end-state id="end">
+        <on-entry>
+            <evaluate expression="WriteAuditLog" />
+        </on-entry>
+    </end-state>
+
+    <bean-import resource="dumpconfig-beans.xml" />
+
+</flow>
diff --git a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/admin.properties b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/admin.properties
index 344cb7902..8713a8178 100644
--- a/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/admin.properties
+++ b/idp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/admin/admin.properties
@@ -24,6 +24,14 @@
 #idp.resolvertest.resolveAttributes = false
 #idp.resolvertest.postAuthenticationFlows =
 
+#idp.dumpconfig.logging = DumpConfig
+#idp.dumpconfig.accessPolicy = AccessByIPAddress
+#idp.dumpconfig.authenticated = false
+#idp.dumpconfig.nonBrowserSupported = false
+#idp.dumpconfig.defaultAuthenticationMethods =
+#idp.dumpconfig.resolveAttributes = false
+#idp.dumpconfig.postAuthenticationFlows =
+
 #idp.mdquery.logging = MetadataQuery
 #idp.mdquery.accessPolicy = AccessByIPAddress
 #idp.mdquery.authenticated = false
diff --git a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/InterceptorAwareProfileConfiguration.java b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/InterceptorAwareProfileConfiguration.java
index b484d1cfb..4a2b8b51b 100644
--- a/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/InterceptorAwareProfileConfiguration.java
+++ b/idp-profile-api/src/main/java/net/shibboleth/idp/profile/config/InterceptorAwareProfileConfiguration.java
@@ -25,6 +25,7 @@ import javax.annotation.Nullable;
 import org.opensaml.profile.context.ProfileRequestContext;
 
 import net.shibboleth.profile.config.ProfileConfiguration;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
@@ -48,6 +49,7 @@ public interface InterceptorAwareProfileConfiguration extends ProfileConfigurati
      * 
      * @return  a set of interceptor flow IDs to enable
      */
+    @ConfigurationSetting(name="inboundInterceptorFlows")
     @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getInboundInterceptorFlows(
             @Nullable final ProfileRequestContext profileRequestContext);
 
@@ -63,6 +65,7 @@ public interface InterceptorAwareProfileConfiguration extends ProfileConfigurati
      * 
      * @return  a set of interceptor flow IDs to enable
      */
+    @ConfigurationSetting(name="outboundInterceptorFlows")
     @Nonnull @NonnullElements @NotLive @Unmodifiable List<String> getOutboundInterceptorFlows(
             @Nullable final ProfileRequestContext profileRequestContext);
     
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
index 79ec12275..b643840af 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/BrowserSSOProfileConfiguration.java
@@ -28,6 +28,7 @@ import javax.annotation.Nullable;
 
 import net.shibboleth.idp.authn.config.AuthenticationProfileConfiguration;
 import net.shibboleth.profile.config.AttributeResolvingProfileConfiguration;
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NonNegative;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotLive;
@@ -60,6 +61,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.0.0
      */
+    @ConfigurationSetting(name="ignoreScoping")
     boolean isIgnoreScoping(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
@@ -71,6 +73,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.0.0
      */
+    @ConfigurationSetting(name="skipEndpointValidationWhenSigned")
     boolean isSkipEndpointValidationWhenSigned(@Nullable final ProfileRequestContext profileRequestContext);
 
     /**
@@ -80,6 +83,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @return audiences for a proxied assertion
      */
+    @ConfigurationSetting(name="proxyAudiences")
     @Nonnull @NonnullElements @NotLive @Unmodifiable Set<String> getProxyAudiences(
             @Nullable final ProfileRequestContext profileRequestContext);
     
@@ -94,6 +98,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.2.0
      */
+    @ConfigurationSetting(name="suppressAuthenticatingAuthority")
     boolean isSuppressAuthenticatingAuthority(@Nullable final ProfileRequestContext profileRequestContext);
         
     /**
@@ -108,6 +113,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.0.0
      */
+    @ConfigurationSetting(name="proxiedAuthnInstant")
     boolean isProxiedAuthnInstant(@Nullable final ProfileRequestContext profileRequestContext);
 
     /**
@@ -119,6 +125,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.3.0
      */
+    @ConfigurationSetting(name="requireSignedRequests")
     boolean isRequireSignedRequests(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
@@ -129,6 +136,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @return max lifetime of service provider should maintain a session
      */
+    @ConfigurationSetting(name="maximumSPSessionLifetime")
     @Nullable Duration getMaximumSPSessionLifetime(@Nullable final ProfileRequestContext profileRequestContext);
     
     /**
@@ -154,7 +162,6 @@ public interface BrowserSSOProfileConfiguration
      */
     @Deprecated(since="5.0.0", forRemoval=true)
     @NonNegative long getMaximumTokenDelegationChainLength(@Nullable final ProfileRequestContext profileRequestContext);
-
     
     /**
      * Get the function to use to translate an inbound proxied SAML 2.0 {@link AuthnContext} into the appropriate
@@ -166,6 +173,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.0.0
      */
+    @ConfigurationSetting(name="authnContextTranslationStrategy")
     @Nullable Function<AuthnContext,Collection<Principal>> getAuthnContextTranslationStrategy(
             @Nullable final ProfileRequestContext profileRequestContext);
 
@@ -182,6 +190,7 @@ public interface BrowserSSOProfileConfiguration
      * 
      * @since 4.1.0
      */
+    @ConfigurationSetting(name="authnContextTranslationStrategyEx")
     @Nullable Function<ProfileRequestContext,Collection<Principal>> getAuthnContextTranslationStrategyEx(
             @Nullable final ProfileRequestContext profileRequestContext);
 
diff --git a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/ECPProfileConfiguration.java b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/ECPProfileConfiguration.java
index b8f9bf6e0..283f04997 100644
--- a/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/ECPProfileConfiguration.java
+++ b/idp-saml-api/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/ECPProfileConfiguration.java
@@ -24,6 +24,7 @@ import javax.annotation.Nullable;
 
 import org.opensaml.profile.context.ProfileRequestContext;
 
+import net.shibboleth.shared.annotation.ConfigurationSetting;
 import net.shibboleth.shared.annotation.constraint.NonnullElements;
 import net.shibboleth.shared.annotation.constraint.NotLive;
 import net.shibboleth.shared.annotation.constraint.Unmodifiable;
@@ -41,6 +42,7 @@ public interface ECPProfileConfiguration extends BrowserSSOProfileConfiguration,
      * 
      * @since 3.3.0
      */
+    @ConfigurationSetting(name="localEvents")
     @Nonnull @NonnullElements @NotLive @Unmodifiable
     Set<String> getLocalEvents(@Nullable final ProfileRequestContext profileRequestContext);
     
diff --git a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/SingleLogoutProfileConfiguration.java b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/SingleLogoutProfileConfiguration.java
index 526c26a61..8418999e6 100644
--- a/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/SingleLogoutProfileConfiguration.java
+++ b/idp-saml-impl/src/main/java/net/shibboleth/idp/saml/saml2/profile/config/impl/SingleLogoutProfileConfiguration.java
@@ -72,7 +72,8 @@ public class SingleLogoutProfileConfiguration extends AbstractSAML2ArtifactAware
         setEncryptNameIDsPredicate(new NoConfidentialityMessageChannelPredicate());
 
         signSOAPRequestsPredicate = new org.opensaml.messaging.logic.NoIntegrityMessageChannelPredicate();
-        final Predicate<MessageContext> cltsrp = new org.opensaml.messaging.logic.NoIntegrityMessageChannelPredicate().negate();
+        final Predicate<MessageContext> cltsrp =
+                new org.opensaml.messaging.logic.NoIntegrityMessageChannelPredicate().negate();
         assert cltsrp!=null;
         clientTLSSOAPRequestsPredicate = cltsrp;
         

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


More information about the commits mailing list