web-dev-qa-db-ja.com

Java aws cognito APIのJWTの検証の例はありますか?

Aws cognitoユーザープールを使用しています。ユーザーがサインインした後、シングルページアプリケーションでIDトークンを取得しました。これは予期されていることです。その後、リクエストごとに、JavaのバックエンドRESTAPIでIDトークンを確認する必要があります。 、awsdocはそれを行う方法についてあまり言及していませんでした。

その例はありますか?

混乱は次のとおりです。

  1. idトークンは署名されたJWTだけでなく、暗号化されているようです。ニンバスライブラリを使用する場合、暗号化されたJWTのシークレットを指定する必要があります。シークレットはどこで入手できますか?私の理解では、これはawsから取得する必要があります。何かをダウンロードしてから、jvmキーストアに配置する必要がありますか?

  2. よく知られているjwts.jsonがawsからダウンロードできます。次のようになります。

`

{
    "keys": [
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "HFPWHdsrG5WyulOwH5dai69YTsWz2KBB1NHbAcVx7M0=",
            "kty": "RSA",
            "n": "...",
            "use": "sig"
        },
        {
            "alg": "RS256",
            "e": "AQAB",
            "kid": "kSwTdVq/qD4Ra4Q8dJqUTlvOA7eiLxezOZ3mJKI61zU=",
            "kty": "RSA",
            "n": "....",
            "use": "sig"
        }
    ]
}

`

これを理解する方法、各プロパティは何に使用されますか?ユーザープール内のすべてのユーザーが1つのキーを表すということですか?

  1. Java aws cognitoサービス検証のコードの例はありますか?aws sdkを使用できますか、それともnimbusなどのライブラリを使用して自分で検証を行う必要がありますか?
12
Jakim

私はこれに苦労し、それを共有しようと思いました。

Mavenを使用する場合は、これをpom.xmlに追加してください

<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>Java-jwt</artifactId>
    <version>3.3.0</version>
</dependency>
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>jwks-rsa</artifactId>
    <version>0.4.0</version>
</dependency>

Gradleを使用する場合は、

compile 'com.auth0:jwks-rsa:0.4.0'
compile 'com.auth0:Java-jwt:3.3.0'

RSAKeyProviderを実装するクラスを作成します

import com.auth0.jwk.Jwk;
import com.auth0.jwk.JwkProvider;
import com.auth0.jwk.JwkProviderBuilder;
import com.auth0.jwt.interfaces.RSAKeyProvider;

import Java.net.MalformedURLException;
import Java.net.URL;
import Java.security.interfaces.RSAPrivateKey;
import Java.security.interfaces.RSAPublicKey;

public class AwsCognitoRSAKeyProvider implements RSAKeyProvider {

    private final URL aws_kid_store_url;

    public AwsCognitoRSAKeyProvider(String aws_cognito_region, String aws_user_pools_id) {
        String url = String.format("https://cognito-idp.%s.amazonaws.com/%s/.well-known/jwks.json", aws_cognito_region, aws_user_pools_id);
        try {
            this.aws_kid_store_url = new URL(url);
        } catch (MalformedURLException e) {
            throw new RuntimeException(String.format("Invalid URL provided, URL=%s", url));
        }
    }


    @Override
    public RSAPublicKey getPublicKeyById(String kid) {
        try {
            JwkProvider provider = new JwkProviderBuilder(aws_kid_store_url).build();
            Jwk jwk = provider.get(kid);
            return (RSAPublicKey) jwk.getPublicKey();
        } catch (Exception e) {
            throw new RuntimeException(String.format("Failed to get JWT kid=%s from aws_kid_store_url=%s", kid, aws_kid_store_url));
        }
    }

    @Override
    public RSAPrivateKey getPrivateKey() {
        return null;
    }

    @Override
    public String getPrivateKeyId() {
        return null;
    }
}

これで、トークンを確認できます。

String aws_cognito_region = "us-east-1"; // Replace this with your aws cognito region
String aws_user_pools_id = "us-east-1_7DEw1nt5r"; // Replace this with your aws user pools id
RSAKeyProvider keyProvider = new AwsCognitoRSAKeyProvider(aws_cognito_region, aws_user_pools_id);
Algorithm algorithm = Algorithm.RSA256(keyProvider);
JWTVerifier jwtVerifier = JWT.require(algorithm)
    //.withAudience("2qm9sgg2kh21masuas88vjc9se") // Validate your apps audience if needed
    .build();

String token = "eyJraWQiOiJjdE.eyJzdWIiOiI5NTMxN2E.VX819z1A1rJij2"; // Replace this with your JWT token
jwtVerifier.verify(token);

JwkProviderBuilderは、awsキーストアから取得したキーをキャッシュするLRUキャッシュを備えたJwkProviderを構築することに注意してください。これは非常に優れています。キャッシュルールはビルダーで変更できます。

16
AndiDev

秘密については、App Client固有のものを参照していますか?これは、AppClientを作成するときに取得します。 AWSコンソールとCognitoに移動します。適切なユーザープールを選択し、[アプリクライアント]をクリックします。秘密はありますが、App Clientを作成するときに、作成するオプションを選択する(または使用しない)ようにする必要があります。それ以外の場合は、新しいものを作成します。

0
chris2187

標準の JWTライブラリ を使用してトークンを検証できます。さらに、JWTトークンの検証にはいくつかの手順が含まれます。 Javaの例は見つかりませんでしたが、以下は検証プロセスを説明するNodeJSの例です。

const jwt = require('jsonwebtoken');
const jwtToken = "sampletoken****";
const jwkPem = { "alg" : "RS256", "kid" : "samplekid****" }

var decodedJwt = jwt.decode(jwtToken, {complete: true});

//Fail if the token is not jwt
if (!decodedJwt) {
    console.log("Not a valid JWT token");
    return;
}

//Fail if token is not from your User Pool
if (decodedJwt.payload.iss != iss) {
    console.log("invalid issuer");
    return;
}

//Reject the jwt if it's not an 'Access Token'
if (!(decodedJwt.payload.token_use == 'id' || 
    decodedJwt.payload.token_use == 'access')) {
    console.log("token_use is invalid");
    return;
}

//Get the kid from the token and retrieve corresponding PEM
var kid = decodedJwt.header.kid;
var pem = jwkPem[kid];
if (!pem) {
    console.log("Invalid access token");
    return;
}

//Verify the signature of the JWT token to ensure it's really coming from your User Pool and that it has not expired
jwt.verify(jwtToken, pem, { issuer: iss, maxAge: 3600000}, function(err, payload) {
  if(err) {
    console.log(err);
  } else {
    console.log("Authorization successful");
  }
});
0
Ashan