2

Я изо всех сил пытаюсь проверить подпись маркера Azure AD.Неподтвержденная подпись подписей Azure AD JAVA

Когда я смотрю на правильный ключ описание в поле «jwks_uri» под

https://login.microsoftonline.com/common/.well-known/openid-configuration

Я проверить принадлежность ключевых данных.

Я пытаюсь использовать «N» - модуль упругости и «е» поля для создания открытого ключа для проверки подписи я в конечном итоге с ошибкой:

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<Header, String> c = Jwts.parser().setSigningKey(pubKey).parsePlaintextJwt(token); 

} catch (Exception ex) { 
    ex.printStackTrace(); 
} 

консоли:

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) 

Я попробовал другой подход использовать «x5c», поданный, который является базой 64 кодируются серта цепь:

byte[] certChain = Base64.getDecoder().decode(x5c); 
X509Certificate cert = X509CertUtils.parse(certChain); 
PublicKey pubKeyNew = cert.getPublicKey(); 
Claims claims3 = Jwts.parser() 
      .setSigningKey(pubKeyNew) 
      .parseClaimsJws(token).getBody(); 

я в конечном итоге с другой ошибкой:

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) 

Может кто-нибудь знать, что я делаю неправильно? Спасибо.

+0

Вы пытались использовать библиотеку ADAL, указанную в библиотеках, официально рекомендованных Майкрософт здесь: https://docs.microsoft.com/en-us/azure/active-directory/active-directory-authentication-libraries –

ответ

2

Первый пример

Modulus и экспонент (n и e) в https://login.microsoftonline.com/common/discovery/keys кодируются в base64url, а не в base64, поэтому код для декодирования их должно быть

byte[] modulusBytes = Base64.getUrlDecoder().decode(n); 
BigInteger modulusInt = new BigInteger(1, modulusBytes); 

Не используйте старые com.sun.misc.BASE64Decoder

Если JWT подписан, вы не должны использовать JWTParser.plaintextJwt(). По documentation

plaintextJwt: a compact serialized unsigned plaintext JWT string

использовать вместо parseClaimsJws или parsePlaintextJws. Второй метод, только если полезная нагрузка представляет собой строку, не JSON

Второй пример

второй пример, в основном правильно. Я предполагаю, что X509CertUtils.parse(certChain) похож на

InputStream in = new ByteArrayInputStream(certChain); 
CertificateFactory certFactory = CertificateFactory.getInstance("X.509"); 
X509Certificate cert = (X509Certificate)certFactory.generateCertificate(in); 

Modulus и показатель сертификата те же, что декодируется, поэтому открытый ключ эквивалентен

Есть два аналогичных сертификатов в ссылке, проверьте оба. Вы должны иметь возможность проверить подпись. Если нет, то токен не подписан с этими ключами.

+0

Вы правы, второй подход правильный. Проблема в том, что azure вернул id_token и токен доступа. Проверка корректна с id_token и не выполняется с помощью токена доступа. Как говорится в документации на https://docs.microsoft.com/en-us/azure/active-directory/active-directory-v2-tokens: «[...] токены доступа, выпущенные конечной точкой v2.0, могут использоваться только службами Microsoft. Ваши приложения не должны для выполнения любой проверки [...]. " «В настоящее время единственной проверкой маркера, которую должны выполнять ваши приложения, является проверка идентификационных маркеров ID». – HDCase

Смежные вопросы