.NET Core and Azure Active Directory integration

2019-08-01 03:21发布

I am using the token authentication (instead of cookie) with Azure Active Directory.

Based on this article: https://www.itunity.com/article/angular-2-openid-connect-azure-active-directory-3093

I was able to get it working on the client side.

   public validateSignature(token): Observable<boolean> {
        /* Retrieve from federated metadata endpoint.
        In this sample, the document was downloaded locally */
        return this.httpService.get("metadata/metadata.xml")
            .map((res: Response) => {
                let dom = (new DOMParser()).parseFromString(res.text(), "text/xml");
                let json = xml2json(dom, "");
                let cert = "-----BEGIN CERTIFICATE-----" + 
                JSON.parse(json).EntityDescriptor[0]["ds:Signature"]
                    ["KeyInfo"]["X509Data"]["X509Certificate"] + 
                 "-----END CERTIFICATE-----";
                 let key = KEYUTIL.getKey(cert);
                return KJUR.jws.JWS.verifyJWT(token, key, { alg: ['RS256'] });
            })
        } 

I was trying to re-implement the above method in the .NET Core 1.0.3.

Based on this article: how to sign and verify signature with net and a certificate

The following line won't compile on .NET Core:

RSACryptoServiceProvider csp = (RSACryptoServiceProvider)cert.PublicKey.Key;

I am not sure what is correct way to verify the token based on the certificate in .NET Core.

2条回答
ゆ 、 Hurt°
2楼-- · 2019-08-01 03:55

An easy way to verify the token issued by Azure AD is leverage the OWIN comment with web API. We just need to config the JwtBearerOptions and send the request to a controller which protected by Azure AD. If the token is not verified, you will get the 401 response. You can refer the code sample here.

And if you want to implement the code to verify the token manually, we can refer the code how the Microsoft verify the token in Microsoft.AspNetCore.Authentication.JwtBearer.

I also wrote a code sample for your reference:

public class JsonWebTokenValidator
{
    public void Validate(string token)
    {
        var stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
        var options = new JwtBearerOptions
        {
            ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint, new OpenIdConnectConfigurationRetriever()),

            TokenValidationParameters = new Microsoft.IdentityModel.Tokens.TokenValidationParameters()
            {
                ValidateIssuer = true,
                ValidIssuer = "https://sts.windows.net/{tenantId}/",

                ValidateAudience = true,
                ValidAudience = "{audience}",

                RequireExpirationTime = true,
                ValidateLifetime = true,

                ValidateIssuerSigningKey = true,

                ClockSkew = TimeSpan.Zero
            },
            Authority = "https://login.microsoftonline.com/{tenantId}",
        };

        SecurityToken validatedToken = null;
        ClaimsPrincipal result = null;
        var configuration = options.ConfigurationManager.GetConfigurationAsync(new CancellationToken()).Result;
        options.TokenValidationParameters.IssuerSigningKeys = configuration.SigningKeys;

        options.ConfigurationManager.RequestRefresh();
        foreach (var validators in options.SecurityTokenValidators)
        {
            result = validators.ValidateToken(token, options.TokenValidationParameters, out validatedToken);
        }

        foreach (var claim in result.Claims)
        {
            Console.WriteLine($"{claim.Subject}:{claim.Value}");
        }
    }

Project.json

{
  "version": "1.0.0-*",
  "buildOptions": {
    "emitEntryPoint": true
  },

  "dependencies": {
    "Microsoft.IdentityModel.Clients.ActiveDirectory": "3.13.9",
    "Microsoft.NETCore.App": {
      "type": "platform",
      "version": "1.0.1"
    },

    "System.IdentityModel.Tokens.Jwt": {
      "version": "5.1.3"
    },
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0",
    "Microsoft.IdentityModel.Protocols": "2.1.3",
    "Microsoft.IdentityModel.Protocols.OpenIdConnect": "2.0.0"
  },

  "frameworks": {
    "netcoreapp1.0": {
      "imports": "dnxcore50"
    }
  }
}
查看更多
smile是对你的礼貌
3楼-- · 2019-08-01 03:59

According to this QA: implement RSA in .NET core your cert object should have a GetRSAPublicKey() method which returns an RSA object - just be sure to wrap it in using as it's IDisposable.

static bool Verify(string text, byte[] signature, string certPath)
{
    X509Certificate2 cert = new X509Certificate2( certPath );

    using( RSA rsa = cert.GetRSAPublicKey() )
    using( SHA1Managed sha1 = new SHA1Managed() )
    {
        byte[] data = Encoding.Unicode.GetBytes( text );
        byte[] hash = sha1.ComputeHash( data );

        return rsa.VerifyHash( hash, CryptoConfig.MapNameToOID("SHA1"), signature );
    }
}

Apparently GetRSAPublicKey() is defined as an extension method: https://msdn.microsoft.com/en-us/library/system.security.cryptography.x509certificates.rsacertificateextensions.getrsapublickey(v=vs.110).aspx

查看更多
登录 后发表回答