[java-oidc-common] branch main updated: JCOMOIDC-158 - Add protocol message logging support to AuthnResponseDecoders
Codeberg
noreply at shibboleth.net
Wed Mar 11 16:47:17 UTC 2026
This is an automated email from the git hooks/post-receive script.
codeberg pushed a commit to branch main
in repository java-oidc-common.
View the commit online:
https://codeberg.org/Shibboleth/java-oidc-common/commit/f9e4a03daf60e8e2e6234d86d95a04dbdf10c773
The following commit(s) were added to refs/heads/main by this push:
new f9e4a03d JCOMOIDC-158 - Add protocol message logging support to AuthnResponseDecoders
f9e4a03d is described below
commit f9e4a03daf60e8e2e6234d86d95a04dbdf10c773
Author: Phil Smart <philip.smart at jisc.ac.uk>
AuthorDate: Wed Mar 11 16:47:09 2026 +0000
JCOMOIDC-158 - Add protocol message logging support to
AuthnResponseDecoders
- Added logging support to the base decoder class
- Is only logging errors and Authorization Code response params e.g.
code and state.
https://shibboleth.atlassian.net/browse/JCOMOIDC-158
---
.../claims/impl/ChainingJWTClaimsValidator.java | 2 +-
.../decoding/impl/BaseHttpOIDCRequestDecoder.java | 30 +++++++-
.../impl/HTTPPostAuthnResponseDecoder.java | 9 ---
.../impl/HTTPRedirectAuthnResponseDecoder.java | 8 ---
.../impl/HTTPPostAuthnResponseDecoderTest.java | 83 ++++++++++++++++++++++
.../impl/HTTPRedirectAuthnResponseDecoderTest.java | 27 ++++++-
6 files changed, 138 insertions(+), 21 deletions(-)
diff --git a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/ChainingJWTClaimsValidator.java b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/ChainingJWTClaimsValidator.java
index a2c4caab..46bf8424 100644
--- a/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/ChainingJWTClaimsValidator.java
+++ b/oidc-common-crypto-impl/src/main/java/net/shibboleth/oidc/security/jwt/claims/impl/ChainingJWTClaimsValidator.java
@@ -42,7 +42,7 @@ import net.shibboleth.shared.primitive.LoggerFactory;
* <p>Normally, validation terminates when one of the validators throws a {@link JWTValidationException}.
* If no {@link JWTValidationException} is thrown, the claims set is 'valid'.</p>
*
- * <p>Optionally this can be toggled such that any of the validators succeeeding implies overall success.</p>
+ * <p>Optionally this can be toggled such that any of the validators succeeding implies overall success.</p>
*
* <p>Note, does not represent a chain of responsibility pattern despite the name.</p>
*/
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/BaseHttpOIDCRequestDecoder.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/BaseHttpOIDCRequestDecoder.java
index fb37f88e..b2493865 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/BaseHttpOIDCRequestDecoder.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/BaseHttpOIDCRequestDecoder.java
@@ -17,11 +17,16 @@ package net.shibboleth.oidc.profile.decoding.impl;
import java.util.function.Function;
import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.decoder.MessageDecodingException;
import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
+import com.google.common.base.MoreObjects;
+import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
+import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
+
import net.shibboleth.oidc.profile.decoding.OIDCMessageDecoder;
import net.shibboleth.shared.logic.Constraint;
import net.shibboleth.shared.logic.FunctionSupport;
@@ -29,6 +34,7 @@ import net.shibboleth.shared.logic.FunctionSupport;
/**
* A base class for OpenID Connect request decoders.
*/
+//TODO in v4 rename this class AbstractOIDCMessageDecoder
public abstract class BaseHttpOIDCRequestDecoder extends AbstractHttpServletRequestMessageDecoder
implements OIDCMessageDecoder {
@@ -42,6 +48,7 @@ public abstract class BaseHttpOIDCRequestDecoder extends AbstractHttpServletRequ
/** Constructor.*/
protected BaseHttpOIDCRequestDecoder() {
postDecodeStrategy = FunctionSupport.constant(true);
+ setProtocolMessageLoggerSubCategory("OAUTH2");
}
/**
@@ -81,6 +88,27 @@ public abstract class BaseHttpOIDCRequestDecoder extends AbstractHttpServletRequ
*/
protected abstract void performDecode() throws MessageDecodingException;
-
+ /** {@inheritDoc} */
+ @Override
+ @Nullable
+ protected String serializeMessageForLogging(@Nullable final Object message) {
+ if (message instanceof final AuthenticationSuccessResponse response) {
+ return MoreObjects.toStringHelper(this).omitNullValues()
+ .add("state", response.getState())
+ .add("code", response.getAuthorizationCode())
+ .toString();
+ }
+ if (message instanceof final AuthenticationErrorResponse response && response.getErrorObject() != null) {
+ return MoreObjects.toStringHelper(this).omitNullValues()
+ .add("status", response.getErrorObject().getHTTPStatusCode())
+ .add("error_description", response.getErrorObject().getDescription())
+ .add("error_uri", response.getErrorObject().getURI() == null ? null :
+ response.getErrorObject().getURI().toString())
+ .add("error", response.getErrorObject().getCode())
+ .add("state", response.getState())
+ .toString();
+ }
+ return null;
+ }
}
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoder.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoder.java
index c4f75a95..4a7957ad 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoder.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoder.java
@@ -17,7 +17,6 @@ package net.shibboleth.oidc.profile.decoding.impl;
import java.io.IOException;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.decoder.MessageDecoder;
@@ -65,12 +64,4 @@ public class HTTPPostAuthnResponseDecoder extends BaseHttpOIDCRequestDecoder {
setMessageContext(messageContext);
}
- /** {@inheritDoc} */
- @Override
- @Nullable
- protected String serializeMessageForLogging(@Nullable final Object message) {
- // Returning null disables log output. If want protocol message logging, need to implement this.
- return null;
- }
-
}
\ No newline at end of file
diff --git a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoder.java b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoder.java
index 63864fbe..f5efdb38 100644
--- a/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoder.java
+++ b/oidc-common-profile-impl/src/main/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoder.java
@@ -17,7 +17,6 @@ package net.shibboleth.oidc.profile.decoding.impl;
import java.io.IOException;
import javax.annotation.Nonnull;
-import javax.annotation.Nullable;
import org.opensaml.messaging.context.MessageContext;
import org.opensaml.messaging.decoder.MessageDecoder;
@@ -67,11 +66,4 @@ public class HTTPRedirectAuthnResponseDecoder extends BaseHttpOIDCRequestDecoder
setMessageContext(messageContext);
}
- /** {@inheritDoc} */
- @Override
- @Nullable
- protected String serializeMessageForLogging(@Nullable final Object message) {
- // Returning null disables log output. If want protocol message logging, need to implement this.
- return null;
- }
}
diff --git a/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoderTest.java b/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoderTest.java
index 1348e3fc..a0e422c1 100644
--- a/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoderTest.java
+++ b/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPPostAuthnResponseDecoderTest.java
@@ -14,6 +14,8 @@
package net.shibboleth.oidc.profile.decoding.impl;
+import static org.testng.Assert.assertEquals;
+import static org.testng.Assert.assertNotNull;
import static org.testng.Assert.assertTrue;
import org.opensaml.messaging.context.MessageContext;
@@ -23,6 +25,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
@@ -65,6 +68,86 @@ public class HTTPPostAuthnResponseDecoderTest {
assertTrue(((AuthenticationSuccessResponse) msg).getAuthorizationCode().getValue().equals("XSpej7DkB2WYcF1Gzth5CCHw6Oxf3gxR"));
}
+ @Test
+ public void testErrorResponseDecoding() throws Exception {
+ mockRequest.setMethod("POST");
+ mockRequest.setRequestURI("/idp/profile/Authn/OIDC/RP/callback");
+ mockRequest.addParameter("state", "91c28622815dd9a92ef7c984c74c9e39.65317332");
+ mockRequest.addParameter("error", "invalid_request");
+ mockRequest.addParameter("error_description", "bad request");
+ mockRequest.setContentType("application/x-www-form-urlencoded");
+ decoder.setHttpServletRequestSupplier(new ThreadLocalHttpServletRequestSupplier());
+ decoder.initialize();
+ decoder.decode();
+
+ final MessageContext mc = decoder.getMessageContext();
+ assert mc != null;
+
+ final Object msg = mc.getMessage();
+ assertTrue(msg instanceof AuthenticationErrorResponse);
+ assert msg != null;
+ assertTrue(((AuthenticationResponse) msg).getState().getValue().equals("91c28622815dd9a92ef7c984c74c9e39.65317332"));
+ assertEquals(((AuthenticationErrorResponse) msg).getErrorObject().getCode(),"invalid_request");
+ assertEquals(((AuthenticationErrorResponse) msg).getErrorObject().getDescription(),"bad request");
+ }
+
+ /* Test to make sure the protocol logging is creating a string for logging.*/
+ @SuppressWarnings("null")
+ @Test
+ public void testErrorResponseDecoding_ProtocolMessage() throws Exception {
+ mockRequest.setMethod("POST");
+ mockRequest.setRequestURI("/idp/profile/Authn/OIDC/RP/callback");
+ mockRequest.addParameter("state", "91c28622815dd9a92ef7c984c74c9e39.65317332");
+ mockRequest.addParameter("error", "invalid_request");
+ mockRequest.addParameter("error_uri", "http://op.example.org/error");
+ mockRequest.addParameter("error_description", "bad request");
+ mockRequest.setContentType("application/x-www-form-urlencoded");
+ decoder.setHttpServletRequestSupplier(new ThreadLocalHttpServletRequestSupplier());
+ decoder.initialize();
+ decoder.decode();
+
+ final MessageContext mc = decoder.getMessageContext();
+ assert mc != null;
+
+ final Object msg = mc.getMessage();
+ assertTrue(msg instanceof AuthenticationErrorResponse);
+ assert msg != null;
+ assertTrue(((AuthenticationResponse) msg).getState().getValue().equals("91c28622815dd9a92ef7c984c74c9e39.65317332"));
+ assertEquals(((AuthenticationErrorResponse) msg).getErrorObject().getCode(),"invalid_request");
+ assertEquals(((AuthenticationErrorResponse) msg).getErrorObject().getDescription(),"bad request");
+ final String logMessage = decoder.serializeMessageForLogging(msg);
+ assertNotNull(logMessage);
+ assertTrue(logMessage.contains("code"));
+ assertTrue(logMessage.contains("description"));
+ }
+
+ /* Test to make sure the protocol logging is creating a string for logging.*/
+ @SuppressWarnings("null")
+ @Test
+ public void testSuccessful_ProtocolMessage() throws Exception {
+ mockRequest.setMethod("POST");
+ mockRequest.setRequestURI("/idp/profile/Authn/OIDC/RP/callback");
+ mockRequest.addParameter("state", "91c28622815dd9a92ef7c984c74c9e39.65317332");
+ mockRequest.addParameter("code", "XSpej7DkB2WYcF1Gzth5CCHw6Oxf3gxR");
+ mockRequest.setContentType("application/x-www-form-urlencoded");
+ decoder.setHttpServletRequestSupplier(new ThreadLocalHttpServletRequestSupplier());
+ decoder.initialize();
+ decoder.decode();
+
+ final MessageContext mc = decoder.getMessageContext();
+ assert mc != null;
+
+ final Object msg = mc.getMessage();
+ assertTrue(msg instanceof AuthenticationSuccessResponse);
+ assert msg != null;
+ assertTrue(((AuthenticationResponse) msg).getState().getValue().equals("91c28622815dd9a92ef7c984c74c9e39.65317332"));
+ assertTrue(((AuthenticationSuccessResponse) msg).getAuthorizationCode().getValue().equals("XSpej7DkB2WYcF1Gzth5CCHw6Oxf3gxR"));
+ final String logMessage = decoder.serializeMessageForLogging(msg);
+ assertNotNull(logMessage);
+ assertTrue(logMessage.contains("state"));
+ assertTrue(logMessage.contains("code"));
+ }
+
@Test(expectedExceptions = MessageDecodingException.class)
public void testWrongMethod() throws Exception {
mockRequest.setMethod("GET");
diff --git a/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoderTest.java b/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoderTest.java
index 379ec400..bed93eee 100644
--- a/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoderTest.java
+++ b/oidc-common-profile-impl/src/test/java/net/shibboleth/oidc/profile/decoding/impl/HTTPRedirectAuthnResponseDecoderTest.java
@@ -14,6 +14,7 @@
package net.shibboleth.oidc.profile.decoding.impl;
+import static org.testng.Assert.assertEquals;
import static org.testng.Assert.assertTrue;
import org.opensaml.messaging.context.MessageContext;
@@ -23,6 +24,7 @@ import org.springframework.mock.web.MockHttpServletResponse;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
+import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
@@ -47,8 +49,7 @@ public class HTTPRedirectAuthnResponseDecoderTest {
@Test
public void testSuccessfulDecoding_Query_AuthCode() throws Exception {
mockRequest.setMethod("GET");
- mockRequest.setRequestURI("https://localhost/idp/profile/Authn/OIDC/RP/"
- + "callback?code=XSpej7DkB2WYcF1Gzth5CCHw6Oxf3gxR&state=91c28622815dd9a92ef7c984c74c9e39.65317332");
+ mockRequest.setRequestURI("https://localhost/idp/profile/Authn/OIDC/RP/callback");
mockRequest.setQueryString(
"code=XSpej7DkB2WYcF1Gzth5CCHw6Oxf3gxR&state=91c28622815dd9a92ef7c984c74c9e39.65317332");
mockRequest.setContentType("application/x-www-form-urlencoded");
@@ -68,6 +69,28 @@ public class HTTPRedirectAuthnResponseDecoderTest {
assertTrue(((AuthenticationSuccessResponse) msg).getAuthorizationCode().getValue().equals("XSpej7DkB2WYcF1Gzth5CCHw6Oxf3gxR"));
}
+ @Test
+ public void testErrorResponseDecoding() throws Exception {
+ mockRequest.setMethod("GET");
+ mockRequest.setRequestURI("https://localhost/idp/profile/Authn/OIDC/RP/callback");
+ mockRequest.setQueryString(
+ "error=invalid_request&error_description=bad%20request&state=91c28622815dd9a92ef7c984c74c9e39.65317332");
+ mockRequest.setContentType("application/x-www-form-urlencoded");
+ decoder.setHttpServletRequestSupplier(new ThreadLocalHttpServletRequestSupplier());
+ decoder.initialize();
+ decoder.decode();
+
+ final MessageContext mc = decoder.getMessageContext();
+ assert mc != null;
+
+ final Object msg = mc.getMessage();
+ assertTrue(msg instanceof AuthenticationErrorResponse);
+ assert msg != null;
+ assertTrue(((AuthenticationResponse) msg).getState().getValue().equals("91c28622815dd9a92ef7c984c74c9e39.65317332"));
+ assertEquals(((AuthenticationErrorResponse) msg).getErrorObject().getCode(),"invalid_request");
+ assertEquals(((AuthenticationErrorResponse) msg).getErrorObject().getDescription(),"bad request");
+ }
+
@Test(expectedExceptions = MessageDecodingException.class)
public void testWrongMethod() throws Exception {
mockRequest.setMethod("POST");
--
To stop receiving notification emails like this one, please contact
the administrator of this repository.
More information about the commits
mailing list