繁体   English   中英

如何在 c# Moq 中模拟“aud”声明

[英]How to mock "aud" claim in c# Moq

我正在尝试为使用最小起订量的 Azure AD 客户端凭据流实现的身份验证逻辑编写单元测试。

第一个测试用例是检查"Audience"是否有效。 我正在尝试模拟声明以使用ClaimTypes设置"aud""appId"声明,但无法找到ClaimTypes.Aud类的内容

var identity = new ClaimsIdentity(new Claim[] {
    new Claim(ClaimTypes.Name, "Sahil")
});
var mockPrincipal = new Mock<ClaimsPrincipal>(identity);
mockPrincipal.Setup(x => x.Identity).Returns(identity);
mockPrincipal.Setup(x => x.IsInRole(It.IsAny<string>())).Returns(true);

我如何在 C# 中设置“aud”和“appId”声明,或者只需设置 mockPrincipal 以便当它尝试检查“aud”是否有效时返回 false。

我正在尝试为以下代码编写单元测试。

public void Authenticate(JwtBearerOptions options)
{
    _configuration.Bind("AzureAD", options);
    options.TokenValidationParameters.ValidateAudience = true;
    options.TokenValidationParameters.ValidateIssuerSigningKey = true;
    options.TokenValidationParameters.ValidateIssuer = true;

    options.Events ??= new JwtBearerEvents();
    var existingHandlers = options.Events.OnTokenValidated;

    options.Events.OnTokenValidated = async context =>
    {
        string appId = GetAppIdFromToken(context);
        bool isAllowed = await CheckAppIdIsAllowedAsync(context, appId);

        if (isAllowed)
        {
            _logger.LogInformation($"[{nameof(Authenticate)}] AppId in allow list");
        }
        else
        {
            _logger.LogError($"[{nameof(Authenticate)}] AppId {appId} not in allowed list");
        }

        await Task.CompletedTask.ConfigureAwait(false);
    };
    options.Events.OnTokenValidated += existingHandlers;
}

private string GetAppIdFromToken(TokenValidatedContext context)
{
    string appId = context.Principal.Claims.FirstOrDefault(x => x.Type == "appid" || x.Type == "azp")?.Value;
    return appId;
}

private async Task<bool> CheckAppIdIsAllowedAsync(TokenValidatedContext context, string appId)
{
    IEnumerable<string> AllowedApps = _configuration.GetSection("AllowedAppPrincipals").Get<string[]>();
    var FoundAppId = AllowedApps.FirstOrDefault(a => a == appId);
    if (FoundAppId == null)
    {
        context.Response.StatusCode = (int)HttpStatusCode.Forbidden;
        context.Response.ContentType = "application/json";
        const string message = "{\"error\" : \"Unacceptable app principal\"}";
        byte[] arr = Encoding.ASCII.GetBytes(message);
        await context.Response.BodyWriter.WriteAsync(arr);
        context.Fail(message);
        return false;
    }
    return true;
}

如何使用 Moq 模拟audappId声明?

我试图重现如何让观众在我的环境中无效。

当颁发者端点不同或 scope 未正确给出或 scope 与所提及的不同时,通常会发生这种情况。

https://login.microsoftonline.com/xx/oauth2/v2.0/token

在这里我给了 scope 作为 api 而不是 microsoft graph。

在此处输入图像描述

但是下一步我正在调用图形端点,所以我收到了无效的观众错误。

https://graph.microsoft.com/v1.0/users/xxx

在此处输入图像描述

要检查 mocking 测试,您可以考虑以下几点,因为无法获得 c# 中针对“aud”观众的直接声明 AFAIK。

Aud 声明是Application ID URI or GUID标识令牌的预期受众。 在 v2.0 令牌中,受众必须是 API 的客户端 ID ,而在v1.0 令牌中,它可以是请求中使用的客户端 ID 或资源 URI

在此处输入图像描述

在此处输入图像描述

验证它的一种方法是与发行者/观众核对以下方式

您可以根据授权端点提供自定义值

代码:

string AUDIENCE = "<GUID of your Audience according to the app>";
 string TENANT = "<GUID of your Tenant>";

private static async Task<SecurityToken> validateJwtTokenAsync(string token)
{
    //  URL based on your AAD-TenantId
    var stsDiscoveryEndpoint = String.Format(CultureInfo.InvariantCulture, "https://login.microsoftonline.com/{0}/.well-known/openid-configuration", TENANT);
    //To Get tenant information
    var configManager = new ConfigurationManager<OpenIdConnectConfiguration>(stsDiscoveryEndpoint)
    // Get Config from AAD:
    var config = await configManager.GetConfigurationAsync();

    // Validate token:
    var tokenHandler = new JwtSecurityTokenHandler();
    var validationParameters = new TokenValidationParameters
    {
        ValidAudience = AUDIENCE,
        ValidIssuer = config.Issuer,
        IssuerSigningTokens = config.SigningTokens,
        CertificateValidator = X509CertificateValidator.ChainTrust,
    };

    var validatedToken = (SecurityToken)new JwtSecurityToken();

    tokenHandler.ValidateToken(token, validationParameters, out validatedToken);

    return validatedToken;
}

或者

var TokenValidationParameters = new TokenValidationParameters
{
    ValidateIssuerSigningKey = true,
    IssuerSigningKey = key,
    ValidateIssuer = true,
    ValidateAudience = true,
    ValidateLifetime = false,
    ....
    ValidIssuer = configuration["JwtAuthentication:Issuer"],
    ValidAudience = configuration["JwtAuthentication:Audience"]
};

因此,从验证参数中,您可以了解我们的受众是否有效,这主要发生在发行者与我们预期的不同或范围不正确时。

您可以尝试让那些验证为声明以检查 mocking

下面的片段摘自TokenValidationParameters.AudienceValidator, System.IdentityModel.Tokens C# (CSharp) 代码示例 - HotExamples

 public virtual ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken) { if (string.IsNullOrWhiteSpace(securityToken)) { throw new ArgumentNullException("securityToken"); } if (validationParameters == null) { throw new ArgumentNullException("validationParameters"); } if (validationParameters.ValidateAudience) { if (validationParameters.AudienceValidator.= null) { if (.validationParameters,AudienceValidator(jwt,Audiences. jwt. validationParameters)) { throw new SecurityTokenInvalidAudienceException(string,Format(CultureInfo.InvariantCulture, ErrorMessages.IDX10231; jwt.ToString())). } } else { this,ValidateAudience(jwt,Audiences; jwt. validationParameters), } } ClaimsIdentity identity = this,CreateClaimsIdentity(jwt; issuer. validationParameters). if (validationParameters;SaveSigninToken) { identity;BootstrapContext = new BootstrapContext(securityToken); } validatedToken = jwt; return new ClaimsPrincipal(identity); }

还要检查参考c# - 如何使用最小起订量模拟 ConfigurationManager.AppSettings - 堆栈内存溢出

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM