【问题标题】:Does OAuth token audience validation do anything else besides string compare of audience?除了受众的字符串比较之外,OAuth 令牌受众验证还做其他事情吗?
【发布时间】:2018-01-24 17:39:31
【问题描述】:
我正在使用 Microsoft.AspNetCore.Authentication.OpenIdConnect 和 Microsoft.AspNetCore.Authentication.JwtBearer 在 ASP.NET Core 应用程序中验证 OAuth 令牌。如果我禁用了内置的受众验证并自己验证了aud 声明,那么除了需要进行字符串比较之外是否还有其他必要的东西,例如校验和或签名检查?
我的具体情况是我有一个纯客户端 SPA 应用程序,它使用 msal.js(Azure AD OpenId Connect Workflow V2)与具有不同应用程序注册的 .NET API(因此不同的 ApplicationId/ClientId/Audidence 取决于抽象层)。即使使用原始的POST 调用,v2 Oauth 工作流程也不允许我使用访问令牌与受众 A 与受众 B 交谈。V1 不允许我在不公开客户端密钥或私钥的情况下浏览器。我更愿意让 API 接受多个受众,然后共享应用注册,直到存在流程。
【问题讨论】:
标签:
asp.net-core
oauth-2.0
azure-active-directory
【解决方案1】:
查看Microsoft.IdentityModel.Tokens的代码,实际执行的验证只是字符串比较。似乎没有任何校验和签名检查。
/// <summary>
/// Determines if the audiences found in a <see cref="SecurityToken"/> are valid.
/// </summary>
/// <param name="audiences">The audiences found in the <see cref="SecurityToken"/>.</param>
/// <param name="securityToken">The <see cref="SecurityToken"/> being validated.</param>
/// <param name="validationParameters"><see cref="TokenValidationParameters"/> required for validation.</param>
/// <exception cref="ArgumentNullException">If 'vaidationParameters' is null.</exception>
/// <exception cref="ArgumentNullException">If 'audiences' is null and <see cref="TokenValidationParameters.ValidateAudience"/> is true.</exception>
/// <exception cref="SecurityTokenInvalidAudienceException">If <see cref="TokenValidationParameters.ValidAudience"/> is null or whitespace and <see cref="TokenValidationParameters.ValidAudiences"/> is null.</exception>
/// <exception cref="SecurityTokenInvalidAudienceException">If none of the 'audiences' matched either <see cref="TokenValidationParameters.ValidAudience"/> or one of <see cref="TokenValidationParameters.ValidAudiences"/>.</exception>
/// <remarks>An EXACT match is required.</remarks>
public static void ValidateAudience(IEnumerable<string> audiences, SecurityToken securityToken, TokenValidationParameters validationParameters)
{
if (validationParameters == null)
throw LogHelper.LogArgumentNullException(nameof(validationParameters));
if (!validationParameters.ValidateAudience)
{
IdentityModelEventSource.Logger.WriteWarning(LogMessages.IDX10233);
return;
}
if (audiences == null)
throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidAudienceException(LogMessages.IDX10207) { InvalidAudience = null });
if (string.IsNullOrWhiteSpace(validationParameters.ValidAudience) && (validationParameters.ValidAudiences == null))
throw LogHelper.LogExceptionMessage(new SecurityTokenInvalidAudienceException(LogMessages.IDX10208) { InvalidAudience = Utility.SerializeAsSingleCommaDelimitedString(audiences) });
foreach (string audience in audiences)
{
if (string.IsNullOrWhiteSpace(audience))
{
continue;
}
if (validationParameters.ValidAudiences != null)
{
foreach (string str in validationParameters.ValidAudiences)
{
if (string.Equals(audience, str, StringComparison.Ordinal))
{
IdentityModelEventSource.Logger.WriteInformation(LogMessages.IDX10234, audience);
return;
}
}
}
if (!string.IsNullOrWhiteSpace(validationParameters.ValidAudience))
{
if (string.Equals(audience, validationParameters.ValidAudience, StringComparison.Ordinal))
{
IdentityModelEventSource.Logger.WriteInformation(LogMessages.IDX10234, audience);
return;
}
}
}
throw LogHelper.LogExceptionMessage(
new SecurityTokenInvalidAudienceException(String.Format(CultureInfo.InvariantCulture, LogMessages.IDX10214, Utility.SerializeAsSingleCommaDelimitedString(audiences), (validationParameters.ValidAudience ?? "null"), Utility.SerializeAsSingleCommaDelimitedString(validationParameters.ValidAudiences)))
{ InvalidAudience = Utility.SerializeAsSingleCommaDelimitedString(audiences) });
}