java异步验证签名失败,验证Azure AD令牌签名失败JAVA

I am struggling to validate an Azure AD token signature.

When I look up the correct key description in the "jwks_uri" field under

I check the belonging key data .

I try to use the "n" - modulus and "e" fields to generate the public key for the signature validation I end up with an error:

BASE64Decoder decoder = new BASE64Decoder();

byte[] modulusBytes = decoder.decodeBuffer(n);

byte[] exponentBytes = decoder.decodeBuffer(e);

BigInteger modulusInt = new BigInteger(1, modulusBytes);

BigInteger exponentInt = new BigInteger(1, exponentBytes);

try {

KeyFactory keyFactory = KeyFactory.getInstance("RSA");

RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(modulusInt, exponentInt);

RSAPublicKey pubKey = (RSAPublicKey)keyFactory.generatePublic(publicSpec);

Jwt c = Jwts.parser().setSigningKey(pubKey).parsePlaintextJwt(token);

} catch (Exception ex) {

ex.printStackTrace();

}

Console:

io.jsonwebtoken.SignatureException: Unable to verify RSA signature using configured PublicKey. Signature length not correct: got 256 but was expecting 246

at io.jsonwebtoken.impl.crypto.RsaSignatureValidator.isValid(RsaSignatureValidator.java:50)

at io.jsonwebtoken.impl.crypto.DefaultJwtSignatureValidator.isValid(DefaultJwtSignatureValidator.java:47)

at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:351)

at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481)

at io.jsonwebtoken.impl.DefaultJwtParser.parsePlaintextJwt(DefaultJwtParser.java:503)

at com.ge.hc.pfh.poc.ams.filter.JwtFilter.doFilter(JwtFilter.java:120)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at com.ge.hc.pfh.poc.ams.filter.ApiOriginFIlter.doFilter(ApiOriginFIlter.java:28)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at com.ge.hc.pfh.poc.ams.filter.MDCFilter.doFilter(MDCFilter.java:34)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)

at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784)

at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)

at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410)

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

at java.lang.Thread.run(Thread.java:745)

I tried another approach to use the "x5c" filed which is a base 64 encoded cert chain:

byte[] certChain = Base64.getDecoder().decode(x5c);

X509Certificate cert = X509CertUtils.parse(certChain);

PublicKey pubKeyNew = cert.getPublicKey();

Claims claims3 = Jwts.parser()

.setSigningKey(pubKeyNew)

.parseClaimsJws(token).getBody();

I end up with an other error:

io.jsonwebtoken.SignatureException: JWT signature does not match locally computed signature. JWT validity cannot be asserted and should not be trusted.

at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:354)

at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:481)

at io.jsonwebtoken.impl.DefaultJwtParser.parsePlaintextJwt(DefaultJwtParser.java:503)

at com.ge.hc.pfh.poc.ams.filter.JwtFilter.doFilter(JwtFilter.java:106)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at com.ge.hc.pfh.poc.ams.filter.ApiOriginFIlter.doFilter(ApiOriginFIlter.java:28)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at com.ge.hc.pfh.poc.ams.filter.MDCFilter.doFilter(MDCFilter.java:34)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.HttpPutFormContentFilter.doFilterInternal(HttpPutFormContentFilter.java:89)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:77)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:197)

at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192)

at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165)

at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198)

at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108)

at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)

at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)

at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79)

at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)

at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:349)

at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:784)

at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)

at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:802)

at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1410)

at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)

at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)

at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)

at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

at java.lang.Thread.run(Thread.java:745)

Would anyone know what I am doing wrong?

Thanks.

解决方案

First example

Modulus and Exponent (n and e) in https://login.microsoftonline.com/common/discovery/keys are encoded in base64url and not in base64, so the code to decode them should be

byte[] modulusBytes = Base64.getUrlDecoder().decode(n);

BigInteger modulusInt = new BigInteger(1, modulusBytes);

Do not use old com.sun.misc.BASE64Decoder

If the JWT is signed you should not use JWTParser.plaintextJwt(). According to documentation

plaintextJwt: a compact serialized unsigned plaintext JWT string

Use instead parseClaimsJws or parsePlaintextJws. The second method only if the payload is a string non-JSON

Second example

The second example is basically right. I assume X509CertUtils.parse(certChain) is similar to

InputStream in = new ByteArrayInputStream(certChain);

CertificateFactory certFactory = CertificateFactory.getInstance("X.509");

X509Certificate cert = (X509Certificate)certFactory.generateCertificate(in);

Modulus and exponent of the certificate are the same that the decoded, so public key is equivalent

There are two similar certificates in the link, check both. You should be able to validate the signature. If not, then the token is not signed with those keys

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值