2017-06-26 29 views
1

JavaでOpenID Connectを正常に実装しました。残っている部分だけがid_tokenの検証済みです。私はbase64を使用してid_tokenをデコードし、ユーザーの電子メールと名前を取得しました。今私はそのユーザーの詳細を使用できるようにid_tokenを検証したいと思います。 id_tokenの検証に誰も助けてくれますか?ライブラリを使用しないでid_tokenを検証する方法

私が検証するために、コードの下にしようとしているid_token

import java.math.BigInteger; 
import java.nio.charset.StandardCharsets; 
import java.security.GeneralSecurityException; 
import java.security.KeyFactory; 
import java.security.PublicKey; 
import java.security.Signature; 
import java.security.spec.RSAPublicKeySpec; 
import org.apache.commons.codec.binary.Base64; 

public class ValidateIdToken { 
    public static final String id_token = "eyJhbGciOiJSUzI1NiIsImtpZCI6IjRlMjVjMTQ2Y2Y4NmU2MGM4ODYxNDdlYWQyNzBlYzAxYTllODU1YTEifQ.eyJhenAiOiIyODQzNDYxNzE1OTEtMGxtOGphamkwOW9iMzNuM2h1bXRrOXYyMzczcjgxcnEuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJhdWQiOiIyODQzNDYxNzE1OTEtMGxtOGphamkwOW9iMzNuM2h1bXRrOXYyMzczcjgxcnEuYXBwcy5nb29nbGV1c2VyY29udGVudC5jb20iLCJzdWIiOiIxMDk0NjgzNjY4OTQ1NjQwMDU3MzgiLCJoZCI6ImluZm9vYmplY3RzLmNvbSIsImVtYWlsIjoia2lzaG9yZS5zdXRoYXJAaW5mb29iamVjdHMuY29tIiwiZW1haWxfdmVyaWZpZWQiOnRydWUsImF0X2hhc2giOiJod255SGc0dnlrOTZXVUxZYktyRTl3IiwiaXNzIjoiaHR0cHM6Ly9hY2NvdW50cy5nb29nbGUuY29tIiwiaWF0IjoxNDk4NDc5MDIyLCJleHAiOjE0OTg0ODI2MjIsIm5hbWUiOiJLaXNob3JlIFN1dGhhciIsInBpY3R1cmUiOiJodHRwczovL2xoNS5nb29nbGV1c2VyY29udGVudC5jb20vLXJNb3kzeEpfRHA4L0FBQUFBQUFBQUFJL0FBQUFBQUFBQUFBL0FJNnlHWHp5WXdoeXMtU0FwVnhodDBJbTFOQktlYXpZa0Evczk2LWMvcGhvdG8uanBnIiwiZ2l2ZW5fbmFtZSI6Iktpc2hvcmUiLCJmYW1pbHlfbmFtZSI6IlN1dGhhciIsImxvY2FsZSI6ImVuIn0.iWJquu48swut8denWospcnOu-0QpQjWrw7d_K7lDdtwJ6xo6zE1rnmoOHw1xxeWrE9e2Vy-AqJ4mLHYn3rGoRe026oWLvwQMAgcNmhBENwvd9kAbYZukg_J7Ypy2Srnsu97u0q-QTAs3MBmxO0Yp2bHwuR5gmwEvTaE6gTtSZOf_Tg5FyrqaZgdrBuXxxLvQqHsNXIp4MxthxBtAH1kGo_KBrVAoKH1dRkKzsjSlt73nB_uKODGe2FoUwrNybItp9t5xE653pnxp2L6rbLJ2U9TU3gGSQ5yDdWPMt-AIAGJ7d1WOIHHGpN9FcT3KYEueS0j0h6Kfktr5XCCYnuEwQg"; 
    public static final String[] id_token_parts = id_token.split("\\."); 

    public static final String MODULUS = "5SGw1jcqyFYEZaf39RoxAhlq-hfRSOsneVtsT2k09yEQhwB2myvf3ckVAwFyBF6y0Hr1psvu1FlPzKQ9YfcQkfge4e7eeQ7uaez9mMQ8RpyAFZprq1iFCix4XQw-jKW47LAevr9w1ttZY932gFrGJ4gkf_uqutUny82vupVUETpQ6HDmIL958SxYb_-d436zi5LMlHnTxcR5TWIQGGxip-CrD7vOA3hrssYLhNGQdwVYtwI768EvwE8h4VJDgIrovoHPH1ofDQk8-oG20eEmZeWugI1K3z33fZJS-E_2p_OiDVr0EmgFMTvPTnQ75h_9vyF1qhzikJpN9P8KcEm8oGu7KJGIn8ggUY0ftqKG2KcWTaKiirFFYQ981PhLHryH18eOIxMpoh9pRXf2y7DfNTyid99ig0GUH-lzAlbKY0EV2sIuvEsIoo6G8YT2uI72xzl7sCcp41FS7oFwbUyHp_uHGiTZgN7g-18nm2TFmQ_wGB1xCwJMFzjIXq1PwEjmg3W5NBuMLSbG-aDwjeNrcD_4vfB6yg548GztQO2MpV_BuxtrZDJQm-xhJXdm4FfrJzWdwX_JN9qfsP0YU1_mxtSU_m6EKgmwFdE3Yh1WM0-kRRSk3gmNvXpiKeVduzm8I5_Jl7kwLgBw24QUVaLZn8jC2xWRk_jcBNFFLQgOf9U"; 
    public static final String EXPONENT = "AQAB"; 

    public static final String ID_TOKEN_HEADER = base64UrlDecode(id_token_parts[0]); 
    public static final String ID_TOKEN_PAYLOAD = base64UrlDecode(id_token_parts[1]); 
    public static final byte[] ID_TOKEN_SIGNATURE = base64UrlDecodeToBytes(id_token_parts[2]); 

    public static String base64UrlDecode(String input) { 
     byte[] decodedBytes = base64UrlDecodeToBytes(input); 
     String result = new String(decodedBytes, StandardCharsets.UTF_8); 
     return result; 
    } 

    public static byte[] base64UrlDecodeToBytes(String input) { 
     Base64 decoder = new Base64(-1, null, true); 
     byte[] decodedBytes = decoder.decode(input); 

     return decodedBytes; 
    } 

    public static void main(String args[]) { 
     validateToken(); 
    } 

    public static void validateToken() { 
     PublicKey publicKey = getPublicKey(MODULUS, EXPONENT); 
     byte[] data = (id_token_parts[0] + "." + id_token_parts[1]).getBytes(StandardCharsets.UTF_8); 

     try { 
      boolean isSignatureValid = verifyUsingPublicKey(data, ID_TOKEN_SIGNATURE, publicKey); 
      System.out.println("isSignatureValid: " + isSignatureValid); 
     } catch (GeneralSecurityException e) { 
      e.printStackTrace(); 
     } 

    } 

    public static PublicKey getPublicKey(String MODULUS, String EXPONENT) { 
     byte[] nb = base64UrlDecodeToBytes(MODULUS); 
     byte[] eb = base64UrlDecodeToBytes(EXPONENT); 
     BigInteger n = new BigInteger(1, nb); 
     BigInteger e = new BigInteger(1, eb); 

     RSAPublicKeySpec rsaPublicKeySpec = new RSAPublicKeySpec(n, e); 
     try { 
      PublicKey publicKey = KeyFactory.getInstance("RSA").generatePublic(rsaPublicKeySpec); 

      return publicKey; 
     } catch (Exception ex) { 
      throw new RuntimeException("Cant create public key", ex); 
     } 
    } 

    private static boolean verifyUsingPublicKey(byte[] data, byte[] signature, PublicKey pubKey) 
      throws GeneralSecurityException { 
     Signature sig = Signature.getInstance("SHA256withRSA"); 
     sig.initVerify(pubKey); 
     sig.update(data); 

     return sig.verify(signature); 
    } 
} 

エラー

java.security.SignatureException: Signature length not correct: got 256 but was expecting 512 
    at sun.security.rsa.RSASignature.engineVerify(RSASignature.java:189) 
    at java.security.Signature$Delegate.engineVerify(Signature.java:1219) 
    at java.security.Signature.verify(Signature.java:652) 
    at com.certain.sso.handler.ValidateIdToken.verifyUsingPublicKey(ValidateIdToken.java:75) 
    at com.certain.sso.handler.ValidateIdToken.validateToken(ValidateIdToken.java:45) 
    at com.certain.sso.handler.ValidateIdToken.main(ValidateIdToken.java:37) 
+0

あなたが使っているプログラミング言語と、Nimbusや他のライブラリでどのような問題があったかについての情報を追加してください。 –

+0

@JánHalaša更新された質問 – lucy

+0

MODULUSとEXPONENTから公開鍵を作成しようとしましたが、MODULUS値が無効なBase64文字列であるようです。私は 'java.util.Base64.getDecoder()。decode(MODULUS)'から 'Illegal base64 character 2d'を取得します。 –

答えて

0

Javaの例外が正しく計算されていないあなたの署名によるものである: "HS256" ALGパラメータあなたのIDトークンヘッダーでは、単にSHA-256ハッシュを計算し、それをRSA秘密鍵で「暗号化」し、それをbase64でエンコードしてIDトークンの最後に入力する必要があるということを意味しません。

HS256は、RFC-8017で完全に指定されているPKCS#1「SHA256withRSA」アルゴリズムを使用する必要があることを意味します。このRFCによれば、署名はRSA係数と同じ長さのオクテットでなければならない。あなたのRSAモジュラスは512バイト長ですから、IDトークンの署名部分は512バイト長でなければなりません。ハッシュ関数(HMAC-SHA256)が256ビット長の値を返すとしても。

したがって、RFC-8017では256ビット長のHMAC-SHA256ハッシュから512バイトの長さのシグネチャを計算するために、I2OSPの整数 - オクテット文字列プリミティブを使用する必要があります。 、整数512(あなたのRSAモジュラスの長さ)です。 I2OSPは512バイト長のオクテット文字列を出力します。これは最終的にパラメータとしてsig.verify()に渡す必要があります。

関連する問題