[java-plugin-shibd] branch main updated: Preliminary WIP on Hub auditing.
Codeberg
noreply at shibboleth.net
Wed Jun 24 16:09:09 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/63fb0c408a64fe4a763f424524913815e3c78baf
The following commit(s) were added to refs/heads/main by this push:
new 63fb0c4 Preliminary WIP on Hub auditing.
63fb0c4 is described below
commit 63fb0c408a64fe4a763f424524913815e3c78baf
Author: Scott Cantor <scott at restingparrotsoftware.com>
AuthorDate: Wed Jun 24 12:06:27 2026 -0400
Preliminary WIP on Hub auditing.
---
.../META-INF/net.shibboleth.idp/postconfig.xml | 57 ++++++++++++++
.../idp/flows/sp/abstract/sp-abstract-beans.xml | 35 ++++++++-
.../idp/flows/sp/abstract/sp-abstract-flow.xml | 9 ++-
.../java/net/shibboleth/sp/flows/PingFlowTest.java | 2 +-
.../net/shibboleth/sp/profile/SPAuditFields.java | 43 +++++++++++
.../sp/audit/impl/AgentIDAuditExtractor.java | 41 ++++++++++
.../sp/audit/impl/AgentInputAuditExtractor.java | 89 ++++++++++++++++++++++
.../net/shibboleth/sp/audit/impl/package-info.java | 18 +++++
.../sp/profile/impl/DecodeAgentRequest.java | 1 -
.../shibboleth/sp/profile/impl/WriteAuditLog.java | 40 ++++++++++
10 files changed, 331 insertions(+), 4 deletions(-)
diff --git a/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml b/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
index 977e77d..eb2a668 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net.shibboleth.idp/postconfig.xml
@@ -72,4 +72,61 @@
class="net.shibboleth.sp.util.TemplatedStringLookupStrategy"
p:velocityEngine-ref="shibboleth.VelocityEngine" />
+ <!-- Audit beans. -->
+
+ <bean id="shibboleth.sp.DefaultFlowStartAuditExtractors" lazy-init="true"
+ class="org.springframework.beans.factory.config.MapFactoryBean">
+ <property name="sourceMap">
+ <map>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.idp.profile.IdPAuditFields.START_TIME"/>
+ </key>
+ <bean parent="shibboleth.Functions.Expression" c:_0="T(java.time.Instant).now()" />
+ </entry>
+ </map>
+ </property>
+ </bean>
+
+ <bean id="shibboleth.sp.DefaultPostAgentDecodeAuditExtractors" lazy-init="true"
+ class="org.springframework.beans.factory.config.MapFactoryBean">
+ <property name="sourceMap">
+ <map>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.sp.profile.SPAuditFields.AGENT_ID"/>
+ </key>
+ <bean class="net.shibboleth.sp.audit.impl.AgentIDAuditExtractor" />
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.sp.profile.SPAuditFields.APPLICATION_ID"/>
+ </key>
+ <bean class="net.shibboleth.sp.audit.impl.AgentInputAuditExtractor">
+ <property name="fieldName">
+ <util:constant static-field="net.shibboleth.sp.profile.SPConstants.APPLICATION"/>
+ </property>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.sp.profile.SPAuditFields.TX_ID"/>
+ </key>
+ <bean class="net.shibboleth.sp.audit.impl.AgentInputAuditExtractor">
+ <property name="fieldName">
+ <util:constant static-field="net.shibboleth.sp.profile.SPConstants.TXID"/>
+ </property>
+ </bean>
+ </entry>
+ <entry>
+ <key>
+ <util:constant static-field="net.shibboleth.sp.profile.SPAuditFields.OPERATION"/>
+ </key>
+ <!-- No field name pulls name of structure -> operation. -->
+ <bean class="net.shibboleth.sp.audit.impl.AgentInputAuditExtractor" />
+ </entry>
+ </map>
+ </property>
+ </bean>
+
</beans>
\ No newline at end of file
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 4102728..97a844c 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
@@ -7,11 +7,41 @@
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
default-init-method="initialize" default-destroy-method="destroy">
+ <!-- Beans for flow auditing -->
+
+ <bean id="shibboleth.sp.AbstractPopulateAuditContext" abstract="true"
+ class="net.shibboleth.idp.profile.audit.impl.PopulateAuditContext" scope="prototype"
+ p:formattingMapParser-ref="shibboleth.sp.AuditFormattingMapParser"
+ p:dateTimeFormat="#{getObject('shibboleth.AuditDateTimeFormat')}"
+ p:useDefaultTimeZone="#{getObject('shibboleth.AuditDefaultTimeZone') ?: false}"
+ p:fieldReplacements="#{getObject('shibboleth.AuditFieldReplacementMap')}" />
+
+ <bean id="shibboleth.sp.AuditFormattingMapParser" scope="prototype" lazy-init="true"
+ class="net.shibboleth.idp.profile.audit.impl.PopulateAuditContext.FormattingMapParser"
+ c:_0="#{getObject('shibboleth.sp.AuditFormattingMap') ?: getObject('shibboleth.sp.DefaultAuditFormattingMap')}" />
+
+ <bean id="WriteAuditLog"
+ class="net.shibboleth.sp.profile.impl.WriteAuditLog" scope="prototype" lazy-init="true"
+ p:formattingMap="#{getObject('shibboleth.sp.AuditFormattingMap') ?: getObject('shibboleth.sp.DefaultAuditFormattingMap')}"
+ p:dateTimeFormat="#{getObject('shibboleth.AuditDateTimeFormat')}"
+ p:useDefaultTimeZone="#{getObject('shibboleth.AuditDefaultTimeZone') ?: false}"
+ p:httpServletRequestSupplier-ref="shibboleth.RemotedHttpServletRequestSupplier"
+ p:httpServletResponseSupplier-ref="shibboleth.RemotedHttpServletResponseSupplier" />
+
+ <util:map id="shibboleth.sp.DefaultAuditFormattingMap">
+ <entry key="Shibboleth-Audit.SP" value="%AGENT|%APP|%TX|%OP|%a|%ST|%T|%IDP|%SP|%i|%ac|%t|%attr|%n|%f|%X|%XA|%b|%bb|%e|%S|%SS|%UA" />
+ </util:map>
+
+ <!-- Action beans. -->
+
<bean id="InitializeProfileRequestContext"
class="net.shibboleth.idp.profile.impl.InitializeProfileRequestContext" scope="prototype"
p:profileId-ref="shibboleth.sp.profileId"
p:loggingId-ref="shibboleth.sp.loggingId" />
+ <bean id="FlowStartPopulateAuditContext" parent="shibboleth.sp.AbstractPopulateAuditContext"
+ p:fieldExtractors="#{getObject('shibboleth.sp.FlowStartAuditExtractors') ?: getObject('shibboleth.sp.DefaultFlowStartAuditExtractors')}" />
+
<bean id="PopulateMetricContext"
class="org.opensaml.profile.action.impl.PopulateMetricContext" scope="prototype"
p:counterName="#{getObject('shibboleth.metrics.ProfileCounter')}"
@@ -64,6 +94,9 @@
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
p:populateMDC="%{idp.logging.MDC.enabled:true}" />
+ <bean id="PostAgentDecodePopulateAuditContext" parent="shibboleth.sp.AbstractPopulateAuditContext"
+ p:fieldExtractors="#{getObject('shibboleth.sp.PostAgentDecodeAuditExtractors') ?: getObject('shibboleth.sp.DefaultPostAgentDecodeAuditExtractors')}" />
+
<bean id="EncodeAgentResponse" class="net.shibboleth.sp.profile.impl.EncodeAgentResponse" scope="prototype"
p:httpServletRequestSupplier-ref="shibboleth.HttpServletRequestSupplier"
p:httpServletResponseSupplier-ref="shibboleth.HttpServletResponseSupplier" />
@@ -76,7 +109,7 @@
<bean id="PrepareAgentErrorResponse"
class="net.shibboleth.sp.profile.impl.PrepareAgentErrorResponse" scope="prototype" />
- <!-- ======== Beans for agent authentication ======== -->
+ <!-- Beans for agent authentication -->
<util:list id="DefaultAgentValidators">
<!-- Default just uses secrets defined in agents.xml file. -->
diff --git a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
index 2e67dbe..d2171c9 100644
--- a/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
+++ b/sp-conf-impl/src/main/resources/META-INF/net/shibboleth/idp/flows/sp/abstract/sp-abstract-flow.xml
@@ -8,6 +8,7 @@
<!-- Needed to allow reuse of various classes. -->
<evaluate expression="opensamlProfileRequestContext.ensureSubcontext(T(net.shibboleth.idp.authn.context.AuthenticationContext)).setAttemptedFlow(flowRequestContext.getActiveFlow().getApplicationContext().getBean('AgentAuthnFlowDescriptor'))" />
</on-entry>
+ <evaluate expression="FlowStartPopulateAuditContext" />
<evaluate expression="PopulateMetricContext" />
<evaluate expression="ExtractUsernamePasswordFromBasicAuth" />
<evaluate expression="InitializeAgentRequestContext" />
@@ -36,6 +37,7 @@
<action-state id="DecodeAgentRequest">
<evaluate expression="DecodeAgentRequest" />
+ <evaluate expression="PostAgentDecodePopulateAuditContext" />
<evaluate expression="'proceed'" />
<transition on="proceed" to="DoOperation" />
@@ -79,6 +81,7 @@
<end-state id="HandleErrorWithView" view="sp/error">
<on-entry>
+ <evaluate expression="WriteAuditLog" />
<evaluate expression="environment" result="requestScope.environment" />
<evaluate expression="currentEvent" result="requestScope.currentEvent" />
<evaluate expression="opensamlProfileRequestContext" result="requestScope.profileRequestContext" />
@@ -104,7 +107,11 @@
<!-- Successful terminal state (success meaning outbound agent response encoded). -->
- <end-state id="end" />
+ <end-state id="end">
+ <on-entry>
+ <evaluate expression="WriteAuditLog" />
+ </on-entry>
+ </end-state>
<!-- All unhandled non-proceed results are turned into errors. -->
<global-transitions>
diff --git a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/PingFlowTest.java b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/PingFlowTest.java
index c33534f..7100b07 100644
--- a/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/PingFlowTest.java
+++ b/sp-conf-impl/src/test/java/net/shibboleth/sp/flows/PingFlowTest.java
@@ -81,7 +81,7 @@ public class PingFlowTest extends AbstractSPFlowTest {
@Test
public void testSuccess() throws IOException {
setDefaultAuth();
- setRequest("GET", new DDF(null));
+ setRequest("GET", new DDF("ping"));
final FlowExecutionResult result = flowExecutor.launchExecution(FLOW_ID, null, externalContext);
assertFlowExecutionResult(result, FLOW_ID);
assertFlowExecutionOutcome(result.getOutcome());
diff --git a/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPAuditFields.java b/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPAuditFields.java
new file mode 100644
index 0000000..28bf80d
--- /dev/null
+++ b/sp-server-api/src/main/java/net/shibboleth/sp/profile/SPAuditFields.java
@@ -0,0 +1,43 @@
+/*
+ * 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.sp.profile;
+
+import javax.annotation.Nonnull;
+
+import net.shibboleth.shared.annotation.constraint.NotEmpty;
+
+/**
+ * Constants for token and logout consumer operations.
+ */
+public final class SPAuditFields {
+
+
+ /** Private constructor. */
+ private SPAuditFields() {
+ }
+
+ /** Agent ID field. */
+ @Nonnull @NotEmpty public static final String AGENT_ID = "AGENT";
+
+ /** Application ID field. */
+ @Nonnull @NotEmpty public static final String APPLICATION_ID = "APP";
+
+ /** Transaction ID field. */
+ @Nonnull @NotEmpty public static final String TX_ID = "TX";
+
+ /** Operation field. */
+ @Nonnull @NotEmpty public static final String OPERATION = "OP";
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/AgentIDAuditExtractor.java b/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/AgentIDAuditExtractor.java
new file mode 100644
index 0000000..1ea2f18
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/AgentIDAuditExtractor.java
@@ -0,0 +1,41 @@
+/*
+ * 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.sp.audit.impl;
+
+import java.util.function.Function;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.sp.Agent;
+import net.shibboleth.sp.context.AgentRequestContext;
+
+/**
+ * Audit field extractor that pulls the Agent ID from the active request.
+ */
+public class AgentIDAuditExtractor implements Function<ProfileRequestContext,String> {
+
+ /** {@inheritDoc} */
+ @Nullable public String apply(@Nullable final ProfileRequestContext input) {
+
+ final AgentRequestContext agentRequestContext =
+ input != null ? input.getSubcontext(AgentRequestContext.class) : null;
+
+ final Agent agent = agentRequestContext != null ? agentRequestContext.getAgent() : null;
+ return agent != null ? agent.getId() : null;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/AgentInputAuditExtractor.java b/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/AgentInputAuditExtractor.java
new file mode 100644
index 0000000..9e3f3fa
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/AgentInputAuditExtractor.java
@@ -0,0 +1,89 @@
+/*
+ * 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.sp.audit.impl;
+
+import java.nio.charset.StandardCharsets;
+import java.util.function.Function;
+
+import javax.annotation.Nullable;
+
+import org.opensaml.profile.context.ProfileRequestContext;
+
+import net.shibboleth.sp.context.AgentRequestContext;
+import net.shibboleth.sp.ddf.DDF;
+
+/**
+ * Audit field extractor that pulls out and converts a particular input member from an
+ * Agent's request message.
+ *
+ * <p>If no field is specified, the "name" of the actual message structure is returned.</p>
+ */
+public class AgentInputAuditExtractor implements Function<ProfileRequestContext,String> {
+
+ /**
+ * Name of field to extract.
+ */
+ @Nullable private String fieldName;
+
+ /**
+ * Sets name of the field for which to return a value.
+ *
+ * @param name field name, dotted notation permitted
+ */
+ public void setFieldName(@Nullable final String name) {
+ fieldName = name;
+ }
+
+ /** {@inheritDoc} */
+ @Nullable public String apply(@Nullable final ProfileRequestContext input) {
+
+ final AgentRequestContext agentRequestContext =
+ input != null ? input.getSubcontext(AgentRequestContext.class) : null;
+ final DDF obj = agentRequestContext != null ? agentRequestContext.getInput() : null;
+ if (obj != null) {
+ if (fieldName != null) {
+ final DDF field = obj.getmember(fieldName);
+ if (field.isstring()) {
+ return field.string();
+ } else if (field.isint() || field.islist() || field.isstruct()) {
+ final Integer val = field.integer();
+ if (val != null) {
+ return val.toString();
+ }
+ } else if (field.islong()) {
+ final Long val = field.longinteger();
+ if (val != null) {
+ return val.toString();
+ }
+ } else if (field.isfloat()) {
+ final Double val = field.floating();
+ if (val != null) {
+ return val.toString();
+ }
+ } else if (field.isunsafestring()) {
+ final byte[] val = field.unsafe_string();
+ if (val != null) {
+ return new String(val, StandardCharsets.UTF_8);
+ }
+ }
+ } else {
+ return obj.name();
+ }
+ }
+
+ return null;
+ }
+
+}
\ No newline at end of file
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/package-info.java b/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/package-info.java
new file mode 100644
index 0000000..ccf4014
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/audit/impl/package-info.java
@@ -0,0 +1,18 @@
+/*
+ * 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.
+ */
+
+/**
+ * Implementation of SP audting features.
+ */
+package net.shibboleth.sp.audit.impl;
\ No newline at end of file
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 dd61813..098a837 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
@@ -108,7 +108,6 @@ public class DecodeAgentRequest extends AbstractAgentAction {
}
final AgentRequestContext agentContext = ensureAgentRequestContext();
- final Agent agent = agentContext.getAgent();
try (final InputStream in = request.getInputStream()) {
assert in != null;
diff --git a/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/WriteAuditLog.java b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/WriteAuditLog.java
new file mode 100644
index 0000000..5241b4e
--- /dev/null
+++ b/sp-server-impl/src/main/java/net/shibboleth/sp/profile/impl/WriteAuditLog.java
@@ -0,0 +1,40 @@
+/*
+ * 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.sp.profile.impl;
+
+import javax.annotation.Nullable;
+
+import jakarta.servlet.http.HttpServletRequest;
+
+/**
+ * Subclass of IdP auditing action that overrides the {@link HttpServletRequest} accessor
+ * to bypass the "non-null" assumptions built into our profile action classes.
+ *
+ * This is an "alternative" means of getting the remoted request into the execution code
+ * and is necessary when the object may be absent.
+ */
+public class WriteAuditLog extends net.shibboleth.idp.profile.audit.impl.WriteAuditLog {
+
+ /** {@inheritDoc} */
+ @Override
+ @Nullable public HttpServletRequest getHttpServletRequest() {
+ try {
+ return super.getHttpServletRequest();
+ } catch (final IllegalStateException e) {
+ return null;
+ }
+ }
+
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list