在Java中验证Azure AD JWT id_token

时间:2016-11-16 20:25:48

标签: java active-directory oauth-2.0 authorization azure-active-directory

我正在尝试验证在AD服务器上成功用户授权后收到的RS256令牌。

我正在查看响应的id_token属性值。

这就是我所拥有的 -

String[] split_string = idToken.split("\\.");
String base64EncodedHeader = split_string[0];
String base64EncodedBody = split_string[1];
String base64EncodedSignature = split_string[2];
Base64 base64Url = new Base64(true);
String header = new String(base64Url.decode(base64EncodedHeader));
JSONObject jsonObjHeader = JSONObject.fromObject(header);
String body = new String(base64Url.decode(base64EncodedBody));
JSONObject jsonObjBody = JSONObject.fromObject(body);
String signatre = new String(base64Url.decode(base64EncodedSignature));

//kid for signature validation
String kid = jsonObjHeader.getString("kid");

//open-id-config endpoint
String openIdConfigEndPoint = "https://login.microsoftonline.com/{tenantID}/.well-known/openid-configuration";
OAuthRequest requestOpenId = constructOAuthRequest(
                    openIdConfigEndPoint, oauthNonce, oauthTimestamp, Verb.GET);
Response responseOpenId = requestOpenId.send();
String openIdString = responseOpenId.getBody();
JSONObject jsonObjopenId = JSONObject.fromObject(openIdString);

String keysEndPoint = jsonObjopenId.getString("jwks_uri");
OAuthRequest requestkeysEndPoint = constructOAuthRequest(keysEndPoint,
                    oauthNonce, oauthTimestamp, Verb.GET);
Response responsekeysEndPoint = requestkeysEndPoint.send();
String keysEndPointString = responsekeysEndPoint.getBody();
JSONObject jsonKeysEndPointString = JSONObject.fromObject(keysEndPointString);

JSONArray keysEndPointArray = jsonKeysEndPointString.getJSONArray("keys");
String x5t = null;
String n = null;
String e = null;        
for (int i = 0; i < keysEndPointArray.size(); i++) {
    JSONObject obj1 = keysEndPointArray.getJSONObject(i);
    if (obj1.getString("kid").equals(kid)) {

        n = obj1.getString("n");
        e = obj1.getString("e");
        x5t = obj1.getString("x5t");                
    }

}

byte[] modulusBytes = Base64.decodeBase64(n.getBytes("UTF-8"));
byte[] exponentBytes = Base64.decodeBase64(e.getBytes("UTF-8"));

BigInteger modulusInt = new BigInteger(1, modulusBytes);
BigInteger exponentInt = new BigInteger(1, exponentBytes);

try {
    Signature signature = Signature.getInstance("SHA256withRSA");
    RSAPublicKeySpec publicSpec = new RSAPublicKeySpec(modulusInt, exponentInt);

    KeyFactory keyFactory = KeyFactory.getInstance("RSA");
    PublicKey pubKey = keyFactory.generatePublic(publicSpec);

    signature.initVerify(pubKey);
    signature.update(base64Url.decode(base64EncodedBody));

    boolean isVerified = signature.verify(base64Url .decode(base64EncodedSignature));
    // isVerified is false , should be true on successful validation
} catch (Exception ex) {
    ex.printStackTrace();
}

//trying with JJWT


try {
    KeyFactory factory = KeyFactory.getInstance("RSA");
    PublicKey pub = factory.generatePublic(publicSpec);
    Jwt<Header, String> c = Jwts.parser().setSigningKey(pub).parsePlaintextJwt(idToken);
    System.out.println();
} catch (Exception e1) {
    e1.printStackTrace();
}

这是我得到的例外 -

io.jsonwebtoken.SignatureException: Unable to verify RSA signature using configured PublicKey. Signature length not correct: got 255 but was expecting 256
    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:339)
    at io.jsonwebtoken.impl.DefaultJwtParser.parse(DefaultJwtParser.java:458)
    at io.jsonwebtoken.impl.DefaultJwtParser.parsePlaintextJwt(DefaultJwtParser.java:480)
    at edu.umn.faip.web.spring.controller.OAuthSSOTestController.referenceData(OAuthSSOTestController.java:221)
    at org.springframework.web.servlet.mvc.SimpleFormController.referenceData(SimpleFormController.java:214)
    at org.springframework.web.servlet.mvc.AbstractFormController.showForm(AbstractFormController.java:574)
    at org.springframework.web.servlet.mvc.SimpleFormController.showForm(SimpleFormController.java:198)
    at org.springframework.web.servlet.mvc.SimpleFormController.showForm(SimpleFormController.java:175)
    at org.springframework.web.servlet.mvc.AbstractFormController.showNewForm(AbstractFormController.java:338)
    at org.springframework.web.servlet.mvc.AbstractFormController.handleRequestInternal(AbstractFormController.java:278)
    at org.springframework.web.servlet.mvc.AbstractController.handleRequest(AbstractController.java:153)
    at org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter.handle(SimpleControllerHandlerAdapter.java:48)
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:875)
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:807)
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:571)
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:501)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:310)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.security.SignatureException: Signature length not correct: got 255 but was expecting 256
    at sun.security.rsa.RSASignature.engineVerify(Unknown Source)
    at java.security.Signature$Delegate.engineVerify(Unknown Source)
    at java.security.Signature.verify(Unknown Source)
    at io.jsonwebtoken.impl.crypto.RsaSignatureValidator.doVerify(RsaSignatureValidator.java:63)
    at io.jsonwebtoken.impl.crypto.RsaSignatureValidator.isValid(RsaSignatureValidator.java:47)
    ... 38 more

我尝试过使用jjwt库,但这似乎也不起作用。我试图从端点上发布的公钥中获取模数和指数,以在java中构建我自己的密钥对象,然后使用它来验证签名。

非常感谢任何帮助!

1 个答案:

答案 0 :(得分:0)

您可以尝试

signature.update((split_string[0]+ "." +  
                  split_string[0]).getBytes(StandardCharsets.UTF_8)); 

OpenID Connect - how to verify id token in Java?

您可以参考此链接。它对我有用。