wake-up-neo.com

So überprüfen Sie das Azure AD-Sicherheitstoken

Der folgende Code gibt mir Azure AD security token. Ich muss überprüfen, ob das Token gültig ist oder nicht. Wie kann ich das erreichen?

// Get OAuth token using client credentials 
string tenantName = "mytest.onmicrosoft.com";
string authString = "https://login.microsoftonline.com/" + tenantName;

AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);

// Config for OAuth client credentials  
string clientId = "fffff33-6666-4888-a4tt-fbttt44444";
string key = "123v47o=";
ClientCredential clientCred = new ClientCredential(clientId, key);
string resource = "http://mytest.westus.cloudapp.Azure.com";
string token;

Task<AuthenticationResult> authenticationResult = authenticationContext.AcquireTokenAsync(resource, clientCred);
token = authenticationResult.Result.AccessToken;
Console.WriteLine(token);
// How can I validate this token inside my service?                
12
Neo

Es gibt zwei Schritte, um das Token zu überprüfen. Überprüfen Sie zunächst die Signatur des Token, um sicherzustellen, dass das Token von Azure Active Directory ausgegeben wurde. Zweitens überprüfen Sie die Ansprüche im Token basierend auf der Geschäftslogik. 

Beispielsweise müssen wir den Anspruch iss und aud überprüfen, wenn Sie eine einzelne Tenant-App entwickeln. Sie müssen auch nbf überprüfen, um sicherzustellen, dass das Token nicht abgelaufen ist. Weitere Ansprüche können Sie hier beziehen. 

Die folgende Beschreibung stammt von hier über die Details der Signaturprüfung. (Hinweis: Im folgenden Beispiel wird der Endpunkt Azure AD V2 verwendet. Sie sollten den Endpunkt verwenden, der dem von der Client-App verwendeten Endpunkt entspricht.)

Das Zugriffstoken von Azure AD ist ein JSON-Web Token (JWT), das vom Security Token-Dienst in einem privaten Schlüssel signiert wird.

Das JWT besteht aus 3 Teilen: Header, Daten und Signatur. Technisch können wir den öffentlichen Schlüssel verwenden, um das Zugriffstoken zu überprüfen.

Erster Schritt - Abrufen und Zwischenspeichern der gesungenen Token (öffentlicher Schlüssel)

Endpunkt: https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration

Dann können wir mit JwtSecurityTokenHandler das Token anhand des folgenden Beispielcodes überprüfen:

 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;
 }

Wenn Sie die OWIN-Komponenten in Ihrem Projekt verwendet haben, ist es einfacher, das Token zu überprüfen. Wir können den Code unten verwenden, um das Token zu überprüfen:

app.UseWindowsAzureActiveDirectoryBearerAuthentication(
            new WindowsAzureActiveDirectoryBearerAuthenticationOptions
            {
                Audience = ConfigurationManager.AppSettings["ida:Audience"],
                Tenant = ConfigurationManager.AppSettings["ida:Tenant"]
            });

Dann können wir den Code unten verwenden, um den Gültigkeitsbereich des Tokens zu überprüfen:

public IEnumerable<TodoItem> Get()
{
    // user_impersonation is the default permission exposed by applications in AAD
    if (ClaimsPrincipal.Current.FindFirst("http://schemas.Microsoft.com/identity/claims/scope").Value != "user_impersonation")
    {
        throw new HttpResponseException(new HttpResponseMessage {
          StatusCode = HttpStatusCode.Unauthorized,
          ReasonPhrase = "The Scope claim does not contain 'user_impersonation' or scope claim not found"
        });
    }
    ...
}

Und hier ist ein Codebeispiel, das die Web-API mit Azure AD geschützt hat:

Schützen einer Web-API mithilfe von Bearer-Token vor Azure AD

18
Fei Xue

Ich wollte nur die Antwort von Fei für Benutzer von .net Core 2.0 hinzufügen

Sie müssen 2 Zeilen der Validate(string token)-Methode ändern.

ConfigurationManager<OpenIdConnectConfiguration> configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint
, new OpenIdConnectConfigurationRetriever()); //need the 'new OpenIdConnect...'

...
 TokenValidationParameters validationParameters = new TokenValidationParameters
 {
     ValidateAudience = true,
     ValidateIssuer = true,
     IssuerSigningKeys = config.SigningKeys, //.net core calls it "IssuerSigningKeys" and "SigningKeys"
     ValidateLifetime = true
 };
4
Ambrose Leung

Wenn Sie jedoch nicht OWIN in Ihren Projekten verwenden, wird dies ein wenig schwierig oder zumindest zeitaufwändig sein ... Dieser Artikel Hier ist eine großartige Ressource.

Und da ich nicht viel hinzufügen muss, abgesehen von dem ausführlichen Code. Hier ist etwas, das für Sie nützlich sein kann:

 public async Task<ClaimsPrincipal> CreatePrincipleAsync()
    {
        AzureActiveDirectoryToken azureToken = Token.FromJsonString<AzureActiveDirectoryToken>();
        var allParts = azureToken.IdToken.Split(".");
        var header = allParts[0];
        var payload = allParts[1];
        var idToken = payload.ToBytesFromBase64URLString().ToAscii().FromJsonString<AzureActiveDirectoryIdToken>();

        allParts = azureToken.AccessToken.Split(".");
        header = allParts[0];
        payload = allParts[1];
        var signature = allParts[2];
        var accessToken = payload.ToBytesFromBase64URLString().ToAscii().FromJsonString<AzureActiveDirectoryAccessToken>();

        var accessTokenHeader = header.ToBytesFromBase64URLString().ToAscii().FromJsonString<AzureTokenHeader>();
        var isValid = await ValidateToken(accessTokenHeader.kid, header, payload, signature);
        if (!isValid)
        {
            throw new SecurityException("Token can not be validated");
        }
        var principal = await CreatePrincipalAsync(accessToken, idToken);
        return principal;
    }



    private async Task<bool> ValidateToken(string kid, string header, string payload, string signature)
    {
        string keysAsString = null;
        const string microsoftKeysUrl = "https://login.microsoftonline.com/common/discovery/keys";

        using (var client = new HttpClient())
        {
            keysAsString = await client.GetStringAsync(microsoftKeysUrl);
        }
        var azureKeys = keysAsString.FromJsonString<MicrosoftConfigurationKeys>();
        var signatureKeyIdentifier = azureKeys.Keys.FirstOrDefault(key => key.kid.Equals(kid));
        if (signatureKeyIdentifier.IsNotNull())
        {
            var signatureKey = signatureKeyIdentifier.x5c.First();
            var certificate = new X509Certificate2(signatureKey.ToBytesFromBase64URLString());
            var rsa = certificate.GetRSAPublicKey();
            var data = string.Format("{0}.{1}", header, payload).ToBytes();

            var isValidSignature = rsa.VerifyData(data, signature.ToBytesFromBase64URLString(), HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
            return isValidSignature;
        }

        return false;
    }

Ich verwende hier einige Funktionen, die Ihnen nicht zur Verfügung stehen, sie sind selbstbeschreibend.

1
Assil