NPE in checkAndBindMtlsHoKToken on Token Refresh when using SuppressRefreshTokenRotationExecutor and Certificate Bound Token
tnorimat opened this issue · comments
Before reporting an issue
- I have read and understood the above terms for submitting issues, and I understand that my issue may be closed without action if I do not follow them.
Area
oidc
Describe the bug
When using both SuppressRefreshTokenRotationExecutor and Certificate Bound Token, checkAndBindMtlsHoKToken method occurs NPE on Token Refresh request.
Due to the issue, Keycloak 23.0.0 cannnot pass conformace tests (Test Name: fapi1-advanced-final-refresh-token) of Open Finance Brasil FAPI 1.0 (Open Banking Brasil FAPI 1.0 was renamed).
Version
23.0.0
Expected behavior
When using both SuppressRefreshTokenRotationExecutor and Certificate Bound Token, checkAndBindMtlsHoKToken method does not occur NPE on Token Refresh request and returns a token response without a refreshed refresh token.
Actual behavior
When using both SuppressRefreshTokenRotationExecutor and Certificate Bound Token, checkAndBindMtlsHoKToken method occurs NPE on Token Refresh request.
How to Reproduce?
- Apply to a client Certificate Bound Token by HolderOfKeyEnforcerExecutor
- Apply to the client SuppressRefreshTokenRotationExecutor
- The client sends a token request with a X.509 client certificate and receive a token response with a certificate-bound access and refresh tokens.
- The client sends a token refresh request with the X.509 client certificate
Anything else?
No response
In TokenEndpoint.refreshTokenGrant
,
session.clientPolicy().triggerOnEvent(new TokenRefreshResponseContext(formParams, responseBuilder));
checkAndBindMtlsHoKToken(responseBuilder, clientConfig.isUseRefreshToken());
checkAndBindDPoPToken(responseBuilder, clientConfig.isUseRefreshToken() && (client.isPublicClient() || client.isBearerOnly()), Profile.isFeatureEnabled(Profile.Feature.DPOP));
should be
checkAndBindMtlsHoKToken(responseBuilder, clientConfig.isUseRefreshToken());
checkAndBindDPoPToken(responseBuilder, clientConfig.isUseRefreshToken() && (client.isPublicClient() || client.isBearerOnly()), Profile.isFeatureEnabled(Profile.Feature.DPOP));
session.clientPolicy().triggerOnEvent(new TokenRefreshResponseContext(formParams, responseBuilder));