[java-idp-oidc] branch maint-4.3 updated: JOIDC-286 - Improve logging for expired sealed tokens

Codeberg noreply at shibboleth.net
Thu Sep 10 06:52:44 UTC 2026


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

codeberg pushed a commit to branch maint-4.3
in repository java-idp-oidc.

View the commit online:
https://codeberg.org/Shibboleth/java-idp-oidc/commit/c2c3814f4860fbaddf0647c0bb21f4645d1b1dd9

The following commit(s) were added to refs/heads/maint-4.3 by this push:
     new c2c3814f JOIDC-286 - Improve logging for expired sealed tokens
c2c3814f is described below

commit c2c3814f4860fbaddf0647c0bb21f4645d1b1dd9
Author: Henri Mikkonen <henri.mikkonen at iki.fi>
AuthorDate: Thu Sep 10 09:34:58 2026 +0300

    JOIDC-286 - Improve logging for expired sealed tokens
    
    https://shibboleth.atlassian.net/browse/JOIDC-286
    
    Catch DataExpiredException before DataSealerException and log it appropriately
    
    Imported the change manually from UnwrapGrant (main branch) into ValidateGrant (maint-4.3), as JOIDC-255 had modified the structure.
---
 .../oidc/op/oauth2/profile/impl/AbstractProcessTokenAction.java  | 9 ++++++++-
 .../idp/plugin/oidc/op/profile/impl/ValidateGrant.java           | 5 +++++
 .../oidc/op/profile/impl/ValidateRegistrationAccessToken.java    | 5 +++++
 .../logic/DefaultJwtRefreshTokenDeserializationFunction.java     | 3 +++
 ...aultPushedAuthorizationRequestUriDeserializationFunction.java | 3 +++
 .../security/jwt/claims/impl/DPoPProofNonceClaimsValidator.java  | 4 ++++
 .../plugin/oidc/op/userinfo/profile/impl/ParseAccessToken.java   | 5 +++++
 7 files changed, 33 insertions(+), 1 deletion(-)

diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractProcessTokenAction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractProcessTokenAction.java
index 36d7a890..e71624e3 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractProcessTokenAction.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/oauth2/profile/impl/AbstractProcessTokenAction.java
@@ -59,6 +59,7 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.resolver.CriteriaSet;
 import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -268,6 +269,8 @@ public abstract class AbstractProcessTokenAction<T> extends AbstractOIDCRequestA
                     return null;
                 }
             }
+        } catch (final DataExpiredException e) {
+            log.warn("{} Sealed data within the JWT access token has expired", getLogPrefix(), e);
         } catch (final DataSealerException | ParseException e) {
             
         }
@@ -278,6 +281,8 @@ public abstract class AbstractProcessTokenAction<T> extends AbstractOIDCRequestA
             assert tokenValue != null;
             assert dataSealer != null;
             return AccessTokenClaimsSet.parse(tokenValue, dataSealer).getClaimsSet();
+        } catch (final DataExpiredException e) {
+            log.info("{} Opaque access token has expired", getLogPrefix(), e);
         } catch (final DataSealerException | ParseException e) {
             
         }
@@ -300,7 +305,9 @@ public abstract class AbstractProcessTokenAction<T> extends AbstractOIDCRequestA
             assert refreshToken != null;
             assert dataSealer != null;
             return RefreshTokenClaimsSet.parse(refreshToken, dataSealer).getClaimsSet();
-        } catch (ParseException | DataSealerException e) {
+        } catch (final DataExpiredException e) {
+            log.info("{} Opaque refresh token has expired", getLogPrefix(), e);
+        } catch (final ParseException | DataSealerException e) {
         }
         for (final BiFunction<ProfileRequestContext, String, RefreshTokenClaimsSet> deserializer : 
             refreshTokenDeserializers) {
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java
index c884911d..e0d8da36 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateGrant.java
@@ -63,6 +63,7 @@ import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -326,6 +327,10 @@ public class ValidateGrant extends AbstractOIDCTokenResponseAction {
                         }
                     }
                     tokenClaimsSet = authzCodeClaimsSet;
+                } catch (final DataExpiredException e) {
+                    log.info("{} Incoming authorization code has expired", getLogPrefix());
+                    ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+                    return;
                 } catch (final DataSealerException | ParseException e) {
                     log.warn("{} Unwrapping authz code failed: {}", getLogPrefix(), e.getMessage());
                     ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRegistrationAccessToken.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRegistrationAccessToken.java
index 2b16ecb1..b791775e 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRegistrationAccessToken.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/impl/ValidateRegistrationAccessToken.java
@@ -42,6 +42,7 @@ 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;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -198,6 +199,10 @@ public class ValidateRegistrationAccessToken extends AbstractOIDCRequestAction<O
             final String unwrapped = dataSealer.unwrap(accessToken);
             log.debug("{} Access token unwrapped into {}", getLogPrefix(), unwrapped);
             claimsSet = objectMapper.readValue(unwrapped, RegistrationClaimsSet.class);
+        } catch (final DataExpiredException e) {
+            log.warn("{} Decoding access token failed: token has expired", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
+            return;
         } catch (final DataSealerException | JsonProcessingException e) {
             log.error("{} Decoding access token failed: {}", getLogPrefix(), e);
             ActionSupport.buildEvent(profileRequestContext, OidcEventIds.INVALID_GRANT);
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultJwtRefreshTokenDeserializationFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultJwtRefreshTokenDeserializationFunction.java
index 38761b0b..a77e34cd 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultJwtRefreshTokenDeserializationFunction.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultJwtRefreshTokenDeserializationFunction.java
@@ -47,6 +47,7 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.resolver.CriteriaSet;
 import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -212,6 +213,8 @@ public class DefaultJwtRefreshTokenDeserializationFunction extends AbstractIniti
             }
             assert dataSealer != null;
             return RefreshTokenClaimsSet.parse(sealedClaimsSet, dataSealer);
+        } catch (final DataExpiredException e) {
+            log.warn("Could not decrypt the sealed claims set: the data has expired", e);
         } catch (final ParseException | DataSealerException e) {
             log.warn("Could not decrypt the sealed claims set", e);
         }
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultPushedAuthorizationRequestUriDeserializationFunction.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultPushedAuthorizationRequestUriDeserializationFunction.java
index 89de84ac..b4976808 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultPushedAuthorizationRequestUriDeserializationFunction.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/profile/logic/DefaultPushedAuthorizationRequestUriDeserializationFunction.java
@@ -37,6 +37,7 @@ import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.primitive.StringSupport;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -154,6 +155,8 @@ public class DefaultPushedAuthorizationRequestUriDeserializationFunction
                     return null;
                 }
                 return result;
+            } catch (final DataExpiredException e) {
+                log.info("The contents of the requst_uri has expired: {}", uri.toString(), e);
             } catch (final DataSealerException e) {
                 log.debug("Could not decrypt the contents of the request_uri {}", uri.toString(), e);
                 return null;
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/DPoPProofNonceClaimsValidator.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/DPoPProofNonceClaimsValidator.java
index 85fb559b..d900da38 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/DPoPProofNonceClaimsValidator.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/security/jwt/claims/impl/DPoPProofNonceClaimsValidator.java
@@ -40,6 +40,7 @@ import net.shibboleth.shared.annotation.constraint.ThreadSafeAfterInit;
 import net.shibboleth.shared.component.ComponentInitializationException;
 import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -160,6 +161,9 @@ public class DPoPProofNonceClaimsValidator extends AbstractClaimsValidator {
                 log.warn("Relying party IDs don't match: resolved '{}', nonce contained '{}'", rpId, rpIdClaim);
                 throw new DPoPProofNonceJWTValidationException("Relying party IDs don't match");
             }
+        } catch (final DataExpiredException e) {
+            log.debug("Could not unwrap the nonce data: data has expired");
+            throw new DPoPProofNonceJWTValidationException("Could not unwrap the nonce data: data has expired");
         } catch (final DataSealerException e) {
             log.trace("Could not unwrap the nonce data", e);
             throw new DPoPProofNonceJWTValidationException("Could not unwrap the nonce data");
diff --git a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/userinfo/profile/impl/ParseAccessToken.java b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/userinfo/profile/impl/ParseAccessToken.java
index 19376af8..51680f51 100644
--- a/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/userinfo/profile/impl/ParseAccessToken.java
+++ b/idp-oidc-extension-impl/src/main/java/net/shibboleth/idp/plugin/oidc/op/userinfo/profile/impl/ParseAccessToken.java
@@ -46,6 +46,7 @@ import net.shibboleth.shared.logic.Constraint;
 import net.shibboleth.shared.primitive.LoggerFactory;
 import net.shibboleth.shared.resolver.CriteriaSet;
 import net.shibboleth.shared.resolver.ResolverException;
+import net.shibboleth.shared.security.DataExpiredException;
 import net.shibboleth.shared.security.DataSealer;
 import net.shibboleth.shared.security.DataSealerException;
 
@@ -215,6 +216,8 @@ public class ParseAccessToken extends AbstractOIDCUserInfoValidationResponseActi
             assert signedJWT != null;
             assert dataSealer != null;
             return AccessTokenClaimsSet.parse(signedJWT, dataSealer);
+        } catch (final DataExpiredException e) {
+            log.warn("{} Sealed data within the JWT access token has expired", getLogPrefix(), e);
         } catch (final DataSealerException | ParseException e) {
             
         }
@@ -223,6 +226,8 @@ public class ParseAccessToken extends AbstractOIDCUserInfoValidationResponseActi
         try {
             assert dataSealer != null;
             return AccessTokenClaimsSet.parse(tokenValue, dataSealer);
+        } catch (final DataExpiredException e) {
+            log.info("{} Opaque access token has expired", getLogPrefix(), e);
         } catch (final DataSealerException | ParseException e) {
             
         }

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


More information about the commits mailing list