Claims系列 - ID4036错误(The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier)

错误现象

Claims系列 - ID4036错误(The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier)_第1张图片

 

错误原因

a) 在SecurityTokenService.GetScope()方法中,设置了Scope.EncryptingCredentials属性为某个X509证书(公钥);

Claims系列 - ID4036错误(The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier)_第2张图片

b) Relying Party应用程序中没有设置对应的证书(包含私钥)。

 

原因分析

从出错页面的规模信息可知, ID4036是由ID1044错误引发的。

导致ID1044异常的代码为Microsoft.IdentityModel.Web.TokenReceiver.ReadToken(String tokenXml, XmlDictionaryReaderQuotas readerQuotas)。

通过.Net Relector查看TokenReceiver.ReadToken()的内部实现如下:

 1  public SecurityToken ReadToken( string tokenXml, XmlDictionaryReaderQuotas readerQuotas)
 2 {
 3   // 此处无关代码被省略
 4    catch (EncryptedTokenDecryptionFailedException exception)
 5     {
 6          string str3;
 7          if ( this._serviceConfiguration.ServiceCertificate ==  null)
 8         {
 9             str3 = SR.GetString( " NoCert "new  object[ 0]);
10         }
11          else
12         {
13             str3 =  " [Thumbprint]  " +  this._serviceConfiguration.ServiceCertificate.Thumbprint;
14         }
15          throw DiagnosticUtil.ExceptionUtil.ThrowHelperError( new SecurityTokenException(SR.GetString( " ID1044 "new  object[] { str3 }), exception));
16     }
17      return token2;
18 }

显而易见,ID1044异常是由于this._serviceConfiguration.ServiceCertificate == null引起。

 

再查看TokenReceiver类,可知_serviceConfiguration是其私有字段,拍被设置的地方是在构造函数之中,并且是从外部传过来的.

1  public TokenReceiver(ServiceConfiguration serviceConfiguration)
2 {
3      if (serviceConfiguration ==  null)
4     {
5          throw DiagnosticUtil.ExceptionUtil.ThrowHelperArgumentNull( " serviceConfiguration ");
6     }
7      this._serviceConfiguration = serviceConfiguration;
8 }

那么此构造函数在什么地方调用的呢?从调用堆栈可知,推测可能是WSFederationAuthenticationModule.SignInWithResponseMessage(HttpRequest request).

打开.Net Reflector一看,果不其然:

 1  private  void SignInWithResponseMessage(HttpRequest request)
 2 {
 3  // 省略前面的无关代码
 4 
 5      if (!e.Cancel)
 6     {
 7         TokenReceiver receiver =  new TokenReceiver( base.ServiceConfiguration);
 8         IClaimsPrincipal claimsPrincipal = receiver.AuthenticateToken(e.SecurityToken,  true, HttpContext.Current.Request.RawUrl);
 9 
10  // 省略后面的无关代码
11 
12     }
13 }

 传入的参数值为base.ServiceConfiguration,即HttpModuleBase.ServiceConfiguration;其定义如下:

 1  public ServiceConfiguration ServiceConfiguration
 2 {
 3      get
 4     {
 5          return  this._serviceConfiguration;
 6     }
 7      set
 8     {
 9          if (value ==  null)
10         {
11              throw DiagnosticUtil.ExceptionUtil.ThrowHelperArgumentNull( " value ");
12         }
13          this._serviceConfiguration = value;
14     }
15 }

由于ServiceConfiguration是可读写属性,因此可能从外部和内部设置值。

先看外部有没有可能。从调用堆栈可知,其调用都为WSFederationAuthenticationModule.OnAuthenticateRequest(Object sender, EventArgs args):

View Code
 1  protected  virtual  void OnAuthenticateRequest( object sender, EventArgs args)
 2 {
 3     HttpRequest request = HttpContext.Current.Request;
 4      if ( this.CanReadSignInResponse(request))
 5     {
 6          try
 7         {
 8              this.SignInWithResponseMessage(request);
 9         }
10          catch (Exception exception)
11         {
12              if (DiagnosticUtil.IsFatal(exception))
13             {
14                  throw;
15             }
16              if (DiagnosticUtil.TraceUtil.ShouldTrace(TraceEventType.Warning))
17             {
18                 DiagnosticUtil.TraceUtil.TraceString(TraceEventType.Warning, SR.GetString( " ID8020 "new  object[] { exception }),  new  object[ 0]);
19             }
20             ErrorEventArgs args2 =  new ErrorEventArgs(exception);
21              this.OnSignInError(args2);
22              if (!args2.Cancel)
23             {
24                  throw;
25             }
26         }
27     }
28 }

从其实现看,并没有设置ServiceConfiguration值的地方;回过头再看HttpModuleBase,可知设置的地方是Init()函数:

1  public  void Init(HttpApplication context)
2 {
3      this._serviceConfiguration = FederatedAuthentication.ServiceConfiguration;
4      this.InitializeModule(context);
5 }

并且直接引用了FederatedAuthentication.ServiceConfiguration属性。再查看这个属性的定义:

 

 1  public  static ServiceConfiguration ServiceConfiguration
 2 {
 3      get
 4     {
 5          lock (_serviceConfigurationLock)
 6         {
 7              if (_serviceConfiguration ==  null)
 8             {
 9                 _serviceConfiguration =  new ServiceConfiguration();
10                 ServiceConfigurationCreatedEventArgs e =  new ServiceConfigurationCreatedEventArgs(_serviceConfiguration);
11                 EventHandler<ServiceConfigurationCreatedEventArgs> serviceConfigurationCreated = ServiceConfigurationCreated;
12                  if (serviceConfigurationCreated !=  null)
13                 {
14                     serviceConfigurationCreated( null, e);
15                 }
16                 _serviceConfiguration = e.ServiceConfiguration;
17                  if (!_serviceConfiguration.IsInitialized)
18                 {
19                     _serviceConfiguration.Initialize();
20                 }
21             }
22              return _serviceConfiguration;
23         }
24     }
25 }

从代码中可得到两点信息:1)_serviceConfiguration是在第一次请求时new出来的; 2)在第一次请求时会触发ServiceConfigurationCreated事件,并可访问到

_serviceConfiguration。

再看ServiceConfiguration的构造函数:

View Code
 1  public ServiceConfiguration()
 2 {
 3      this._certificateValidationMode = DefaultCertificateValidationMode;
 4      this._claimsAuthenticationManager =  new ClaimsAuthenticationManager();
 5      this._claimsAuthorizationManager =  new ClaimsAuthorizationManager();
 6      this._exceptionMapper =  new ExceptionMapper();
 7      this._revocationMode = DefaultRevocationMode;
 8      this._serviceName = DefaultServiceName;
 9      this._serviceMaxClockSkew = DefaultMaxClockSkew;
10      this._trustedStoreLocation = DefaultTrustedStoreLocation;
11     MicrosoftIdentityModelSection current = MicrosoftIdentityModelSection.Current;
12     ServiceElement element = (current !=  null) ? current.ServiceElements.GetElement(DefaultServiceName) :  null;
13      this.LoadConfiguration(element);
14 }

注意到最后调用了LoadConfiguration进行初始化,再看其内部实现:

 1  protected  void LoadConfiguration(ServiceElement element)
 2 {
 3      if (element !=  null)
 4     {
 5 
 6  // 省略前面无关代码
 7           if (( this._serviceCertificate ==  null) && element.ServiceCertificate.IsConfigured)
 8         {
 9              this._serviceCertificate = GetServiceCertificate(element);
10         }
11  // 省略后面无关代码
12      }
13      this._securityTokenHandlerCollectionManager =  this.LoadHandlers(element);
14 }

再看GetServiceCertificate()

 

 1  private  static X509Certificate2 GetServiceCertificate(ServiceElement element)
 2 {
 3     X509Certificate2 certificate2;
 4      try
 5     {
 6         X509Certificate2 certificate = element.ServiceCertificate.GetCertificate();
 7          if (certificate !=  null)
 8         {
 9             X509Util.EnsureAndGetPrivateRSAKey(certificate);
10         }
11         certificate2 = certificate;
12     }
13      catch (ArgumentException exception)
14     {
15          throw DiagnosticUtil.ExceptionUtil.ThrowHelperConfigurationError(element,  " serviceCertificate ", exception);
16     }
17      return certificate2;
18 }

至此, 终于知道X509证书默认是从ServiceElement即配置文件中的<microsoft.identitymodel><service><servicecertificate>节点。由此我们可得到如下两种解决方案:

解决方案

1 设置配置文件中的<microsoft.identitymodel><service><servicecertificate>节点

  a)找开Relying Party应用程序的配置文件;

  b)设置X509证书如下:

  Claims系列 - ID4036错误(The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier)_第3张图片

2 在FederatedAuthentication.ServiceConfigurationCreated事件处理函数中设置

   a) 在Relying Party工程中添加Global.asax文件(如果不存在的话);

   b) 添加Application_Start事件处理函数

Claims系列 - ID4036错误(The key needed to decrypt the encrypted security token could not be resolved from the following security key identifier)_第4张图片

 

你可能感兴趣的:(Security)