JwtFormat:为啥将令牌的颁发者添加到 ValidIssuers 属性中?

Posted

技术标签:

【中文标题】JwtFormat:为啥将令牌的颁发者添加到 ValidIssuers 属性中?【英文标题】:JwtFormat: why does it add the token's issuer to the ValidIssuers property?JwtFormat:为什么将令牌的颁发者添加到 ValidIssuers 属性中? 【发布时间】:2018-04-25 11:25:49 【问题描述】:

我正在查看 JwtFormat 类的源代码,我想知道为什么它将它从令牌中恢复的 Issuer 添加到 ValidIssuers 列表中。这是否意味着如果我不指定密钥或向正在使用的 TokenValidationParameters 提供 IssueValidator 处理程序,它将接受所有颁发者为有效?

顺便说一句,我正在看这个课程,因为我正在调查一个关于在似乎忽略 ValidIssuer 属性的 Web api 应用程序中使用 JWT 令牌(azure ad v2.0)的问题:

app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions 
      AccessTokenFormat = new JwtFormat(
         GetTokenValidationParameters(),
         new OpenIdConnectCachingSecurityTokenProvider(authority)),
         Provider = new OAuthBearerAuthenticationProvider 
           OnValidateIdentity = ValidateIdentity
         
 );

private TokenValidationParameters GetTokenValidationParameters() 
    return new TokenValidationParameters 
        ValidAudience = ConfigData.ClientId,
        ValidIssuer = "nobody",
        ValidIssuers = null,
        IssuerValidator = ValidateIssuer
    ;

我正在编辑此内容以提供有关正在发生的事情的更多信息。

根据源码,ValidateIssuer默认为true,无需重新设置。只是为了确定,这里是源代码:

public TokenValidationParameters()

  this.RequireExpirationTime = true;
  this.RequireSignedTokens = true;
  this.SaveSigninToken = false;
  this.ValidateActor = false;
  this.ValidateAudience = true;
  this.ValidateIssuer = true;
  this.ValidateIssuerSigningKey = false;
  this.ValidateLifetime = true;

我正在设置 IssuerValidator,因为我想确保如果设置了 ValidIssuer,那么我想将令牌的颁发者与该值进行比较(并且不想在 ValidIssuer 验证时检查 ValidIssuers 集合失败)。

如果您想知道 ValidIssuers 的填充位置(是的,即使在我的示例中,它也会自动填充,即使我已将其显式设置为 null),它发生在 JwtFormat 的 Unprotect 方法中:

public AuthenticationTicket Unprotect(string protectedText)

  if (string.IsNullOrWhiteSpace(protectedText))
    throw new ArgumentNullException(nameof (protectedText));
  if (!(this.TokenHandler.ReadToken(protectedText) is JwtSecurityToken))
    throw new ArgumentOutOfRangeException(nameof (protectedText), Microsoft.Owin.Security.Jwt.Properties.Resources.Exception_InvalidJwt);
  TokenValidationParameters validationParameters = this._validationParameters;
  if (this._issuerCredentialProviders != null)
  
    validationParameters = validationParameters.Clone();
    IEnumerable<string> second1 = this._issuerCredentialProviders.Select<IIssuerSecurityTokenProvider, string>((Func<IIssuerSecurityTokenProvider, string>) (provider => provider.Issuer));
    validationParameters.ValidIssuers = validationParameters.ValidIssuers != null ? validationParameters.ValidIssuers.Concat<string>(second1) : second1;
    IEnumerable<SecurityToken> second2 = this._issuerCredentialProviders.Select<IIssuerSecurityTokenProvider, IEnumerable<SecurityToken>>((Func<IIssuerSecurityTokenProvider, IEnumerable<SecurityToken>>) (provider => provider.SecurityTokens)).Aggregate<IEnumerable<SecurityToken>>((Func<IEnumerable<SecurityToken>, IEnumerable<SecurityToken>, IEnumerable<SecurityToken>>) ((left, right) => left.Concat<SecurityToken>(right)));
    validationParameters.IssuerSigningTokens = validationParameters.IssuerSigningTokens != null ? validationParameters.IssuerSigningTokens.Concat<SecurityToken>(second2) : second2;
  
  SecurityToken validatedToken;
  ClaimsIdentity identity = (ClaimsIdentity) this.TokenHandler.ValidateToken(protectedText, validationParameters, out validatedToken).Identity;
  AuthenticationProperties properties = new AuthenticationProperties();
  if (this.UseTokenLifetime)
  
    DateTime validFrom = validatedToken.ValidFrom;
    if (validFrom != DateTime.MinValue)
      properties.IssuedUtc = new DateTimeOffset?((DateTimeOffset) validFrom.ToUniversalTime());
    DateTime validTo = validatedToken.ValidTo;
    if (validTo != DateTime.MinValue)
      properties.ExpiresUtc = new DateTimeOffset?((DateTimeOffset) validTo.ToUniversalTime());
    properties.AllowRefresh = new bool?(false);
  
  return new AuthenticationTicket(identity, properties);

顺便说一句,当需要反序列化令牌时,AuthenticateCoreAsync 方法最终会(间接)调用此方法:

protected override async Task<AuthenticationTicket> AuthenticateCoreAsync()

  try
  
    string requestToken = (string) null;
    string authorization = this.Request.Headers.Get("Authorization");
    if (!string.IsNullOrEmpty(authorization) && authorization.StartsWith("Bearer ", StringComparison.OrdinalIgnoreCase))
      requestToken = authorization.Substring("Bearer ".Length).Trim();
    OAuthRequestTokenContext requestTokenContext = new OAuthRequestTokenContext(this.Context, requestToken);
    await this.Options.Provider.RequestToken(requestTokenContext);
    if (string.IsNullOrEmpty(requestTokenContext.Token))
      return (AuthenticationTicket) null;
    AuthenticationTokenReceiveContext tokenReceiveContext = new AuthenticationTokenReceiveContext(this.Context, this.Options.AccessTokenFormat, requestTokenContext.Token);
    await this.Options.AccessTokenProvider.ReceiveAsync(tokenReceiveContext);
    if (tokenReceiveContext.Ticket == null)
      tokenReceiveContext.DeserializeTicket(tokenReceiveContext.Token);
//remaining code removed

由于我真的没有阅读规范,我想知道是否有人可以向我解释这种行为(始终将令牌的发行者添加到 ValidIssuers 集合中并检查令牌的发行者是否在 ValidIssuers 中 - 这将始终是正确的!)

最终编辑

好吧,我的错...咖啡不够,我想...实际上,发行者不是从令牌本身添加的,而是从传递给 JwtFormat ctor 的 IIssuerSecurityTokenProvider 添加的(从元数据中获取)端点)...

对不起各位...

谢谢。

路易斯

【问题讨论】:

您是否在 TokenValidationProperties 中将 validateIssuer 设置为 true? 你能提供你正在审查的源代码的 URL 吗? 【参考方案1】:

我目前没有Vs,因为我在手机上写,TokenValidationParameters里面应该有ValidateIssuer属性,但是貌似你把IssuerValidator设置为ValidateIssuer,应该是真的,所以试试看方式:

private TokenValidationParameters GetTokenValidationParameters() 
    return new TokenValidationParameters 
            ValidAudience = ConfigData.ClientId,
            ValidIssuer = "nobody",
            ValidateIssuer = true
    ;

【讨论】:

你好尼古拉斯。是的,有,默认情况下它是真的(这就是我不设置它的原因)。我已经设置了 IssueValidator,以便我可以复制/粘贴默认身份验证代码并查看为什么更改 ValidIssuer 不会禁止令牌。这就是我找到问题中提到的“问题”的方式...... @LuisAbreu 但是您的代码似乎将 IssueValidator 设置为 ValidateIssuer,这意味着按照惯例为 true。然后你的代码设置了问题,不是吗? 我已经用更多信息更新了帖子。我不明白为什么令牌的颁发者总是添加到 ValidIssuers 集合中,为什么默认的 IssueValidator 方法总是会在设置 ValidIssuer 属性时根据 ValidIssuers 集合检查颁发者(这将始终返回 true,因为令牌的颁发者最终被添加到 ValidIssuers 集合中!)。谢谢

以上是关于JwtFormat:为啥将令牌的颁发者添加到 ValidIssuers 属性中?的主要内容,如果未能解决你的问题,请参考以下文章

Keycloak:从内部 docker 容器运行时令牌颁发者无效

Keycloak:作为 docker 服务运行时令牌颁发者无效

WSO2IS 5.10 自定义 JWT 令牌颁发者未在服务提供者配置中列出

验证使用 JSON Web 加密 (JWE) 加密的安全令牌的颁发者?

Azure Identity:自定义令牌验证以验证多租户应用程序中的颁发者

ADFS 2.0 错误 ID4175:安全令牌的颁发者未被 IssuerNameRegistry 识别