Azure Public Keys解释了什么?

时间:2016-11-24 05:56:31

标签: azure azure-active-directory

我正在更新我的应用程序以将Azure Active Directory用作OAuth 2.0身份验证服务器。目前,我成功使用授权代码授权类型并接收access_token和id_token值。

现在,我正在尝试验证返回的id_token。我遵循doco中列出的步骤,我能够找到用于签署JWT的公钥。例如,这是Azure REST端点返回的记录

Returned Public Keys

据我了解,这些是可用的公钥。我可以将其过滤为一个(使用返回的JWT标头中的kid值)。但我正在努力理解的是每个领域的意义。

我是否使用n / e字段为SHA256公钥创建模数和指数值?我的意思是使用x5c值吗?很抱歉,如果这是一个显而易见的问题,但是有任何文档,给定的值如上所述,如何为它创建公钥?我在Java中这样做,所以任何特定的东西都会非常感激。

2 个答案:

答案 0 :(得分:1)

这是一个类似的question我发布并获得了帮助,这可能有所帮助。我想你想使用x5c,这是完整的证书链,并从中获取公钥来验证你的JWT的签名。模数和指数(n和e)将只生成证书链中第一个证书的公钥,但这不足以验证签名。

以下是我用于从端点提取公钥的一些代码段。 AzurePublicKey类只是json的POJO。

private PublicKey convertKey(AzurePublicKey azKey) {
    PublicKey publicKey = null;

    BigInteger modulus = new BigInteger(1, Base64.getUrlDecoder().decode(azKey.getN()));
    BigInteger exponent = new BigInteger(1, Base64.getUrlDecoder().decode(azKey.getE()));

    try {
        publicKey = KeyFactory.getInstance("RSA").generatePublic(new RSAPublicKeySpec(modulus, exponent));

        // load cert
        CertificateFactory factory;
        X509Certificate cert = null; 
        try {
            factory = CertificateFactory.getInstance("X.509");
            cert = (X509Certificate) factory.generateCertificate(new ByteArrayInputStream(DatatypeConverter.parseBase64Binary(azKey.getX5c().iterator().next())));
        } catch (CertificateException e) {
            e.printStackTrace();
        }

        // grab public key
        publicKey = (RSAPublicKey)cert.getPublicKey();

        System.out.println("[");
        System.out.println("kid : " + azKey.getKeyIdentifier());
        System.out.println("e : " + azKey.getE());
        System.out.println("n : " + azKey.getN());

        System.out.println("Maybe this : " + DatatypeConverter.printBase64Binary(publicKey.getEncoded()) );
        System.out.println("]");

    } catch (InvalidKeySpecException | NoSuchAlgorithmException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    return publicKey;
}

使用该公钥来使用JJWT库验证签名的代码。

Jws<Claims> claims = Jwts.parser()
                                .setSigningKeyResolver(signingKeyResolver)
                                .parseClaimsJws(token.replace(TOKEN_PREFIX, ""));


        String issuer   = claims.getBody().getIssuer();
        if(issuer == null || !VALID_ISSUERS.contains(issuer))
            throw new IncorrectClaimException(claims.getHeader(), claims.getBody(), "Invalid Issuer in Token.", new Throwable("Invalid Issuer in Token."));

SigningKeyResolverImpl只根据令牌标头的kid提供正确的公钥。如果解析没有抛出异常,您可以针对您期望的值验证令牌声明,因为我已根据我期待的VALID_ISSUERS列表验证了此处的发布者。

已经有一段时间了,所以我很模糊,但我希望这会有所帮助。

答案 1 :(得分:0)

要验证id_token的签名,如果您使用C#进行开发,我们可以使用JwtSecurityTokenHandler类。您可以将JsonWebTokenValidator.cs引用代码示例以使用此类。为方便起见,我也在这里复制这个课程:

 public class JsonWebTokenValidator
{
    public JwtSecurityToken Validate(string token)
    {
        string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";

        ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint);

        OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;

        TokenValidationParameters validationParameters = new TokenValidationParameters
        {
            ValidateAudience = false,
            ValidateIssuer = false,
            IssuerSigningTokens = config.SigningTokens,
            ValidateLifetime = false
        };

        JwtSecurityTokenHandler tokendHandler = new JwtSecurityTokenHandler();

        SecurityToken jwt;

        var result = tokendHandler.ValidateToken(token, validationParameters, out jwt);

        return jwt as JwtSecurityToken;
    }
}