[java-plugin-shibd] branch main updated: JSHIBD-15 - Implement agent/application IDs as MDC fields

Codeberg noreply at shibboleth.net
Tue Jan 27 21:44:18 UTC 2026


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

codeberg pushed a commit to branch main
in repository java-plugin-shibd.

View the commit online:
https://codeberg.org/Shibboleth/java-plugin-shibd/commit/f53b38d9b9485bfd33b5be8e993ca8fa1a26bdd1

The following commit(s) were added to refs/heads/main by this push:
     new f53b38d  JSHIBD-15 - Implement agent/application IDs as MDC fields
f53b38d is described below

commit f53b38d9b9485bfd33b5be8e993ca8fa1a26bdd1
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Tue Jan 27 16:43:31 2026 -0500

    JSHIBD-15 - Implement agent/application IDs as MDC fields
    
    https://shibboleth.atlassian.net/browse/JSHIBD-15
---
 .../idp/flows/sp/abstract/sp-abstract-beans.xml    |   6 +-
 .../net/shibboleth/idp/module/conf/logback.xml     | 225 +++++++++++++++++++++
 .../shibboleth/sp/flows/AbstractSPFlowTest.java    |   9 +-
 .../sp/flows/SessionInitiatorFlowTest.java         |   5 +-
 .../shibboleth/sp/flows/TokenConsumerFlowText.java |   6 +-
 .../sp/profile/AbstractAgentRequestAction.java     |  33 ---
 .../net/shibboleth/sp/profile/SPConstants.java     |   6 +
 .../authn/impl/InitializeAgentRequestContext.java  |  29 ++-
 .../sp/profile/impl/DecodeAgentRequest.java        |  41 ++++
 .../sp/profile/impl/ResolveApplication.java        |  19 +-
 10 files changed, 327 insertions(+), 52 deletions(-)

diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
index 6b83890..fd4d969 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-beans.xml
@@ -30,7 +30,8 @@
         
     <bean id="InitializeAgentRequestContext"
         class="net.shibboleth.sp.authn.impl.InitializeAgentRequestContext" scope="prototype"
-        p:agentResolver-ref="shibboleth.sp.AgentResolver" />
+        p:agentResolver-ref="shibboleth.sp.AgentResolver"
+        p:populateMDC="%{idp.logging.MDC.enabled:true}" />
         
     <bean id="ValidateAgentAddress"
         class="net.shibboleth.sp.authn.impl.ValidateAgentAddress" scope="prototype"
@@ -52,7 +53,8 @@
         class="net.shibboleth.idp.authn.impl.ValidateCredentials.UsernamePasswordCleanupHook" />
 
     <bean id="DecodeAgentRequest" class="net.shibboleth.sp.profile.impl.DecodeAgentRequest" scope="prototype"
-        p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier" />
+        p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
+        p:populateMDC="%{idp.logging.MDC.enabled:true}" />
         
     <bean id="EncodeAgentResponse" class="net.shibboleth.sp.profile.impl.EncodeAgentResponse" scope="prototype"
         p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
diff --git a/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/logback.xml b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/logback.xml
new file mode 100644
index 0000000..82c212c
--- /dev/null
+++ b/sp-conf-impl/src/main/resources/net/shibboleth/idp/module/conf/logback.xml
@@ -0,0 +1,225 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+
+    <!--
+    Variables for simplifying logging configuration.
+    http://logback.qos.ch/manual/configuration.html#variableSubstitution
+    -->
+
+    <!--
+    If you want to use custom properties in this config file,
+    we load the main property file for you.
+    -->
+    <variable file="${idp.home}/conf/idp.properties" />
+
+    <!-- Location and retention. -->
+    
+    <variable name="idp.logfiles" value="${idp.logfiles:-${idp.home}/logs}" />
+    <variable name="idp.loghistory" value="${idp.loghistory:-180}" />
+    
+    <!-- Much higher performance if you operate on DEBUG. -->
+    <!-- <variable name="idp.process.appender" value="ASYNC_PROCESS" /> -->
+    
+    <!-- Logging level shortcuts. -->
+    <variable name="idp.loglevel.idp" value="${idp.loglevel.idp:-INFO}" />
+    <variable name="idp.loglevel.ldap" value="${idp.loglevel.ldap:-WARN}" />
+    <variable name="idp.loglevel.messages" value="${idp.loglevel.messages:-INFO}" />
+    <variable name="idp.loglevel.encryption" value="${idp.loglevel.encryption:-INFO}" />
+    <variable name="idp.loglevel.opensaml" value="${idp.loglevel.opensaml:-INFO}" />
+    <variable name="idp.loglevel.shared" value="${idp.loglevel.shared:-INFO}" />
+    <variable name="idp.loglevel.props" value="${idp.loglevel.props:-INFO}" />
+    <variable name="idp.loglevel.httpclient" value="${idp.loglevel.httpclient:-INFO}" />
+    
+    <variable name="idp.loglevel.sp" value="${idp.loglevel.sp:-DEBUG}" />
+    
+    <!-- Don't turn these up unless you want a *lot* of noise. -->
+    <variable name="idp.loglevel.spring" value="${idp.loglevel.spring:-WARN}" />
+    <variable name="idp.loglevel.container" value="${idp.loglevel.container:-ERROR}" />
+    <variable name="idp.loglevel.xmlsec" value="${idp.loglevel.xmlsec:-INFO}" />
+
+    <!-- =========================================================== -->
+    <!-- ============== Logging Categories and Levels ============== -->
+    <!-- =========================================================== -->
+
+    <!-- Logs IdP, but not OpenSAML, messages -->
+    <logger name="net.shibboleth.idp" level="${idp.loglevel.idp}"/>
+
+    <!-- Logs OpenSAML, but not IdP, messages -->
+    <logger name="org.opensaml.saml" level="${idp.loglevel.opensaml}"/>
+
+    <!-- Logs supporting code. -->
+    <logger name="net.shibboleth.shared" level="${idp.loglevel.shared}"/>
+    
+    <!-- Logs LDAP related messages -->
+    <logger name="org.ldaptive" level="${idp.loglevel.ldap}"/>
+
+    <!-- Logs embedded HTTP client messages -->
+    <logger name="org.apache.hc" level="${idp.loglevel.httpclient}"/>
+
+    <!-- Logs SP, but not OpenSAML, messages -->
+    <logger name="net.shibboleth.sp" level="${idp.loglevel.sp}"/>
+    
+    <!-- Logs inbound and outbound protocols messages at DEBUG level -->
+    <logger name="PROTOCOL_MESSAGE" level="${idp.loglevel.messages}" />
+
+    <!-- Logs unencrypted SAML at DEBUG level -->
+    <logger name="org.opensaml.saml.saml2.encryption.Encrypter" level="${idp.loglevel.encryption}" />
+    <logger name="org.opensaml.saml.saml2.encryption.Decrypter" level="${idp.loglevel.encryption}" />
+
+    <!-- Logs system properties during startup at DEBUG level -->
+    <logger name="net.shibboleth.idp.admin.impl.LogImplementationDetails" level="${idp.loglevel.props}" />
+
+    <!-- Especially chatty. -->
+    <logger name="org.apache.xml.security" level="${idp.loglevel.xmlsec}" />
+    <logger name="org.springframework" level="${idp.loglevel.spring}"/>
+    <logger name="org.apache.catalina" level="${idp.loglevel.container}"/>
+    <logger name="org.eclipse.jetty" level="${idp.loglevel.container}"/>
+
+
+    <!-- =========================================================== -->
+    <!-- ============== Low Level Details or Changes =============== -->
+    <!-- =========================================================== -->
+    
+    <!-- Process log. -->
+    <appender name="IDP_PROCESS" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <File>${idp.logfiles}/idp-process.log</File>
+        
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${idp.logfiles}/idp-process-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
+            <maxHistory>${idp.loghistory}</maxHistory>
+        </rollingPolicy>
+
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>UTF-8</charset>
+            <Pattern>%date{ISO8601} - %mdc{idp.remote_addr} - TX:%mdc{sp.txid:-null} [%mdc{sp.agent_id}] [%mdc{sp.application_id}] - %level [%logger:%line] - %msg%n%ex{short}</Pattern>
+        </encoder>
+
+        <!-- Ignore Velocity status page error. -->
+        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+            <evaluator>
+                <matcher>
+                    <Name>VelocityStatusMatcher</Name>
+                    <regex>ResourceManager\s*: unable to find resource 'status\.vm' in any resource loader\.</regex>
+                </matcher>
+                <expression>VelocityStatusMatcher.matches(formattedMessage)</expression>
+            </evaluator>
+            <OnMatch>DENY</OnMatch>
+        </filter>
+    </appender>
+
+    <appender name="ASYNC_PROCESS" class="ch.qos.logback.classic.AsyncAppender">
+        <appender-ref ref="IDP_PROCESS" />
+        <discardingThreshold>0</discardingThreshold>
+    </appender>
+
+    <appender name="IDP_WARN" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <!-- Suppress anything below WARN. -->
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>WARN</level>
+        </filter>
+        
+        <File>${idp.logfiles}/idp-warn.log</File>
+        
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${idp.logfiles}/idp-warn-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
+            <maxHistory>${idp.loghistory}</maxHistory>
+        </rollingPolicy>
+        
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>UTF-8</charset>
+            <Pattern>%date{ISO8601} - %mdc{idp.remote_addr} - TX:%mdc{sp.txid:-null} [%mdc{sp.agent_id}] [%mdc{sp.application_id}] - %level [%logger:%line] - %msg%n%ex{full}</Pattern>
+        </encoder>
+        
+        <!-- Ignore Velocity status page error. -->
+        <filter class="ch.qos.logback.core.filter.EvaluatorFilter">
+            <evaluator>
+                <matcher>
+                    <Name>VelocityStatusMatcher</Name>
+                    <regex>ResourceManager\s*: unable to find resource 'status\.vm' in any resource loader\.</regex>
+                </matcher>
+                <expression>VelocityStatusMatcher.matches(formattedMessage)</expression>
+            </evaluator>
+            <OnMatch>DENY</OnMatch>
+        </filter>
+    </appender>
+    
+    <!-- Audit log. -->
+    <appender name="IDP_AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <File>${idp.logfiles}/idp-audit.log</File>
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${idp.logfiles}/idp-audit-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
+            <maxHistory>${idp.loghistory}</maxHistory>
+        </rollingPolicy>
+
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>UTF-8</charset>
+            <Pattern>%msg%n</Pattern>
+        </encoder>
+    </appender>
+    
+    <!-- Consent audit log. -->
+    <appender name="IDP_CONSENT_AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <File>${idp.logfiles}/idp-consent-audit.log</File>
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${idp.logfiles}/idp-consent-audit-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
+            <maxHistory>${idp.loghistory}</maxHistory>
+        </rollingPolicy>
+
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>UTF-8</charset>
+            <Pattern>%msg%n</Pattern>
+        </encoder>
+    </appender>
+
+    <!-- F-TICKS syslog destination. -->
+    <appender name="IDP_FTICKS" class="ch.qos.logback.classic.net.SyslogAppender">
+        <syslogHost>${idp.fticks.loghost:-localhost}</syslogHost>
+        <port>${idp.fticks.logport:-514}</port>
+        <facility>AUTH</facility>
+        <suffixPattern>[%thread] %logger %msg</suffixPattern>
+    </appender>
+
+    <!-- Top level loggers. -->
+
+    <logger name="Shibboleth-Audit" level="ALL">
+        <appender-ref ref="${idp.audit.appender:-IDP_AUDIT}"/>
+    </logger>
+
+    <logger name="Shibboleth-FTICKS" level="ALL" additivity="false">
+        <appender-ref ref="${idp.fticks.appender:-IDP_FTICKS}"/>
+    </logger>
+
+    <logger name="Shibboleth-Consent-Audit" level="ALL">
+        <appender-ref ref="${idp.consent.appender:-IDP_CONSENT_AUDIT}"/>
+    </logger>
+    
+    <root level="${idp.loglevel.root:-INFO}">
+        <appender-ref ref="${idp.process.appender:-IDP_PROCESS}"/>
+        <appender-ref ref="${idp.warn.appender:-IDP_WARN}" />
+    </root>
+
+    <!-- Example routing Password flow auditing to separate location (extend to other flows as needed). -->
+    
+    <!--
+    <appender name="IDP_PASSWORD_AUDIT" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <File>${idp.logfiles}/idp-password-audit.log</File>
+
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <fileNamePattern>${idp.logfiles}/idp-password-audit-%d{yyyy-MM-dd}.log.gz</fileNamePattern>
+            <maxHistory>${idp.loghistory}</maxHistory>
+        </rollingPolicy>
+
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <charset>UTF-8</charset>
+            <Pattern>%msg%n</Pattern>
+        </encoder>
+    </appender>
+    
+    <logger name="Shibboleth-Audit.Password" level="ALL" additivity="false">
+        <appender-ref ref="IDP_PASSWORD_AUDIT"/>
+    </logger>
+    -->
+    
+</configuration>
diff --git a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/AbstractSPFlowTest.java b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/AbstractSPFlowTest.java
index 214d5d5..ada2399 100644
--- a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/AbstractSPFlowTest.java
+++ b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/AbstractSPFlowTest.java
@@ -38,9 +38,11 @@ import org.testng.annotations.BeforeMethod;
 import net.shibboleth.idp.spring.IdPPropertiesApplicationContextInitializer;
 import net.shibboleth.idp.test.PreferFileSystemApplicationContextInitializer;
 import net.shibboleth.idp.test.flows.AbstractFlowTest;
+import net.shibboleth.shared.security.IdentifierGenerationStrategy;
 import net.shibboleth.shared.servlet.impl.HttpServletRequestResponseContext;
 import net.shibboleth.shared.xml.ParserPool;
 import net.shibboleth.sp.ddf.DDF;
+import net.shibboleth.sp.profile.SPConstants;
 import net.shibboleth.sp.profile.impl.ResolveApplication;
 
 /**
@@ -78,6 +80,10 @@ public abstract class AbstractSPFlowTest extends AbstractFlowTest {
     @Autowired
     @Qualifier("shibboleth.ParserPool")
     protected ParserPool parserPool;
+
+    @Autowired
+    @Qualifier("shibboleth.DefaultIdentifierGenerationStrategy")
+    protected IdentifierGenerationStrategy idGenerator;
     
     protected AbstractSPFlowTest(final String id) {
         this(id, END_STATE_ID);
@@ -155,7 +161,8 @@ public abstract class AbstractSPFlowTest extends AbstractFlowTest {
         if (input == null || !input.isstruct()) {
             input = new DDF(null).structure();
         }
-        input.addmember(ResolveApplication.APPLICATION_ID).string(applicationId);
+        input.addmember(SPConstants.APPLICATION).string(applicationId);
+        input.addmember(SPConstants.TXID).string(idGenerator.generateIdentifier(false));
         setRequest("POST", input);
     }
 
diff --git a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java
index 1dc5512..98721f8 100644
--- a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java
+++ b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/SessionInitiatorFlowTest.java
@@ -26,7 +26,6 @@ import org.testng.annotations.Test;
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.profile.SPConstants;
-import net.shibboleth.sp.profile.impl.ResolveApplication;
 
 /**
  * Unit test for the SP session-initiator flow (basics only).
@@ -63,7 +62,7 @@ public class SessionInitiatorFlowTest extends AbstractSPFlowTest {
         setDefaultAuth();
 
         final DDF input = new DDF(null).structure();
-        input.addmember(ResolveApplication.APPLICATION_ID).string("foo");
+        input.addmember(SPConstants.APPLICATION).string("foo");
         setRequest("POST", input);
         
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -81,7 +80,7 @@ public class SessionInitiatorFlowTest extends AbstractSPFlowTest {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
-        input.addmember(ResolveApplication.APPLICATION_ID).string(APPLICATION_ID);
+        input.addmember(SPConstants.APPLICATION).string(APPLICATION_ID);
         input.addmember(SPConstants.TARGET).unsafe_string("https://sp.example.org".getBytes(StandardCharsets.UTF_8));
         setRequest("POST", input);
 
diff --git a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/TokenConsumerFlowText.java b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/TokenConsumerFlowText.java
index d387d6c..2cb797d 100644
--- a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/TokenConsumerFlowText.java
+++ b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/TokenConsumerFlowText.java
@@ -24,7 +24,7 @@ import org.testng.annotations.Test;
 
 import net.shibboleth.idp.authn.AuthnEventIds;
 import net.shibboleth.sp.ddf.DDF;
-import net.shibboleth.sp.profile.impl.ResolveApplication;
+import net.shibboleth.sp.profile.SPConstants;
 
 /**
  * Unit test for the SP token-consumer flow (basics only).
@@ -63,7 +63,7 @@ public class TokenConsumerFlowText extends AbstractSPFlowTest {
         setDefaultAuth();
 
         final DDF input = new DDF(null).structure();
-        input.addmember(ResolveApplication.APPLICATION_ID).string("foo");
+        input.addmember(SPConstants.APPLICATION).string("foo");
         setRequest("POST", input);
         
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
@@ -82,7 +82,7 @@ public class TokenConsumerFlowText extends AbstractSPFlowTest {
         setDefaultAuth();
         
         final DDF input = new DDF(null).structure();
-        input.addmember(ResolveApplication.APPLICATION_ID).string(APPLICATION_ID);
+        input.addmember(SPConstants.APPLICATION).string(APPLICATION_ID);
         setRequest("POST", input);
 
         final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentRequestAction.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentRequestAction.java
index 9218f2f..d12c6f9 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentRequestAction.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/AbstractAgentRequestAction.java
@@ -29,8 +29,6 @@ import net.shibboleth.idp.profile.AbstractProfileAction;
 import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
-import net.shibboleth.sp.Agent;
-import net.shibboleth.sp.Application;
 import net.shibboleth.sp.context.AgentRequestContext;
 
 /**
@@ -47,9 +45,6 @@ public abstract class AbstractAgentRequestAction extends AbstractProfileAction {
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(AbstractAgentRequestAction.class);
     
-    /** Local copy of extended log prefix. */
-    @Nullable private String logPrefix;
-    
     /** Lookup strategy for {@link AgentRequestContext}. */
     @Nonnull private Function<ProfileRequestContext,AgentRequestContext> agentRequestContextLookupStrategy;
 
@@ -109,33 +104,5 @@ public abstract class AbstractAgentRequestAction extends AbstractProfileAction {
         
         return true;
     }
-
-    /** {@inheritDoc} */
-    @Override
-    @Nonnull protected String getLogPrefix() {
-        
-        if (logPrefix != null) {
-            return logPrefix;
-        }
-
-        final StringBuilder s = new StringBuilder();
-        final AgentRequestContext ctx = getAgentRequestContext();
-        if (ctx != null) {
-            final Agent agent = ctx.getAgent();
-            if (agent != null) {
-                s.append("Agent ").append(agent.getId()).append(" - ");
-            }
-            final Application app = ctx.getApplication();
-            if (app != null) {
-                s.append(" Application ").append(app.getApplicationId()).append(" - ");
-            }
-        }
-        
-        s.append(super.getLogPrefix());
-        logPrefix = s.toString();
-        
-        assert logPrefix != null;
-        return logPrefix;
-    }
     
 }
\ No newline at end of file
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPConstants.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPConstants.java
index 223713e..30b7ccf 100644
--- a/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPConstants.java
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPConstants.java
@@ -23,6 +23,9 @@ import net.shibboleth.shared.annotation.constraint.NotEmpty;
  */
 public final class SPConstants {
 
+    /** Application parameter. */
+    @Nonnull @NotEmpty public static final String APPLICATION = "application";
+    
     /** Target parameter. */
     @Nonnull @NotEmpty public static final String TARGET = "target";
 
@@ -32,6 +35,9 @@ public final class SPConstants {
     /** Event parameter. */
     @Nonnull @NotEmpty public static final String EVENT = "event";
 
+    /** Transaction ID parameter. */
+    @Nonnull @NotEmpty public static final String TXID = "txid";
+    
     /** Private constructor. */
     private SPConstants() {
         
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContext.java b/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContext.java
index 76fc6ee..43df3dd 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContext.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/authn/impl/InitializeAgentRequestContext.java
@@ -23,6 +23,7 @@ import org.opensaml.profile.action.ActionSupport;
 import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
+import org.slf4j.MDC;
 
 import net.shibboleth.idp.authn.AbstractAuthenticationAction;
 import net.shibboleth.idp.authn.AuthnEventIds;
@@ -30,6 +31,7 @@ import net.shibboleth.idp.authn.context.AuthenticationContext;
 import net.shibboleth.idp.authn.context.UsernamePasswordContext;
 import net.shibboleth.shared.annotation.constraint.NonnullAfterInit;
 import net.shibboleth.shared.annotation.constraint.NonnullBeforeExec;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
@@ -53,9 +55,13 @@ import net.shibboleth.sp.context.AgentRequestContext;
  * @event {@link AuthnEventIds#UNKNOWN_USERNAME}
  * @pre <pre>ProfileRequestContext.getSubcontext(AuthenticationContext.class) != null</pre>
  * @post <pre>ProfileRequestContext.ensureSubcontext(AgentRequestContext.class).getAgent() != null</pre>
+ * @post <pre>An MDC logging attribute is created with the successfully resolved ID.</pre>
  */
 public class InitializeAgentRequestContext extends AbstractAuthenticationAction {
 
+    /** MDC attribute name for agent ID. */
+    @Nonnull @NotEmpty public static final String AGENT_ID_MDC_ATTRIBUTE = "sp.agent_id";
+    
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(InitializeAgentRequestContext.class);
     
@@ -66,7 +72,10 @@ public class InitializeAgentRequestContext extends AbstractAuthenticationAction
     @Nonnull private Function<ProfileRequestContext,AgentRequestContext> agentRequestContextCreationStrategy;
     
     /** The agent resolver. */
-    @NonnullAfterInit ReloadableService<AgentResolver> agentResolver;
+    @NonnullAfterInit private ReloadableService<AgentResolver> agentResolver;
+    
+    /** Whether to populate the MDC. */
+    private boolean populateMDC;
     
     /** Cached agent credential ID from "username". */
     @NonnullBeforeExec private String agentCredentialID;
@@ -77,6 +86,7 @@ public class InitializeAgentRequestContext extends AbstractAuthenticationAction
         usernamePasswordContextLookupStrategy = new ChildContextLookup<>(UsernamePasswordContext.class).compose(
                 new ChildContextLookup<>(AuthenticationContext.class));
         agentRequestContextCreationStrategy = new ChildContextLookup<>(AgentRequestContext.class, true);
+        populateMDC = true;
     }
     
     /**
@@ -116,6 +126,19 @@ public class InitializeAgentRequestContext extends AbstractAuthenticationAction
         agentResolver = Constraint.isNotNull(service, "AgentResolver service cannot be null");
     }
     
+    /**
+     * Sets whether to populate the agent ID into the logging MDC.
+     * 
+     * <p>Defaults to true.</p>
+     * 
+     * @param flag flag to set
+     */
+    public void setPopulateMDC(final boolean flag) {
+        checkSetterPreconditions();
+        
+        populateMDC = flag;
+    }
+    
     /** {@inheritDoc} */
     @Override
     protected void doInitialize() throws ComponentInitializationException {
@@ -172,6 +195,10 @@ public class InitializeAgentRequestContext extends AbstractAuthenticationAction
             }
             
             agentRequestContext.setAgent(agent);
+            if (populateMDC) {
+                MDC.put(AGENT_ID_MDC_ATTRIBUTE, agent.getId());
+            }
+            log.debug("{} Resolved requesting agent '{}'", getLogPrefix(), agent.getId());
             
         } catch (final ServiceException e) {
             log.error("{} Unable to obtain AgentResolver component", getLogPrefix(), e);
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java
index 82e6a76..85bdf76 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/DecodeAgentRequest.java
@@ -19,17 +19,23 @@ import java.io.InputStream;
 
 import javax.annotation.Nonnull;
 
+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.slf4j.MDC;
 
 import jakarta.servlet.http.HttpServletRequest;
+import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.UsernamePasswordContext;
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.context.AgentRequestContext;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.messaging.RemotedHttpServletRequest;
 import net.shibboleth.sp.profile.AbstractAgentRequestAction;
+import net.shibboleth.sp.profile.SPConstants;
 
 /**
  * A profile action to decode an agent request and stash the resulting {@link DDF} in the
@@ -50,8 +56,35 @@ import net.shibboleth.sp.profile.AbstractAgentRequestAction;
  */
 public class DecodeAgentRequest extends AbstractAgentRequestAction {
 
+    /** MDC attribute name for application ID. */
+    @Nonnull @NotEmpty public static final String APPLICATION_ID_MDC_ATTRIBUTE = "sp.application_id";
+    
+    /** MDC attribute name for transaction ID. */
+    @Nonnull @NotEmpty public static final String TX_ID_MDC_ATTRIBUTE = "sp.txid";
+    
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(DecodeAgentRequest.class);
+        
+    /** Whether to populate the MDC. */
+    private boolean populateMDC;
+    
+    /** Constructor. */
+    public DecodeAgentRequest() {
+        populateMDC = true;
+    }
+    
+    /**
+     * Sets whether to populate the application and tx IDs into the logging MDC.
+     * 
+     * <p>Defaults to true.</p>
+     * 
+     * @param flag flag to set
+     */
+    public void setPopulateMDC(final boolean flag) {
+        checkSetterPreconditions();
+        
+        populateMDC = flag;
+    }
     
     /** {@inheritDoc} */
     @Override
@@ -88,6 +121,14 @@ public class DecodeAgentRequest extends AbstractAgentRequestAction {
                     }
                 }
                 
+                final String txid = msg.getmember(SPConstants.TXID).string();
+                log.debug("{} Decoded message with transaction ID '{}'", getLogPrefix(), txid);
+                
+                if (populateMDC) {
+                    MDC.put(TX_ID_MDC_ATTRIBUTE, txid);
+                    MDC.put(APPLICATION_ID_MDC_ATTRIBUTE, msg.getmember(SPConstants.APPLICATION).string());
+                }
+                
             } catch (final IOException e) {
                 log.warn("{} Unable to parse input message from HttpServletRequest", getLogPrefix(), e);
                 ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/ResolveApplication.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/ResolveApplication.java
index db1e4ca..4876527 100644
--- a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/ResolveApplication.java
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/ResolveApplication.java
@@ -21,12 +21,12 @@ import org.opensaml.profile.action.EventIds;
 import org.opensaml.profile.context.ProfileRequestContext;
 import org.slf4j.Logger;
 
-import net.shibboleth.shared.annotation.constraint.NotEmpty;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.sp.Agent;
 import net.shibboleth.sp.Application;
 import net.shibboleth.sp.ddf.DDF;
 import net.shibboleth.sp.profile.AbstractAgentAction;
+import net.shibboleth.sp.profile.SPConstants;
 
 /**
  * An action that maps a message request from an agent to the corresponding {@link Application}
@@ -35,12 +35,10 @@ import net.shibboleth.sp.profile.AbstractAgentAction;
  * @event {@link EventIds#PROCEED_EVENT_ID}
  * @event {@link EventIds#INVALID_MESSAGE}
  * @post <pre>AgentRequestContext.getApplication() != null</pre>
+ * @post <pre>An MDC logging attribute is created with the successfully resolved ID.</pre>
  */
 public class ResolveApplication extends AbstractAgentAction {
-
-    /** Field member carrying application ID. */
-    @Nonnull @NotEmpty public static final String APPLICATION_ID = "application";
-    
+        
     /** Class logger. */
     @Nonnull private final Logger log = LoggerFactory.getLogger(ResolveApplication.class);
     
@@ -51,19 +49,22 @@ public class ResolveApplication extends AbstractAgentAction {
         final Agent agent = ensureAgent();
         
         final DDF input = ensureAgentRequestContext().getInput();
-        final String applicationId = input != null ? input.getmember(APPLICATION_ID).string() : null;
+        final String applicationId = input != null ? input.getmember(SPConstants.APPLICATION).string() : null;
         if (applicationId == null) {
-            log.warn("{} Request from agent '{}' missing {} specifier", getLogPrefix(), agent.getId(), APPLICATION_ID);
+            log.warn("{} Request from agent '{}' missing {} specifier", getLogPrefix(), agent.getId(),
+                    SPConstants.APPLICATION);
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
             return;
         }
         
         final Application app = agent.getApplication(applicationId);
         if (app != null) {
-            log.debug("{} Request from agent '{}' mapped to application '{}'", getLogPrefix(), agent.getId(), app.getId());
             ensureAgentRequestContext().setApplication(app);
+            log.debug("{} Request from agent '{}' mapped to application '{}'", getLogPrefix(), agent.getId(),
+                    app.getApplicationId());
         } else {
-            log.warn("{} Request from agent '{}' with unknown application '{}'", getLogPrefix(), agent.getId(), applicationId);
+            log.warn("{} Request from agent '{}' with unknown application '{}'", getLogPrefix(), agent.getId(),
+                    applicationId);
             ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_MESSAGE);
         }
     }

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


More information about the commits mailing list