[java-idp-oidc] branch main updated: JOIDC-112 - PROTOCOL_MESSAGE.OAUTH2 log appender to trace all the exchanged protocol messages
Henri Mikkonen
henri.mikkonen at iki.fi
Thu Jun 23 08:13:36 UTC 2022
This is an automated email from the git hooks/post-receive script.
hjmikkon pushed a commit to branch main
in repository java-idp-oidc.
View the commit online:
http://git.shibboleth.net/view/?p=java-idp-oidc.git;a=commit;h=7c0dde43892ced79747557384df270c00f19932b
The following commit(s) were added to refs/heads/main by this push:
new 7c0dde43 JOIDC-112 - PROTOCOL_MESSAGE.OAUTH2 log appender to trace all the exchanged protocol messages
7c0dde43 is described below
commit 7c0dde43892ced79747557384df270c00f19932b
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Jun 23 11:11:35 2022 +0300
JOIDC-112 - PROTOCOL_MESSAGE.OAUTH2 log appender to trace all the exchanged protocol messages
https://shibboleth.atlassian.net/browse/JOIDC-112
The contents of the Nimbus request and response objects are now logged on DEBUG level
to the PROTOCOL_MESSAGE.OAUTH2 appender. The values of client secrets are not shown.
The existing encoder/decoder class loggers were kept: on DEBUG-level they log all HTTP
headers and parameters, including client secrets (or e.g. HTTP-Basic authentication).
---
.../impl/OIDCAuthenticationRequestDecoder.java | 49 +++-
.../impl/OIDCClientRegistrationRequestDecoder.java | 28 ++-
.../op/decoding/impl/OIDCTokenRequestDecoder.java | 32 ++-
.../decoding/impl/OIDCUserInfoRequestDecoder.java | 27 +-
.../plugin/oidc/op/decoding/impl/RequestUtil.java | 88 +++++++
.../op/encoding/impl/NimbusResponseEncoder.java | 14 +-
.../plugin/oidc/op/encoding/impl/ResponseUtil.java | 275 +++++++++++++++++++++
.../decoding/impl/BaseOAuth2RequestDecoder.java | 76 ++++++
.../impl/OAuth2IntrospectionRequestDecoder.java | 26 +-
.../impl/OAuth2RevocationRequestDecoder.java | 26 +-
10 files changed, 585 insertions(+), 56 deletions(-)
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCAuthenticationRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCAuthenticationRequestDecoder.java
index 477efa97..588287d4 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCAuthenticationRequestDecoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCAuthenticationRequestDecoder.java
@@ -20,20 +20,23 @@ package net.shibboleth.idp.plugin.oidc.op.decoding.impl;
import java.io.IOException;
import javax.annotation.Nonnull;
-import org.opensaml.messaging.context.MessageContext;
+import javax.annotation.Nullable;
+
import org.opensaml.messaging.decoder.MessageDecodingException;
-import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.MoreObjects;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.ServletUtils;
import com.nimbusds.openid.connect.sdk.AuthenticationRequest;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.decoding.impl.BaseOAuth2RequestDecoder;
+
/**
* Message decoder decoding OpenID Connect {@link AuthenticationRequest}s.
*/
-public class OIDCAuthenticationRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+public class OIDCAuthenticationRequestDecoder extends BaseOAuth2RequestDecoder<AuthenticationRequest> {
/** Class logger. */
@Nonnull
@@ -41,20 +44,46 @@ public class OIDCAuthenticationRequestDecoder extends AbstractHttpServletRequest
/** {@inheritDoc} */
@Override
- protected void doDecode() throws MessageDecodingException {
- final MessageContext messageContext = new MessageContext();
- AuthenticationRequest req = null;
+ protected AuthenticationRequest parseMessage() throws MessageDecodingException {
try {
final HTTPRequest httpReq = ServletUtils.createHTTPRequest(getHttpServletRequest());
log.debug("Inbound request {}", RequestUtil.toString(httpReq));
- req = AuthenticationRequest.parse(httpReq);
+ return AuthenticationRequest.parse(httpReq);
} catch (final com.nimbusds.oauth2.sdk.ParseException | IOException e) {
log.error("Unable to decode inbound request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
- messageContext.setMessage(req);
- log.debug("Decoded inbound request query string {}", req.toQueryString());
- setMessageContext(messageContext);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(@Nullable final AuthenticationRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("maxAge", message.getMaxAge())
+ .add("acrValues", message.getACRValues())
+ .add("claimsLocales", message.getClaimsLocales())
+ .add("clientId", message.getClientID())
+ .add("codeChallenge", message.getCodeChallenge())
+ .add("codeChallengeMethod", message.getCodeChallengeMethod())
+ .add("customParameters", message.getCustomParameters())
+ .add("display", message.getDisplay())
+ .add("endpointURI", message.getEndpointURI())
+ .add("idTokenHint", message.getIDTokenHint() == null ? null : message.getIDTokenHint().serialize())
+ .add("loginHint", message.getLoginHint())
+ .add("nonce", message.getNonce())
+ .add("oidcClaims", message.getOIDCClaims())
+ .add("prompt", message.getPrompt())
+ .add("purpose", message.getPurpose())
+ .add("redirectionURI", message.getRedirectionURI())
+ .add("requestObject", message.getRequestObject() == null ? null : message.getRequestObject().serialize())
+ .add("requestURI", message.getRequestURI())
+ .add("resources", message.getResources())
+ .add("responseMode", message.getResponseMode())
+ .add("responseType", message.getResponseType())
+ .add("scope", message.getScope())
+ .add("state", message.getState())
+ .add("uiLocales", message.getUILocales())
+ .toString();
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCClientRegistrationRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCClientRegistrationRequestDecoder.java
index 88257a1b..94661099 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCClientRegistrationRequestDecoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCClientRegistrationRequestDecoder.java
@@ -20,13 +20,13 @@ package net.shibboleth.idp.plugin.oidc.op.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.MessageDecodingException;
-import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.MoreObjects;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.client.ClientRegistrationRequest;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
@@ -34,11 +34,12 @@ import com.nimbusds.oauth2.sdk.http.ServletUtils;
import com.nimbusds.openid.connect.sdk.rp.OIDCClientRegistrationRequest;
import net.minidev.json.JSONObject;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.decoding.impl.BaseOAuth2RequestDecoder;
/**
* Message decoder decoding OpenID Connect {@link ClientRegistrationRequest}s.
*/
-public class OIDCClientRegistrationRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+public class OIDCClientRegistrationRequestDecoder extends BaseOAuth2RequestDecoder<OIDCClientRegistrationRequest> {
/** Class logger. */
@Nonnull
@@ -46,8 +47,7 @@ public class OIDCClientRegistrationRequestDecoder extends AbstractHttpServletReq
/** {@inheritDoc} */
@Override
- protected void doDecode() throws MessageDecodingException {
- final MessageContext messageContext = new MessageContext();
+ protected OIDCClientRegistrationRequest parseMessage() throws MessageDecodingException {
try {
final HTTPRequest httpRequest = ServletUtils.createHTTPRequest(getHttpServletRequest());
log.debug("Inbound request {}", RequestUtil.toString(httpRequest));
@@ -61,9 +61,7 @@ public class OIDCClientRegistrationRequestDecoder extends AbstractHttpServletReq
}
log.trace("JSON object: {}", httpRequest.getQueryAsJSONObject().toJSONString());
- final OIDCClientRegistrationRequest request = OIDCClientRegistrationRequest.parse(httpRequest);
- messageContext.setMessage(request);
- log.debug("Decoded OIDC client registration request {}", request.toHTTPRequest());
+ return OIDCClientRegistrationRequest.parse(httpRequest);
} catch (final IOException e) {
log.error("Could not create HTTP request from the request", e);
throw new MessageDecodingException(e);
@@ -71,7 +69,19 @@ public class OIDCClientRegistrationRequestDecoder extends AbstractHttpServletReq
log.error("Unable to decode oidc request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
- setMessageContext(messageContext);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(@Nullable final OIDCClientRegistrationRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("accessToken", RequestUtil.getAccessTokenLog(message.getAccessToken()))
+ .add("clientMetadata", message.getClientMetadata())
+ .add("endpointURI", message.getEndpointURI())
+ .add("oidcClientMetadata", message.getOIDCClientMetadata())
+ .add("softwareStatement", message.getSoftwareStatement() == null ? null :
+ message.getSoftwareStatement().serialize())
+ .toString();
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCTokenRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCTokenRequestDecoder.java
index 7f8e3233..65ef5539 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCTokenRequestDecoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCTokenRequestDecoder.java
@@ -19,21 +19,24 @@ package net.shibboleth.idp.plugin.oidc.op.decoding.impl;
import java.io.IOException;
import javax.annotation.Nonnull;
-import org.opensaml.messaging.context.MessageContext;
+import javax.annotation.Nullable;
+
import org.opensaml.messaging.decoder.MessageDecodingException;
-import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.MoreObjects;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.TokenRequest;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.ServletUtils;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.decoding.impl.BaseOAuth2RequestDecoder;
+
/**
* Message decoder decoding OpenID Connect {@link TokenRequest}s.
*/
-public class OIDCTokenRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+public class OIDCTokenRequestDecoder extends BaseOAuth2RequestDecoder<TokenRequest> {
/** Class logger. */
@Nonnull
@@ -41,19 +44,30 @@ public class OIDCTokenRequestDecoder extends AbstractHttpServletRequestMessageDe
/** {@inheritDoc} */
@Override
- protected void doDecode() throws MessageDecodingException {
- final MessageContext messageContext = new MessageContext();
- TokenRequest req = null;
+ protected TokenRequest parseMessage() throws MessageDecodingException {
try {
final HTTPRequest httpReq = ServletUtils.createHTTPRequest(getHttpServletRequest());
log.debug("Inbound request {}", RequestUtil.toString(httpReq));
- req = TokenRequest.parse(httpReq);
+ return TokenRequest.parse(httpReq);
} catch (final ParseException | IOException e) {
log.error("Unable to decode inbound request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
- messageContext.setMessage(req);
- setMessageContext(messageContext);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(@Nullable final TokenRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("authorizationGrant", RequestUtil.getAuthorizationGrantLog(message.getAuthorizationGrant()))
+ .add("clientAuthentication", RequestUtil.getClientAuthenticationLog(message.getClientAuthentication()))
+ .add("clientId", message.getClientID())
+ .add("customParameters", message.getCustomParameters())
+ .add("endpointURI", message.getEndpointURI())
+ .add("existingGrant", RequestUtil.getRefreshTokenLog(message.getExistingGrant()))
+ .add("resources", message.getResources())
+ .add("scope", message.getScope())
+ .toString();
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCUserInfoRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCUserInfoRequestDecoder.java
index bfe4993a..8aef7af0 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCUserInfoRequestDecoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/OIDCUserInfoRequestDecoder.java
@@ -19,40 +19,49 @@ package net.shibboleth.idp.plugin.oidc.op.decoding.impl;
import java.io.IOException;
import javax.annotation.Nonnull;
-import org.opensaml.messaging.context.MessageContext;
+import javax.annotation.Nullable;
+
import org.opensaml.messaging.decoder.MessageDecodingException;
-import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.MoreObjects;
import com.nimbusds.oauth2.sdk.ParseException;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.ServletUtils;
import com.nimbusds.openid.connect.sdk.UserInfoRequest;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.decoding.impl.BaseOAuth2RequestDecoder;
+
/**
* Message decoder decoding OpenID Connect {@link UserInfoRequest}s.
*/
-public class OIDCUserInfoRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+public class OIDCUserInfoRequestDecoder extends BaseOAuth2RequestDecoder<UserInfoRequest> {
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(OIDCUserInfoRequestDecoder.class);
/** {@inheritDoc} */
@Override
- protected void doDecode() throws MessageDecodingException {
- final MessageContext messageContext = new MessageContext();
- UserInfoRequest req = null;
+ protected UserInfoRequest parseMessage() throws MessageDecodingException {
try {
final HTTPRequest httpReq = ServletUtils.createHTTPRequest(getHttpServletRequest());
log.debug("Inbound request {}", RequestUtil.toString(httpReq));
- req = UserInfoRequest.parse(httpReq);
+ return UserInfoRequest.parse(httpReq);
} catch (final ParseException | IOException e) {
log.error("Unable to decode inbound request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
- messageContext.setMessage(req);
- setMessageContext(messageContext);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(final @Nullable UserInfoRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("accessToken", RequestUtil.getAccessTokenLog(message.getAccessToken()))
+ .add("method", message.getMethod())
+ .add("endpointURI", message.getEndpointURI())
+ .toString();
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/RequestUtil.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/RequestUtil.java
index c1d7dab2..fcd63487 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/RequestUtil.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/decoding/impl/RequestUtil.java
@@ -23,7 +23,15 @@ import java.util.Map.Entry;
import javax.annotation.Nullable;
+import com.google.common.base.MoreObjects;
+import com.nimbusds.oauth2.sdk.AuthorizationCodeGrant;
+import com.nimbusds.oauth2.sdk.AuthorizationGrant;
+import com.nimbusds.oauth2.sdk.ClientCredentialsGrant;
+import com.nimbusds.oauth2.sdk.RefreshTokenGrant;
+import com.nimbusds.oauth2.sdk.auth.ClientAuthentication;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
+import com.nimbusds.oauth2.sdk.token.AccessToken;
+import com.nimbusds.oauth2.sdk.token.RefreshToken;
/** Request logging helper class. */
public final class RequestUtil {
@@ -61,4 +69,84 @@ public final class RequestUtil {
}
return ret;
}
+
+ /**
+ * Helper method for getting protocol log message for client authentication object.
+ *
+ * @param authentication The client authentication object
+ * @return The log message
+ */
+ @Nullable public static String getClientAuthenticationLog(@Nullable final ClientAuthentication authentication) {
+ return authentication == null ? null : MoreObjects.toStringHelper("ClientAuthentication")
+ .add("clientId", authentication.getClientID())
+ .add("method", authentication.getMethod())
+ .toString();
+ }
+
+ /**
+ * Helper method for getting protocol log message for access token object.
+ *
+ * @param accessToken The access token object
+ * @return The log message
+ */
+ @Nullable public static String getAccessTokenLog(@Nullable final AccessToken accessToken) {
+ return accessToken == null ? null : MoreObjects.toStringHelper("AccessToken")
+ .add("lifetime", accessToken.getLifetime())
+ .add("issuedTokenType", accessToken.getIssuedTokenType())
+ .add("parameterNames", accessToken.getParameterNames())
+ .add("scope", accessToken.getScope())
+ .add("value", accessToken.getValue())
+ .add("type", accessToken.getType())
+ .toString();
+ }
+
+ /**
+ * Helper method for getting protocol log message for authorization grant object.
+ *
+ * @param grant The authorization grant object
+ * @return The log message
+ */
+ @Nullable public static String getAuthorizationGrantLog(@Nullable final AuthorizationGrant grant) {
+ if (grant == null) {
+ return null;
+ }
+ if (grant instanceof AuthorizationCodeGrant) {
+ final AuthorizationCodeGrant codeGrant = (AuthorizationCodeGrant) grant;
+ return MoreObjects.toStringHelper(codeGrant).omitNullValues()
+ .add("authorizationCode", codeGrant.getAuthorizationCode())
+ .add("codeVerifier", codeGrant.getCodeVerifier())
+ .add("redirectionURI", codeGrant.getRedirectionURI())
+ .add("type", codeGrant.getType())
+ .toString();
+ } else if (grant instanceof RefreshTokenGrant) {
+ final RefreshTokenGrant refreshGrant = (RefreshTokenGrant) grant;
+ return MoreObjects.toStringHelper(refreshGrant).omitNullValues()
+ .add("refreshToken", getRefreshTokenLog(refreshGrant.getRefreshToken()))
+ .add("type", refreshGrant.getType())
+ .toString();
+ } else if (grant instanceof ClientCredentialsGrant) {
+ final ClientCredentialsGrant credentialsGrant = (ClientCredentialsGrant) grant;
+ return MoreObjects.toStringHelper(credentialsGrant).omitNullValues()
+ .add("type", credentialsGrant.getType())
+ .toString();
+
+ }
+ return MoreObjects.toStringHelper(grant).omitNullValues()
+ .add("type", grant.getType())
+ .toString();
+ }
+
+ /**
+ * Helper method for getting protocol log message for refresh token object.
+ *
+ * @param refreshToken The refresh token object
+ * @return The log message
+ */
+ @Nullable public static String getRefreshTokenLog(@Nullable final RefreshToken refreshToken) {
+ return refreshToken == null ? null : MoreObjects.toStringHelper("RefreshToken")
+ .add("parameterNames", refreshToken.getParameterNames())
+ .add("value", refreshToken.getValue())
+ .toString();
+ }
+
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/NimbusResponseEncoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/NimbusResponseEncoder.java
index d579ed82..f53c402f 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/NimbusResponseEncoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/NimbusResponseEncoder.java
@@ -57,6 +57,9 @@ public class NimbusResponseEncoder extends AbstractHttpServletResponseMessageEnc
/** Class logger. */
@Nonnull private final Logger log = LoggerFactory.getLogger(NimbusResponseEncoder.class);
+ /** Used to log protocol messages. */
+ @Nonnull private final Logger protocolMessageLog = LoggerFactory.getLogger("PROTOCOL_MESSAGE.OAUTH2");
+
/** Velocity engine used to evaluate the template when using FORM POST response mode. */
@Nullable private VelocityEngine velocityEngine;
@@ -122,7 +125,16 @@ public class NimbusResponseEncoder extends AbstractHttpServletResponseMessageEnc
if (!(getMessageContext().getMessage() instanceof Response)) {
throw new MessageEncodingException("Incorrect message type");
}
-
+
+ if (protocolMessageLog.isDebugEnabled() ){
+ final String message = ResponseUtil.getProtocolMessage((Response) getMessageContext().getMessage());
+ if (message == null) {
+ log.warn("Protocol log message was null, nothing to log");
+ } else {
+ protocolMessageLog.debug(message);
+ }
+ }
+
try {
final HttpServletResponse response = getHttpServletResponse();
if (impliesFormPost(getMessageContext().getMessage())) {
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/ResponseUtil.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/ResponseUtil.java
index 45c5fcc3..746b017f 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/ResponseUtil.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/encoding/impl/ResponseUtil.java
@@ -22,10 +22,37 @@ import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.servlet.http.HttpServletResponse;
+import com.google.common.base.MoreObjects;
+import com.nimbusds.oauth2.sdk.AccessTokenResponse;
+import com.nimbusds.oauth2.sdk.ErrorObject;
+import com.nimbusds.oauth2.sdk.ErrorResponse;
+import com.nimbusds.oauth2.sdk.Response;
+import com.nimbusds.oauth2.sdk.TokenErrorResponse;
+import com.nimbusds.oauth2.sdk.TokenIntrospectionErrorResponse;
+import com.nimbusds.oauth2.sdk.TokenIntrospectionResponse;
+import com.nimbusds.oauth2.sdk.TokenIntrospectionSuccessResponse;
+import com.nimbusds.oauth2.sdk.TokenResponse;
+import com.nimbusds.oauth2.sdk.client.ClientInformation;
+import com.nimbusds.oauth2.sdk.client.ClientInformationResponse;
+import com.nimbusds.oauth2.sdk.client.ClientRegistrationErrorResponse;
import com.nimbusds.oauth2.sdk.http.HTTPResponse;
+import com.nimbusds.oauth2.sdk.token.Tokens;
+import com.nimbusds.openid.connect.sdk.AuthenticationErrorResponse;
+import com.nimbusds.openid.connect.sdk.AuthenticationResponse;
+import com.nimbusds.openid.connect.sdk.AuthenticationSuccessResponse;
+import com.nimbusds.openid.connect.sdk.UserInfoErrorResponse;
+import com.nimbusds.openid.connect.sdk.UserInfoResponse;
+import com.nimbusds.openid.connect.sdk.UserInfoSuccessResponse;
+import com.nimbusds.openid.connect.sdk.rp.OIDCClientInformationResponse;
+import com.nimbusds.openid.connect.sdk.token.OIDCTokens;
+
+import net.shibboleth.idp.plugin.oidc.op.decoding.impl.RequestUtil;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.impl.OAuth2RevocationErrorResponse;
+import net.shibboleth.idp.plugin.oidc.op.oauth2.messaging.impl.OAuth2RevocationSuccessResponse;
/** Response logging helper class. */
public final class ResponseUtil {
@@ -88,4 +115,252 @@ public final class ResponseUtil {
return ret;
}
+ /**
+ * Helper method for getting protocol message for a Nimbus response object. This method can currently
+ * recognize success and error responses for OIDC authentication, token, userinfo, introspetion and
+ * revocation.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessage(@Nullable final Response response) {
+ if (response == null) {
+ return null;
+ }
+ if (response instanceof AuthenticationResponse) {
+ return getProtocolMessageForAuthenticationResponse((AuthenticationResponse) response);
+ } else if (response instanceof OIDCClientInformationResponse) {
+ return getProtocolMessageForRegistrationResponse((OIDCClientInformationResponse) response);
+ } else if (response instanceof TokenResponse) {
+ return getProtocolMessageForTokenResponse((TokenResponse) response);
+ } else if (response instanceof UserInfoResponse) {
+ return getProtocolMessageForUserInfoResponse((UserInfoResponse) response);
+ } else if (response instanceof TokenIntrospectionResponse) {
+ return getProtocolMessageForIntrospectionResponse((TokenIntrospectionResponse) response);
+ } else if (response instanceof OAuth2RevocationSuccessResponse) {
+ return getProtocolMessageForRevocationResponse(response);
+ } else if (response instanceof OAuth2RevocationErrorResponse) {
+ return getProtocolMessageForRevocationResponse(response);
+ } else if (response instanceof ErrorResponse) {
+ final ErrorResponse genericError = (ErrorResponse) response;
+ return MoreObjects.toStringHelper(genericError).omitNullValues()
+ .add("errorObject", genericError.getErrorObject())
+ .toString();
+ }
+ return MoreObjects.toStringHelper(response).toString();
+ }
+
+ /**
+ * Helper method for getting protocol message for OIDC authentication response.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessageForAuthenticationResponse(
+ @Nonnull final AuthenticationResponse response) {
+ if (response.indicatesSuccess()) {
+ final AuthenticationSuccessResponse successResponse = response.toSuccessResponse();
+ return MoreObjects.toStringHelper(successResponse).omitNullValues()
+ .add("accessToken", RequestUtil.getAccessTokenLog(successResponse.getAccessToken()))
+ .add("authorizationCode", successResponse.getAuthorizationCode())
+ .add("idToken", successResponse.getIDToken() == null ?
+ null : successResponse.getIDToken().serialize())
+ .add("issuer", successResponse.getIssuer())
+ .add("jwtResponse", successResponse.getJWTResponse() == null ?
+ null : successResponse.getJWTResponse().serialize())
+ .add("redirectionURI", successResponse.getRedirectionURI())
+ .add("responseMode", successResponse.getResponseMode())
+ .add("sessionState", successResponse.getSessionState())
+ .add("state", successResponse.getState())
+ .toString();
+ } else {
+ final AuthenticationErrorResponse errorResponse = response.toErrorResponse();
+ return MoreObjects.toStringHelper(errorResponse).omitNullValues()
+ .add("errorObject", getProtocolMessageForErrorObject(errorResponse.getErrorObject()))
+ .add("issuer", errorResponse.getIssuer())
+ .add("jwtResponse", errorResponse.getJWTResponse() == null ?
+ null : errorResponse.getJWTResponse().serialize())
+ .add("redirectionURI", errorResponse.getRedirectionURI())
+ .add("responseMode", errorResponse.getResponseMode())
+ .add("state", errorResponse.getState())
+ .toString();
+ }
+ }
+
+ /**
+ * Helper method for getting protocol message for OIDC registration response.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessageForRegistrationResponse(
+ @Nonnull final OIDCClientInformationResponse response) {
+ if (response.indicatesSuccess()) {
+ final ClientInformationResponse successResponse = response.toSuccessResponse();
+ return MoreObjects.toStringHelper(successResponse).omitNullValues()
+ .add("clientInformation",
+ getProtocolMessageForClientInformation(successResponse.getClientInformation()))
+ .toString();
+ } else {
+ final ClientRegistrationErrorResponse errorResponse = response.toErrorResponse();
+ return MoreObjects.toStringHelper(errorResponse).omitNullValues()
+ .add("errorObject", getProtocolMessageForErrorObject(errorResponse.getErrorObject()))
+ .toString();
+ }
+ }
+
+ /**
+ * Helper method for getting protocol message for client information object.
+ *
+ * @param clientInformation The client information
+ * @return The log message
+ */
+ @Nullable public static String getProtocolMessageForClientInformation(
+ @Nullable final ClientInformation clientInformation) {
+ return clientInformation == null ? null : MoreObjects.toStringHelper(clientInformation).omitNullValues()
+ .add("clientId", clientInformation.getID())
+ .add("idIssuedDate", clientInformation.getIDIssueDate())
+ .add("metadadata", clientInformation.getMetadata())
+ .add("registrationAccessToken",
+ RequestUtil.getAccessTokenLog(clientInformation.getRegistrationAccessToken()))
+ .add("registrationURI", clientInformation.getRegistrationURI())
+ .add("secret", clientInformation.getSecret() == null ? null : "<secret>")
+ .toString();
+ }
+
+ /**
+ * Helper method for getting protocol message for token response.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessageForTokenResponse(@Nonnull final TokenResponse response) {
+ if (response.indicatesSuccess()) {
+ final AccessTokenResponse successResponse = response.toSuccessResponse();
+ return MoreObjects.toStringHelper(successResponse).omitNullValues()
+ .add("customParameters", successResponse.getCustomParameters())
+ .add("tokens", successResponse.getTokens())
+ .toString();
+ } else {
+ final TokenErrorResponse errorResponse = response.toErrorResponse();
+ return MoreObjects.toStringHelper(errorResponse).omitNullValues()
+ .add("errorObject", getProtocolMessageForErrorObject(errorResponse.getErrorObject()))
+ .toString();
+ }
+ }
+
+ /**
+ * Helper method for getting protocol message for error object.
+ *
+ * @param errorObject The error object
+ * @return The log message
+ */
+ @Nullable public static String getProtocolMessageForErrorObject(@Nullable final ErrorObject errorObject) {
+ return errorObject == null ? null : MoreObjects.toStringHelper(errorObject).omitNullValues()
+ .add("httpStatusCode", errorObject.getHTTPStatusCode())
+ .add("code", errorObject.getCode())
+ .add("description", errorObject.getDescription())
+ .add("uri", errorObject.getURI())
+ .toString();
+ }
+
+ /**
+ * Helper method for getting protocol message for tokens object.
+ *
+ * @param tokens The tokens object
+ * @return The log message
+ */
+ @Nullable public static String getProtocolMessageForTokens(@Nullable final Tokens tokens) {
+ final String idToken = tokens instanceof OIDCTokens ? MoreObjects.toStringHelper(OIDCTokens.class)
+ .omitNullValues()
+ .add("idToken", tokens.toOIDCTokens().getIDToken() == null ? null :
+ tokens.toOIDCTokens().getIDToken().serialize())
+ .toString() : null;
+ return tokens == null ? null : MoreObjects.toStringHelper(tokens).omitNullValues()
+ .add("accessToken", tokens.getAccessToken())
+ .add("metadata", tokens.getMetadata())
+ .add("parameterNames", tokens.getParameterNames())
+ .add("refreshToken", tokens.getRefreshToken())
+ .add("idToken", idToken)
+ .toString();
+ }
+
+ /**
+ * Helper method for getting protocol message for OIDC user info response.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessageForUserInfoResponse(@Nonnull final UserInfoResponse response) {
+ if (response.indicatesSuccess()) {
+ final UserInfoSuccessResponse successResponse = response.toSuccessResponse();
+ return MoreObjects.toStringHelper(successResponse).omitNullValues()
+ .add("entityContentType", successResponse.getEntityContentType())
+ .add("userInfo", successResponse.getUserInfo() != null ?
+ successResponse.getUserInfo().toJSONString() : null)
+ .add("userInfoJWT", successResponse.getUserInfoJWT() == null ? null :
+ successResponse.getUserInfoJWT().serialize())
+ .toString();
+ } else {
+ final UserInfoErrorResponse errorResponse = response.toErrorResponse();
+ return MoreObjects.toStringHelper(errorResponse).omitNullValues()
+ .add("errorObject", errorResponse.getErrorObject())
+ .toString();
+ }
+ }
+
+ /**
+ * Helper method for getting protocol message for introspection response.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessageForIntrospectionResponse(
+ @Nonnull final TokenIntrospectionResponse response) {
+ if (response.indicatesSuccess()) {
+ final TokenIntrospectionSuccessResponse successResponse = response.toSuccessResponse();
+ return MoreObjects.toStringHelper(successResponse).omitNullValues()
+ .add("active", successResponse.isActive())
+ .add("audience", successResponse.getAudience())
+ .add("clientId", successResponse.getClientID())
+ .add("expirationTime", successResponse.getExpirationTime())
+ .add("issuer", successResponse.getIssuer())
+ .add("issueTime", successResponse.getIssueTime())
+ .add("jwtId", successResponse.getJWTID())
+ .add("notBeforeTime", successResponse.getNotBeforeTime())
+ .add("parameters", successResponse.getParameters())
+ .add("scope", successResponse.getScope())
+ .add("jwkThumbprintConfirmation", successResponse.getJWKThumbprintConfirmation())
+ .add("subject", successResponse.getSubject())
+ .add("tokenType", successResponse.getTokenType())
+ .add("username", successResponse.getUsername())
+ .toString();
+ } else {
+ final TokenIntrospectionErrorResponse errorResponse = response.toErrorResponse();
+ return MoreObjects.toStringHelper(errorResponse).omitNullValues()
+ .add("errorObject", errorResponse.getErrorObject())
+ .toString();
+ }
+ }
+
+ /**
+ * Helper method for getting protocol message for revocation response.
+ *
+ * @param response The response message
+ * @return The response message specific log message
+ */
+ @Nullable public static String getProtocolMessageForRevocationResponse(@Nonnull Response response) {
+ if (response instanceof OAuth2RevocationSuccessResponse) {
+ final OAuth2RevocationSuccessResponse successResponse = (OAuth2RevocationSuccessResponse) response;
+ return MoreObjects.toStringHelper(successResponse).omitNullValues().toString();
+ }
+ if (response instanceof OAuth2RevocationErrorResponse) {
+ final OAuth2RevocationErrorResponse errorResponse = (OAuth2RevocationErrorResponse) response;
+ return MoreObjects.toStringHelper(errorResponse).omitNullValues()
+ .add("errorObject", errorResponse.getErrorObject())
+ .toString();
+ } else {
+ return null;
+ }
+ }
}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/BaseOAuth2RequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/BaseOAuth2RequestDecoder.java
new file mode 100644
index 00000000..bc611fe7
--- /dev/null
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/BaseOAuth2RequestDecoder.java
@@ -0,0 +1,76 @@
+/*
+ * 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.plugin.oidc.op.oauth2.decoding.impl;
+
+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 org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import com.nimbusds.oauth2.sdk.Request;
+
+/**
+ * Base decoder for Nimbus OAuth2 request messages.
+ *
+ * @param <T> The exact type of the request message, extends {@link Request}.
+ */
+public abstract class BaseOAuth2RequestDecoder<T extends Request> extends AbstractHttpServletRequestMessageDecoder {
+
+ /** Class logger. */
+ @Nonnull
+ private final Logger log = LoggerFactory.getLogger(BaseOAuth2RequestDecoder.class);
+
+ /** Used to log protocol messages. */
+ @Nonnull private final Logger protocolMessageLog = LoggerFactory.getLogger("PROTOCOL_MESSAGE.OAUTH2");
+
+ /** {@inheritDoc} */
+ @Override
+ protected void doDecode() throws MessageDecodingException {
+ final MessageContext messageContext = new MessageContext();
+ final T requestMessage = parseMessage();
+ messageContext.setMessage(requestMessage);
+ setMessageContext(messageContext);
+ if (protocolMessageLog.isDebugEnabled() ){
+ final String message = getMessageToLog(requestMessage);
+ if (message == null) {
+ log.warn("Decoded protocol log message was null, nothing to log");
+ return;
+ }
+ protocolMessageLog.debug(message);
+ }
+ }
+
+ /**
+ * Parses the message into the exact type of the request message.
+ *
+ * @return The request message
+ * @throws MessageDecodingException if there is a problem decoding the message context
+ */
+ @Nullable protected abstract T parseMessage() throws MessageDecodingException;
+
+ /**
+ * Get the string representation of what will be logged as the protocol message.
+ *
+ * @return the string representing the protocol message for logging purposes
+ */
+ @Nullable protected abstract String getMessageToLog(final T message);
+}
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2IntrospectionRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2IntrospectionRequestDecoder.java
index b3909797..2294a0b4 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2IntrospectionRequestDecoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2IntrospectionRequestDecoder.java
@@ -19,13 +19,13 @@ package net.shibboleth.idp.plugin.oidc.op.oauth2.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.MessageDecodingException;
-import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import com.google.common.base.MoreObjects;
import com.nimbusds.oauth2.sdk.TokenIntrospectionRequest;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.ServletUtils;
@@ -35,7 +35,7 @@ import net.shibboleth.idp.plugin.oidc.op.decoding.impl.RequestUtil;
/**
* Message decoder decoding OpenID Connect {@link TokenIntrospectionRequest}s.
*/
-public class OAuth2IntrospectionRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+public class OAuth2IntrospectionRequestDecoder extends BaseOAuth2RequestDecoder<TokenIntrospectionRequest> {
/** Class logger. */
@Nonnull
@@ -43,19 +43,27 @@ public class OAuth2IntrospectionRequestDecoder extends AbstractHttpServletReques
/** {@inheritDoc} */
@Override
- protected void doDecode() throws MessageDecodingException {
- final MessageContext messageContext = new MessageContext();
- TokenIntrospectionRequest req = null;
+ protected TokenIntrospectionRequest parseMessage() throws MessageDecodingException {
try {
final HTTPRequest httpReq = ServletUtils.createHTTPRequest(getHttpServletRequest());
log.debug("Inbound request {}", RequestUtil.toString(httpReq));
- req = TokenIntrospectionRequest.parse(httpReq);
+ return TokenIntrospectionRequest.parse(httpReq);
} catch (final com.nimbusds.oauth2.sdk.ParseException | IOException e) {
log.error("Unable to decode inbound request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
- messageContext.setMessage(req);
- setMessageContext(messageContext);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(final @Nullable TokenIntrospectionRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("token", message.getToken())
+ .add("customParameters", message.getCustomParameters())
+ .add("clientAuthentication", RequestUtil.getClientAuthenticationLog(message.getClientAuthentication()))
+ .add("clientAuthorization", RequestUtil.getAccessTokenLog(message.getClientAuthorization()))
+ .add("endpointURI", message.getEndpointURI())
+ .toString();
}
}
\ No newline at end of file
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2RevocationRequestDecoder.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2RevocationRequestDecoder.java
index 3ffe7c5a..12d37b19 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2RevocationRequestDecoder.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/decoding/impl/OAuth2RevocationRequestDecoder.java
@@ -19,12 +19,13 @@ package net.shibboleth.idp.plugin.oidc.op.oauth2.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.MessageDecodingException;
-import org.opensaml.messaging.decoder.servlet.AbstractHttpServletRequestMessageDecoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+
+import com.google.common.base.MoreObjects;
import com.nimbusds.oauth2.sdk.TokenRevocationRequest;
import com.nimbusds.oauth2.sdk.http.HTTPRequest;
import com.nimbusds.oauth2.sdk.http.ServletUtils;
@@ -34,7 +35,7 @@ import net.shibboleth.idp.plugin.oidc.op.decoding.impl.RequestUtil;
/**
* Message decoder decoding OpenID Connect {@link TokenRevocationRequest}s.
*/
-public class OAuth2RevocationRequestDecoder extends AbstractHttpServletRequestMessageDecoder {
+public class OAuth2RevocationRequestDecoder extends BaseOAuth2RequestDecoder<TokenRevocationRequest> {
/** Class logger. */
@Nonnull
@@ -42,19 +43,26 @@ public class OAuth2RevocationRequestDecoder extends AbstractHttpServletRequestMe
/** {@inheritDoc} */
@Override
- protected void doDecode() throws MessageDecodingException {
- final MessageContext messageContext = new MessageContext();
- TokenRevocationRequest req = null;
+ protected TokenRevocationRequest parseMessage() throws MessageDecodingException {
try {
final HTTPRequest httpReq = ServletUtils.createHTTPRequest(getHttpServletRequest());
log.debug("Inbound request {}", RequestUtil.toString(httpReq));
- req = TokenRevocationRequest.parse(httpReq);
+ return TokenRevocationRequest.parse(httpReq);
} catch (final com.nimbusds.oauth2.sdk.ParseException | IOException e) {
log.error("Unable to decode inbound request: {}", e.getMessage());
throw new MessageDecodingException(e);
}
- messageContext.setMessage(req);
- setMessageContext(messageContext);
+ }
+
+ /** {@inheritDoc} */
+ @Override
+ protected String getMessageToLog(final @Nullable TokenRevocationRequest message) {
+ return message == null ? null : MoreObjects.toStringHelper(this).omitNullValues()
+ .add("token", message.getToken())
+ .add("clientId", message.getClientID())
+ .add("clientAuthentication", RequestUtil.getClientAuthenticationLog(message.getClientAuthentication()))
+ .add("endpointURI", message.getEndpointURI())
+ .toString();
}
}
\ 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