如何验证Azure AD安全令牌?

42 浏览
0 Comments

如何验证Azure AD安全令牌?

以下代码给我提供了Azure AD安全令牌,我需要验证该令牌是否有效。如何实现这一点?\n

// 使用客户端凭据获取OAuth令牌
string tenantName = "mytest.onmicrosoft.com";
string authString = "https://login.microsoftonline.com/" + tenantName;
AuthenticationContext authenticationContext = new AuthenticationContext(authString, false);
// 用于OAuth客户端凭据的配置
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 = authenticationContext.AcquireTokenAsync(resource, clientCred);
token = authenticationResult.Result.AccessToken;
Console.WriteLine(token);
// 如何在我的服务内验证这个令牌?                

0
0 Comments

如何验证Azure AD安全令牌?

在项目中不使用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;
    }

这里有一些我在这里使用的函数对你来说是不可用的,它们是自描述的。

我正在使用MS OAuth 2登录到我的网站。我无法在microsoftKeysUrl中找到我的密钥。还有其他地方可以获取正确的密钥吗?

你是说你在令牌中知道密钥的id或名称,但你无法在login.microsoftonline.com/common/discovery/keys中找到它吗?这很奇怪,它应该在那里找到。然而,问题是他们改变了签名算法的版本,并引入了随机数,这会使你很难验证。你使用的是哪个端点来获取令牌,V1还是V2?

经过整整一天的尝试,我终于在这里找到了我的kid。 login.microsoftonline.com/common/discovery/v2.0/keys。但是我必须在AD中启用隐式选项,否则密钥不会显示。

听到这个消息很好。是的,我看到你指定了版本来获取密钥。事情变化很快。

0
0 Comments

问题的出现原因:

用户使用.net Core 2.0时,需要修改Validate(string token)方法的两行代码,但是他们并不清楚具体如何修改。

解决方法:

用户需要修改以下两行代码:

var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(

stsDiscoveryEndpoint,

new OpenIdConnectConfigurationRetriever()); //1. need the 'new OpenIdConnect...'

OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;

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, //2. .NET Core equivalent is "IssuerSigningKeys" and "SigningKeys"

ValidateLifetime = true

};

对于问题中提到的具体代码错误,用户可以根据下面提供的链接获取进一步的解决方案。

此外,用户还可以使用OpenSSL来生成自己的SigningKeys。具体的示例可以参考stackoverflow.com/a/10176685/508681上的回答。

对于出现"Microsoft.IdentityModel.Tokens.SecurityTokenException: IDX10612: Decryption failed. Header.Enc is null or empty, it must be specified."错误的情况,目前还没有提供具体的解决方案。

0
0 Comments

如何验证Azure AD安全令牌?

在验证令牌时有两个步骤。首先,验证令牌的签名以确保该令牌是由Azure Active Directory发布的。其次,基于业务逻辑验证令牌中的声明。

例如,如果您正在开发一个单租户应用程序,则需要验证iss和aud声明。您还需要验证nbf以确保令牌未过期。更多声明请参考此处。

下面的描述是关于签名验证的详细信息。

首先,我们需要检索和缓存签名令牌(公钥)。

 
public JwtSecurityToken Validate(string token)
{
    string stsDiscoveryEndpoint = "https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration";
    ConfigurationManager configManager = new ConfigurationManager(stsDiscoveryEndpoint);
    OpenIdConnectConfiguration config = configManager.GetConfigurationAsync().Result;
    TokenValidationParameters validationParameters = new TokenValidationParameters
    {
        ValidateAudience = false,
        ValidateIssuer = false,
        IssuerSigningTokens = config.SigningTokens,
        ValidateLifetime = false
    };
    JwtSecurityTokenHandler tokenHandler = new JwtSecurityTokenHandler();
    SecurityToken jwt;
    var result = tokenHandler.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 Get()
{
    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"
        });
    }
    ...
}

如果您希望Azure AD支持撤销访问令牌,您可以从此处提交反馈。

目前,无法撤销已由Azure AD发布的访问令牌。但是,我们可以通过在Azure门户上启用“需要用户分配才能访问应用程序”功能并禁用用户来完全禁用用户的登录。如果您想要支持撤销访问令牌,您可以从此处提交反馈。

请不要在示例代码中关闭重要的验证规则(ValidateAudience,ValidateIssuer,ValidateLifetime),以免有人复制粘贴您的示例并认为它已准备好投入生产。

您应该将Validate方法放在哪里并在何处调用它?

我很好奇-谁以及如何管理公钥的缓存,以及在哪些情况下缓存会更新?

但是如何配置config.SigningTokens?Azure AD通过专用URI提供访问密钥。

请参考下面的答案。这个答案已经过时了。SigningTokens不再被Azure使用。

的确,已经更改为SigningKeys,请参考stackoverflow.com/questions/45500752/…

0