I'm trying to validate the RS256 token that I receive upon successful user authorization on the AD server.
I am looking at the id_token property value of the response.
Here's what I have -
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();
}
This is the exception I get -
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
I've tried using the jjwt library for this, but that doesn't seem to work either. I've tried to get the modulus and the exponent from the public keys posted on the endpoint to construct my own key object in java and then use it to validate the signature.
Any help is much appreciated!