使用pac4j向login.gov请求令牌失败:client_assertion含null的iat声明
问题
我尝试使用pac4j oidc-client对接login.gov进行认证,相关安全配置如下:
oidcConfiguration.setDiscoveryURI("https://idp.int.identitysandbox.gov/.well-known/openid-configuration"); oidcConfiguration.setClientId(clientId); oidcConfiguration.setUseNonce(true); oidcConfiguration.setResponseType("code"); oidcConfiguration.setScope("openid"); // Load private key from PEM file ClassLoader classLoader = getClass().getClassLoader(); File pkFile = new File(classLoader.getResource("private.pem").getFile()); var privateKey = readPKCS8PrivateKey(pkFile); var privateKeyJwtConfig = new PrivateKeyJWTClientAuthnMethodConfig(JWSAlgorithm.RS256, privateKey); oidcConfiguration.setPrivateKeyJWTClientAuthnMethodConfig(privateKeyJwtConfig); oidcConfiguration.addCustomParam("acr_values", "http://idmanagement.gov/ns/assurance/ial/1"); oidcConfiguration.addCustomParam("prompt", "select_account"); oidcConfiguration.addCustomParam("client_assertion_type","urn:ietf:params:oauth:client-assertion-type:jwt-bearer"); oidcConfiguration.setClientAuthenticationMethod(ClientAuthenticationMethod.PRIVATE_KEY_JWT); oidcConfiguration.setStateGenerator(new RandomValueGenerator(28)); oidcConfiguration.setWithState(true); oidcConfiguration.setPreferredJwsAlgorithm(JWSAlgorithm.RS256); oidcConfiguration.setSecret("bogus");
注:即使login.gov配置中未设置密钥,设置一个secret才能让发送到令牌端点的请求包含client_assertion。
pac4j发送的client_assertion负载中包含null的iat声明,导致令牌端点返回错误并抛出异常:
JEE PAC4J DEMO 17:53:54.491 [qtp1990828041-45] DEBUG o.p.core.engine.DefaultCallbackLogic - extracted credentials: OidcCredentials(code=e45f8b5b-d039-4c0d-9c75-f6251568fb80, accessToken=null, refreshToken=null, idToken=null) [WARNING] /callback org.pac4j.oidc.exceptions.OidcTokenException: Bad token response, error=Client assertion iat must be an integer or floating point Unix timestamp representing a time in the past, description=null, status=400 at org.pac4j.oidc.credentials.authenticator.OidcAuthenticator.executeTokenRequest(OidcAuthenticator.java:120) at org.pac4j.oidc.credentials.authenticator.OidcAuthenticator.validate(OidcAuthenticator.java:65) at org.pac4j.core.client.BaseClient.internalValidateCredentials(BaseClient.java:113) at org.pac4j.core.client.BaseClient.validateCredentials(BaseClient.java:95) at org.pac4j.core.engine.DefaultCallbackLogic.perform(DefaultCallbackLogic.java:83) at org.pac4j.jee.filter.CallbackFilter.internalFilter(CallbackFilter.java:63) at org.pac4j.jee.config.AbstractConfigFilter.doFilter(AbstractConfigFilter.java:92) at org.eclipse.jetty.servlet.FilterHolder.doFilter(FilterHolder.java:210) at org.eclipse.jetty.servlet.ServletHandler$Chain.doFilter(ServletHandler.java:1635) at org.eclipse.jetty.websocket.servlet.WebSocketUpgradeFilter.doFilter(WebSocketUpgradeFilter.java:170)
pac4j发送的client_assertion负载如下,其中iat声明为null:
{ "sub": "urn:gov:gsa:openidconnect.profiles:sp:sso:doi:quicktime_9996", "aud": "https://idp.int.identitysandbox.gov/api/openid_connect/token", "nbf": null, "iss": "urn:gov:gsa:openidconnect.profiles:sp:sso:doi:quicktime_9996", "exp": 1717804013, "iat": null, "jti": "mspXEErL5LUDuO-x5IUmTYDB679lA0TyYPYIT6d2_xg" }
如何让pac4j生成的iat声明为当前系统时间戳而非null?
解决方案
为PrivateKeyJWTClientAuthnMethodConfig配置自定义JWT生成器,强制生成iat声明:
- 创建
DefaultJwtGenerator实例并开启iat声明生成 - 将生成器绑定到私钥JWT认证配置中
修改后的关键代码如下:
// 加载私钥逻辑保持不变 ClassLoader classLoader = getClass().getClassLoader(); File pkFile = new File(classLoader.getResource("private.pem").getFile()); var privateKey = readPKCS8PrivateKey(pkFile); // 配置JWT生成器,强制包含iat声明 DefaultJwtGenerator jwtGenerator = new DefaultJwtGenerator(); jwtGenerator.setIncludeIssuedAt(true); // 开启iat生成 jwtGenerator.setIncludeNotBefore(true); // 可选,若需要生成nbf声明 // 绑定生成器到私钥认证配置 var privateKeyJwtConfig = new PrivateKeyJWTClientAuthnMethodConfig(JWSAlgorithm.RS256, privateKey); privateKeyJwtConfig.setJwtGenerator(jwtGenerator); // 后续配置保持不变 oidcConfiguration.setPrivateKeyJWTClientAuthnMethodConfig(privateKeyJwtConfig); // ... 其他原有配置
另外,若使用的pac4j版本较旧,升级至最新稳定版也可能解决默认不生成iat的问题。
内容的提问来源于stack exchange,提问作者Eduardo
相关产品推荐
相关产品推荐

