我目前正在开发一个小型 ASP.NET 项目,该项目涉及针对第 3 方身份提供者对用户进行身份验证。我遇到了由 SP 发起的 SLO 请求的问题。
我正在使用WIF SAML 2.0 扩展来处理 SAML 协议。
调试我的应用程序时,它立即崩溃,给我以下错误消息(我删除了 RawData 的值,即用于签名的 X509Certificate 的公钥):
The token resolver is unable to resolve the token reference 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = X509RawDataKeyIdentifierClause(RawData = )
)
'.
Description: An unhandled exception occurred during the execution of the current web request. Please review the stack trace for more information about the error and where it originated in the code.
Exception Details: System.InvalidOperationException: The token resolver is unable to resolve the token reference 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = X509RawDataKeyIdentifierClause(RawData = )
)
'.
Source Error:
An unhandled exception was generated during the execution of the current web request. Information regarding the origin and location of the exception can be identified using the exception stack trace below.
Stack Trace:
[InvalidOperationException: The token resolver is unable to resolve the token reference 'SecurityKeyIdentifier
(
IsReadOnly = False,
Count = 1,
Clause[0] = X509RawDataKeyIdentifierClause(RawData = )
)
'.]
System.IdentityModel.Selectors.SecurityTokenResolver.ResolveToken(SecurityKeyIdentifier keyIdentifier) +226933
Microsoft.IdentityModel.Web.Saml2AuthenticationModule.ReadSelfMetadata(Stream stream, String fileName, String& entityId, EndpointConfiguration& endpointConfiguration, Boolean& signAuthenticationRequests, X509Certificate2& signingCertificate) +771
[ConfigurationErrorsException: ID4451: The signing key specified in metadata could not be found. Update the key identifier in metadata or ensure the key is present in the ServiceTokenResolver. See the inner exception for more details.]
Microsoft.IdentityModel.Web.Saml2AuthenticationModule.ReadSelfMetadata(Stream stream, String fileName, String& entityId, EndpointConfiguration& endpointConfiguration, Boolean& signAuthenticationRequests, X509Certificate2& signingCertificate) +940
Microsoft.IdentityModel.Web.Saml2AuthenticationModule..ctor() +606
[TargetInvocationException: Exception has been thrown by the target of an invocation.]
System.RuntimeTypeHandle.CreateInstance(RuntimeType type, Boolean publicOnly, Boolean noCheck, Boolean& canBeCached, RuntimeMethodHandleInternal& ctor, Boolean& bNeedSecurityCheck) +0
System.RuntimeType.CreateInstanceSlow(Boolean publicOnly, Boolean skipCheckThis, Boolean fillCache) +98
System.RuntimeType.CreateInstanceDefaultCtor(Boolean publicOnly, Boolean skipVisibilityChecks, Boolean skipCheckThis, Boolean fillCache) +241
System.Activator.CreateInstance(Type type, Boolean nonPublic) +69
System.RuntimeType.CreateInstanceImpl(BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +1136
System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture, Object[] activationAttributes) +111
System.Activator.CreateInstance(Type type, BindingFlags bindingAttr, Binder binder, Object[] args, CultureInfo culture) +23
System.Web.HttpRuntime.CreateNonPublicInstance(Type type, Object[] args) +60
System.Web.HttpApplication.BuildIntegratedModuleCollection(List`1 moduleList) +231
System.Web.HttpApplication.GetModuleCollection(IntPtr appContext) +1365
System.Web.HttpApplication.RegisterEventSubscriptionsWithIIS(IntPtr appContext, HttpContext context, MethodInfo[] handlers) +95
System.Web.HttpApplication.InitSpecial(HttpApplicationState state, MethodInfo[] handlers, IntPtr appContext, HttpContext context) +194
System.Web.HttpApplicationFactory.GetSpecialApplicationInstance(IntPtr appContext, HttpContext context) +339
System.Web.Hosting.PipelineRuntime.InitializeApplication(IntPtr appContext) +253
[HttpException (0x80004005): Exception has been thrown by the target of an invocation.]
System.Web.HttpRuntime.FirstRequestInit(HttpContext context) +9090876
System.Web.HttpRuntime.EnsureFirstRequestInit(HttpContext context) +97
System.Web.HttpRuntime.ProcessRequestNotificationPrivate(IIS7WorkerRequest wr, HttpContext context) +256
我的 SP 元数据如下:
<md:EntityDescriptor
xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata"
xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion"
entityID="urn:mace:feide.no:services:no.ntnu.test_lesesalplass">
<!--Find where to turn off LogOutRequestSigning!-->
<md:SPSSODescriptor
WantAssertionsSigned="false"
AuthnRequestsSigned="false"
protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
<md:KeyDescriptor use="signing">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
[...]
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:KeyDescriptor use="encryption">
<ds:KeyInfo xmlns:ds="http://www.w3.org/2000/09/xmldsig#">
<ds:X509Data>
<ds:X509Certificate>
[...]
</ds:X509Certificate>
</ds:X509Data>
</ds:KeyInfo>
</md:KeyDescriptor>
<md:NameIDFormat>
urn:oasis:names:tc:SAML:2.0:nameid-format:transient
</md:NameIDFormat>
<md:SingleLogoutService
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
Location="http://localhost:52681/LeseSalReg/saml/redirect/slo"
ResponseLocation="http://localhost:52681/LeseSalReg/saml/redirect/sloresponse"
/>
<md:AssertionConsumerService
isDefault="true" index="0"
Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
Location="http://localhost:52681/LeseSalReg/saml/post/ac"
/>
</md:SPSSODescriptor>
</md:EntityDescriptor>
我的 web.config 如下所示:
<?xml version="1.0"?>
<configuration>
<configSections>
<section name="microsoft.identityModel" type="Microsoft.IdentityModel.Configuration.MicrosoftIdentityModelSection, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<section name="microsoft.identityModel.saml" type="Microsoft.IdentityModel.Web.Configuration.MicrosoftIdentityModelSamlSection, Microsoft.IdentityModel.Protocols"/>
</configSections>
<connectionStrings>
<add name="ApplicationServices"
connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;AttachDBFilename=|DataDirectory|\aspnetdb.mdf;User Instance=true"
providerName="System.Data.SqlClient" />
<add name="StudySpaceRegEntities"
connectionString="metadata=res://*/LeseSalRegEntity.csdl|res://*/LeseSalRegEntity.ssdl|res://*/LeseSalRegEntity.msl;provider=System.Data.SqlClient;provider connection string="data source=MATSHO;initial catalog=StudySpaceReg;integrated security=True;multipleactiveresultsets=True;App=EntityFramework""
providerName="System.Data.EntityClient" />
</connectionStrings>
<system.web>
<compilation debug="true" targetFramework="4.0" >
<assemblies>
<add assembly="Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
</assemblies>
</compilation>
<siteMap enabled="false">
<providers>
<clear/>
<add name="AspNetXmlSiteMapProvider" type="System.Web.XmlSiteMapProvider" siteMapFile="Web.sitemap" securityTrimmingEnabled="true" />
</providers>
</siteMap>
<authentication mode="Forms">
<forms loginUrl="~/About.aspx" timeout="2880" defaultUrl="~/Register.aspx" />
</authentication>
<pages controlRenderingCompatibilityVersion="4.0" clientIDMode="AutoID" masterPageFile="~/Site.Master"/>
<membership>
<providers>
<clear/>
<add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
applicationName="/" />
</providers>
</membership>
<profile>
<providers>
<clear/>
<add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
</providers>
</profile>
<roleManager enabled="false">
<providers>
<clear/>
<add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
<add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
</providers>
</roleManager>
<httpModules>
<add name="Saml2AuthenticationModule" type="Microsoft.IdentityModel.Web.Saml2AuthenticationModule"/>
<add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule"/>
</httpModules>
</system.web>
<system.webServer>
<validation validateIntegratedModeConfiguration="false"/>
<modules>
<add name="Saml2AuthenticationModule" type="Microsoft.IdentityModel.Web.Saml2AuthenticationModule"/>
<add name="SessionAuthenticationModule" type="Microsoft.IdentityModel.Web.SessionAuthenticationModule"/>
</modules>
</system.webServer>
<microsoft.identityModel>
<service>
<audienceUris>
<clear/>
<add value="urn:mace:feide.no:services:no.ntnu.test_lesesalplass"/>
</audienceUris>
<issuerNameRegistry type="Microsoft.IdentityModel.Tokens.ConfigurationBasedIssuerNameRegistry">
<trustedIssuers>
<add name="https://idp-test.feide.no" thumbprint="fa982efdb69f26e8073c8f815a82a0c5885960a2"/>
</trustedIssuers>
</issuerNameRegistry>
<securityTokenHandlers>
<remove type="Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<add type="Microsoft.IdentityModel.Tokens.Saml2.Saml2SecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" />
<remove type="Microsoft.IdentityModel.Tokens.X509SecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35"/>
<add type="Microsoft.IdentityModel.Tokens.X509SecurityTokenHandler, Microsoft.IdentityModel, Version=3.5.0.0, Culture=neutral, PublicKeyToken=31BF3856AD364E35" />
<securityTokenHandlerConfiguration saveBootstrapTokens="true" >
<audienceUris mode="Always" />
</securityTokenHandlerConfiguration>
</securityTokenHandlers>
</service>
</microsoft.identityModel>
<microsoft.identityModel.saml metadata="App_Data\SPmeta.xml">
<identityProviders>
<metadata file="App_Data\IdPmeta.xml"/>
</identityProviders>
</microsoft.identityModel.saml>
如果我在 SP 元数据中注释掉签名证书的 KeyDescriptor,应用程序不会崩溃。但是,当我尝试注销时,出现以下异常:
ID4450:“LogoutRequest”类型的消息必须在发送前签名。设置消息的 SigningCredentials 属性,或使用非空 X509Certificate2 配置 Saml2MessageDecorator。
我认为 WIF 不支持未签名的 SLO 请求,因此我必须对其进行签名。由于我无法理解的原因,SecurityTokenResolver 似乎无法解析元数据中定义的用于签名的 X509Certificate。
任何指针将不胜感激。