Подтвердить что ты не робот

Как проверить токен безопасности Azure AD?

Следующий код дает мне Azure AD security token, мне нужно проверить, является ли этот токен действительным или нет. Как этого добиться?

// 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?                
4b9b3361

Ответ 1

Есть два шага для проверки токена. Сначала проверьте подпись токена, чтобы убедиться, что токен был выдан Azure Active Directory. Во-вторых, проверьте утверждения в токене на основе бизнес-логики.

Например, нам нужно проверить утверждение iss и aud если вы разрабатывали приложение для одного арендатора. И вам также необходимо проверить nbf чтобы убедиться, что токен не истек. Больше претензий вы можете сослаться здесь.

Ниже описание от здесь о деталях подписи подтверждать. (Примечание. В приведенном ниже примере используется конечная точка Azure AD v2. Следует использовать конечную точку, соответствующую конечной точке, используемой клиентским приложением.)

Маркер доступа из Azure AD представляет собой веб-токен JSON (JWT), подписанный службой токенов безопасности в виде закрытого ключа.

JWT включает в себя 3 части: заголовок, данные и подпись. Технически, мы можем использовать открытый ключ для проверки токена доступа.

Первый шаг - извлечение и кеширование поющих токенов (открытый ключ)

Конечная точка: https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration

Затем мы можем использовать JwtSecurityTokenHandler для проверки токена с помощью приведенного ниже примера кода:

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

И если вы использовали компоненты OWIN в своем проекте, то проще проверить токен. Мы можем использовать код ниже для проверки токена:

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

Затем мы можем использовать приведенный ниже код, чтобы проверить область действия в токене:

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"
        });
    }
    ...
}

А вот пример кода, который защищает веб-API с помощью Azure AD:

Защитите веб-API с помощью токенов на предъявителя из Azure AD

Ответ 2

Просто хотел добавить в Fei ответ для людей, использующих .net Core 2.0

Вам нужно изменить 2 строки метода Validate(string token).

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

...
 TokenValidationParameters validationParameters = new TokenValidationParameters
 {
     //decode the JWT to see what these values should be
     ValidAudience = "some audience",
     ValidIssuer = "some issuer",

     ValidateAudience = true,
     ValidateIssuer = true,
     IssuerSigningKeys = config.SigningKeys, //.net core calls it "IssuerSigningKeys" and "SigningKeys"
     ValidateLifetime = true
 };

Ответ 3

Но если вы не используете Owin в своих проектах, он будет немного трудно или, по крайней мере, много времени.. Эта статья здесь является большим ресурсом.

И потому, что мне нечего добавить к вышесказанному, кроме подробного кода.. Вот кое-что, что может быть полезно для вас:

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

Здесь я использую некоторые функции, которые вам недоступны, они описательны.

Ответ 4

Доброе утро ! Я прочитал ответы, но вы можете сказать мне библиотеки, которые мне нужны для использования ConfigurationManager configManager = new ConfigurationManager (stsDiscoveryEndpoint);

 OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;

в первом ответе?

Спасибо !!!