我目前正在开发一个小型ASP.NET项目,涉及针对第三方身份提供商的用户身份验证。我遇到了SP发起的SLO请求问题。
我使用WIF SAML 2.0 extension来处理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。
任何指示都将深受赞赏。
答案 0 :(得分:1)
解决了它:
问题源于对证书如何工作的理解不足:我试图使用相同的X509Certificate来签署IdP和SP消息。
我created a X509Certificate并将其放入我的电脑“个人商店”。对web.config进行了以下更改:
<microsoft.identityModel>
<service>
<serviceCertificate>
<certificateReference
storeName="My"
x509FindType="FindByThumbprint"
storeLocation="LocalMachine"
findValue="82581cf4710c951d0f2e89e97c3a41d2b4a18890"
/>
</serviceCertificate>
[...]
证书的base64编码版本放在SP元数据中。然后SecurityTokenHandler能够签署我的LogoutRequests。