如何为Holder-of-key配置文件

时间:2015-09-27 13:29:03

标签: spring-security single-sign-on saml saml-2.0 spring-saml

我尝试使用Spring Security SAML扩展的SAML Holder-of-key 配置文件,但我没有成功,我甚至用谷歌搜索但未找到任何相关文档或样本。

我在tomcat config(server.xml文件)中添加了以下标记,以启用HTTPS方案和客户端身份验证:

<Connector port="8443" SSLEnabled="true" scheme="https" secure="true" clientAuth="want" sslProtocol="TLS" keystoreFile="ks.keystore" keystorePass="password" truststoreFile="ts.keystore" truststorePass="password"/>

此配置似乎有效,因为当我访问我的应用程序网站时,它会请求客户端证书并将身份验证请求发送到IdP。 IdP验证请求但不要求客户端证书,作为响应,它返回没有HoK主题确认的断言,我收到以下错误:

org.springframework.security.authentication.AuthenticationServiceException: Error validating SAML message
at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:95)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:167)
at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87)
at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:217)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:184)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.header.HeaderWriterFilter.doFilterInternal(HeaderWriterFilter.java:64)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:53)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:91)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.access.channel.ChannelProcessingFilter.doFilter(ChannelProcessingFilter.java:152)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87)
at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:330)
at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:213)
at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:176)
at org.springframework.security.web.debug.DebugFilter.invokeWithWrappedRequest(DebugFilter.java:75)
at org.springframework.security.web.debug.DebugFilter.doFilter(DebugFilter.java:62)
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:221)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:107)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:155)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:76)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:934)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:90)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:515)
at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1012)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:642)
at org.apache.coyote.http11.Http11NioProtocol$Http11ConnectionHandler.process(Http11NioProtocol.java:223)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1597)
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1555)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
Caused by: org.opensaml.common.SAMLException: Response doesn't have any valid assertion which would pass subject validation
at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:229)
at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:84)
... 43 more
Caused by: org.opensaml.common.SAMLException: Assertion invalidated by subject confirmation - can't be confirmed by holder-of-key method
at org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl.verifySubject(WebSSOProfileConsumerHoKImpl.java:150)
at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.verifyAssertion(WebSSOProfileConsumerImpl.java:296)
at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:214)
... 44 more

这是我的Spring Security配置:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:security="http://www.springframework.org/schema/security"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/security
       http://www.springframework.org/schema/security/spring-security.xsd">


       <context:annotation-config/>
       <security:debug/>

       <context:component-scan base-package="org.springframework.security.saml" />

       <security:http entry-point-ref="samlEntryPoint" use-expressions="false">
              <security:csrf disabled="true" />
              <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY" requires-channel="https" />
              <security:custom-filter before="FIRST" ref="metadataGeneratorFilter" />
              <security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter" />
       </security:http>

       <!-- Filter automatically generates default SP metadata -->
       <bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
              <constructor-arg>
                     <bean class="org.springframework.security.saml.metadata.MetadataGenerator">
                            <property name="bindingsHoKSSO">
                                   <list>
                                          <value>post</value>
                                          <value>artifact</value>
                                   </list>
                            </property>
                            <property name="entityBaseURL" value="https://localhost:8443" />
                            <property name="extendedMetadata">
                                   <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                                          <property name="signMetadata" value="true"/>
                                          <property name="idpDiscoveryEnabled" value="true"/>
                                   </bean>
                            </property>
                     </bean>
              </constructor-arg>
       </bean>

       <bean id="samlFilter" class="org.springframework.security.web.FilterChainProxy">
              <security:filter-chain-map request-matcher="ant">
                     <security:filter-chain pattern="/saml/login/**" filters="samlEntryPoint" />
                     <security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter" />
                     <security:filter-chain pattern="/saml/HoKSSO" filters="samlWebSSOHoKProcessingFilter" />
                     <security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
                     <security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/>
                     <security:filter-chain pattern="/saml/logout/**" filters="samlLogoutFilter" />
                     <security:filter-chain pattern="/saml/single_logout/**" filters="samlLogoutProcessingFilter" />
              </security:filter-chain-map>
       </bean>

       <!-- LOGOUT -->
       <!-- (Local Logout) Override default logout processing filter with the one processing SAML messages -->
       <bean id="samlLogoutFilter" class="org.springframework.security.saml.SAMLLogoutFilter">
              <constructor-arg index="0" ref="successLogoutHandler"/>
              <constructor-arg index="1" ref="logoutHandler"/>
              <constructor-arg index="2" ref="logoutHandler"/>
       </bean>

       <!-- (Single Logout) Filter processing incoming logout messages -->
       <!-- First argument determines URL user will be redirected to after successful global logout -->
       <bean id="samlLogoutProcessingFilter" class="org.springframework.security.saml.SAMLLogoutProcessingFilter">
              <constructor-arg index="0" ref="successLogoutHandler"/>
              <constructor-arg index="1" ref="logoutHandler"/>
       </bean>

       <!-- Handler for successful logout -->
       <bean id="successLogoutHandler" class="org.springframework.security.web.authentication.logout.SimpleUrlLogoutSuccessHandler">
              <property name="defaultTargetUrl" value="/logout.jsp"/>
       </bean>

       <!-- Logout handler terminating local session -->
       <bean id="logoutHandler" class="org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler">
              <property name="invalidateHttpSession" value="false"/>
       </bean>

       <!-- SAML 2.0 Logout Profile -->
       <bean id="logoutprofile" class="org.springframework.security.saml.websso.SingleLogoutProfileImpl"/>

       <!-- IDP Discovery Service -->
       <bean id="samlIDPDiscovery" class="org.springframework.security.saml.SAMLDiscovery">
              <property name="idpSelectionPath" value="/idpSelection.jsp"/>
       </bean>

       <bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter" />

       <!-- Processing filter for WebSSO Holder-of-Key profile -->
       <bean id="samlWebSSOHoKProcessingFilter" class="org.springframework.security.saml.SAMLWebSSOHoKProcessingFilter">
              <property name="authenticationManager" ref="authenticationManager"/>
              <property name="authenticationSuccessHandler" ref="successRedirectHandler"/>
              <property name="authenticationFailureHandler" ref="failureRedirectHandler"/>
       </bean>

       <bean id="samlWebSSOProcessingFilter" class="org.springframework.security.saml.SAMLProcessingFilter">
              <property name="authenticationManager" ref="authenticationManager" />
              <property name="authenticationSuccessHandler" ref="successRedirectHandler" />
              <property name="authenticationFailureHandler" ref="failureRedirectHandler" />
       </bean>

       <bean id="successRedirectHandler" class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
              <property name="defaultTargetUrl" value="/" />
       </bean>

       <bean id="failureRedirectHandler" class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
              <property name="useForward" value="true" />
              <property name="defaultFailureUrl" value="/error.jsp" />
       </bean>

       <bean class="org.springframework.security.saml.trust.httpclient.TLSProtocolConfigurer">
              <property name="sslHostnameVerification" value="default"/>
       </bean>

       <bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
              <property name="defaultProfileOptions">
                     <bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
                            <property name="assertionConsumerIndex" value="2" />
                            <property name="binding" value="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST" />
                            <property name="includeScoping" value="false" />
                     </bean>
              </property>
       </bean>
       <security:authentication-manager alias="authenticationManager">
              <security:authentication-provider ref="samlAuthenticationProvider" />
       </security:authentication-manager>

       <bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
              <constructor-arg>
                     <list>
                            <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                                   <constructor-arg>
                                          <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                                                 <constructor-arg>
                                                        <value type="java.io.File">classpath:IS_metadata.xml</value>
                                                 </constructor-arg>
                                                 <property name="parserPool" ref="parserPool"/>
                                          </bean>
                                   </constructor-arg>
                                   <constructor-arg>
                                          <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                                          </bean>
                                   </constructor-arg>
                            </bean>
                     </list>
              </constructor-arg>
              <!--<property name="defaultIDP" value="https://localhost:9443/samlsso" />-->
       </bean>

       <bean class="org.springframework.security.saml.SAMLBootstrap" />

       <bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider" />

       <!-- SAML 2.0 WebSSO Assertion Consumer -->
       <bean id="webSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerImpl" />

       <!-- SAML 2.0 Web SSO profile -->
       <bean id="webSSOprofile" class="org.springframework.security.saml.websso.WebSSOProfileImpl" />

       <!-- SAML 2.0 Holder-of-Key WebSSO Assertion Consumer -->
       <bean id="hokWebSSOprofileConsumer" class="org.springframework.security.saml.websso.WebSSOProfileConsumerHoKImpl" />

       <!-- SAML 2.0 Holder-of-Key Web SSO profile -->
       <bean id="hokWebSSOProfile" class="org.springframework.security.saml.websso.WebSSOProfileHoKImpl" />

       <!-- SAML 2.0 ECP profile -->
       <bean id="ecpprofile" class="org.springframework.security.saml.websso.WebSSOProfileECPImpl"/>

       <!-- Provider of default SAML Context -->
       <bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl">
              <!--<property name="metadataResolver">
                     <bean class="org.springframework.security.saml.trust.MetadataCredentialResolver">
                            <constructor-arg  index="0" ref="metadata" />
                            <constructor-arg name="keyManager" index="1" ref="keyManager" />
                            <property name="useXmlMetadata" value="false" />
                     </bean>
              </property>-->
              <property name="storageFactory">
                     <bean class="org.springframework.security.saml.storage.EmptyStorageFactory" />
              </property>
       </bean>

       <bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger" />

       <bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
              <constructor-arg value="classpath:samlKeystore.jks" />
              <constructor-arg type="java.lang.String" value="nalle123" />
              <constructor-arg>
                     <map>
                            <entry key="spalias" value="nalle123" />
                     </map>
              </constructor-arg>
              <constructor-arg type="java.lang.String" value="spalias" />
       </bean>

       <!-- Class loading incoming SAML messages from httpRequest stream -->
       <bean id="processor" class="org.springframework.security.saml.processor.SAMLProcessorImpl">
              <constructor-arg>
                     <list>
                            <ref bean="redirectBinding" />
                            <ref bean="postBinding" />
                            <ref bean="artifactBinding" />
                            <ref bean="soapBinding" />
                            <ref bean="paosBinding" />
                     </list>
              </constructor-arg>
       </bean>

       <!-- Bindings, encoders and decoders used for creating and parsing messages -->
       <bean id="postBinding" class="org.springframework.security.saml.processor.HTTPPostBinding">
              <constructor-arg ref="parserPool" />
              <constructor-arg ref="velocityEngine" />
       </bean>

       <bean id="redirectBinding" class="org.springframework.security.saml.processor.HTTPRedirectDeflateBinding">
              <constructor-arg ref="parserPool" />
       </bean>

       <bean id="artifactBinding" class="org.springframework.security.saml.processor.HTTPArtifactBinding">
              <constructor-arg ref="parserPool" />
              <constructor-arg ref="velocityEngine" />
              <constructor-arg>
                     <bean class="org.springframework.security.saml.websso.ArtifactResolutionProfileImpl">
                            <constructor-arg>
                                   <bean class="org.apache.commons.httpclient.HttpClient">
                                          <constructor-arg>
                                                 <bean class="org.apache.commons.httpclient.MultiThreadedHttpConnectionManager" />
                                          </constructor-arg>
                                   </bean>
                            </constructor-arg>
                            <property name="processor">
                                   <bean class="org.springframework.security.saml.processor.SAMLProcessorImpl">
                                          <constructor-arg ref="soapBinding" />
                                   </bean>
                            </property>
                     </bean>
              </constructor-arg>
       </bean>

       <bean id="soapBinding" class="org.springframework.security.saml.processor.HTTPSOAP11Binding">
              <constructor-arg ref="parserPool" />
       </bean>

       <bean id="paosBinding" class="org.springframework.security.saml.processor.HTTPPAOS11Binding">
              <constructor-arg ref="parserPool" />
       </bean>

       <!-- XML parser pool needed for OpenSAML parsing -->
       <bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize">
              <property name="builderFeatures">
                     <map>
                            <entry key="http://apache.org/xml/features/dom/defer-node-expansion" value="false" />
                     </map>
              </property>
       </bean>

       <bean id="parserPoolHolder" class="org.springframework.security.saml.parser.ParserPoolHolder" />

       <!-- Initialization of the velocity engine -->
       <bean id="velocityEngine" class="org.springframework.security.saml.util.VelocityFactory" factory-method="getEngine" />
</beans>

我在这种情况下使用WSO2 Identity Server v4.5.0作为IdP,这是WSO2 IdP元数据:

<?xml version="1.0" encoding="UTF-8"?><md:EntityDescriptor xmlns:md="urn:oasis:names:tc:SAML:2.0:metadata" xmlns:saml="urn:oasis:names:tc:SAML:2.0:assertion" xmlns:ds="http://www.w3.org/2000/09/xmldsig#" entityID="https://localhost:9443/samlsso" validUntil="2023-09-23T06:57:15.396Z">
    <md:IDPSSODescriptor protocolSupportEnumeration="urn:oasis:names:tc:SAML:2.0:protocol">
        <md:KeyDescriptor use="signing">
            <ds:KeyInfo>
                <ds:X509Data>
                    <ds:X509Certificate>
                        MIIDXTCCAkWgAwIBAgIETYI6hjANBgkqhkiG9w0BAQsFADBfMQswCQYDVQQGEwJJ
                        UjELMAkGA1UECBMCTkExDzANBgNVBAcTBlRlaHJhbjENMAsGA1UEChMEV1NPMjEQ
                        MA4GA1UECxMHV1NPMiBJUzERMA8GA1UEAxMIaG9zdG5hbWUwHhcNMTUwOTI3MDYy
                        NDE2WhcNMTUxMjI2MDYyNDE2WjBfMQswCQYDVQQGEwJJUjELMAkGA1UECBMCTkEx
                        DzANBgNVBAcTBlRlaHJhbjENMAsGA1UEChMEV1NPMjEQMA4GA1UECxMHV1NPMiBJ
                        UzERMA8GA1UEAxMIaG9zdG5hbWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
                        AoIBAQCOD3I08VYC+auzqP6sZbnejD40jtuDuX/IooDxzphysqeTaPVOq0Fquv9i
                        uIb6XfxGk1hbFiThriCynXAkxeNbmK2ByurRVoJBgdFcCB9JfbGNapVodAbVl9cR
                        5kXmMJAdqXFDOrMCluira/7HzR0SpoG6A41M/cOkJHq7qtdQlCBaC+L0C5KK+P6/
                        g4X1zKIt5+vmn1lnDDxdOlCUsv5xVgEYLai+2ArPCZzMxKwlGQ/yWoDky2HXRrnx
                        ja/vV0J1VeV86tVwyxMb4Bm4XKohrH5sVtzE296JoiPl3rLfGeWpYEO4DXfJYLbi
                        4+kUvQ4MXTcsSDwQI9aBwVhia8uVAgMBAAGjITAfMB0GA1UdDgQWBBT5CS2/DmR3
                        lWx35Pmf1jZwbYJpcTANBgkqhkiG9w0BAQsFAAOCAQEANU/dEo7hWpQEDaYvaZmN
                        IJbck5fqKw4bgbPE2D6ifaYdb4SxxbNL3eBHg1Hbr5hCwLuX4zeqS9D8mrGzWnap
                        ZgG88VtDl/Y75t9Q3/y8PaRzHKaijo6ydyewLRtumhxFf/nXVKod9kNSPrOorM+o
                        T/1ht+yfaxCeeK32aV/SLs42raPI3LAT2ZyPimiVhsou72jXD7st8aRhm21qliZq
                        Qezbz8MccO1peASUikh8ksXNzb6Uh/3o/ks03NJibBZXwgzXR/62KXq8+FRNKEy+
                        Ec0yudq7bSaBGalQ3SqLXycKP9/Ct58eI2qRVGa0RwqcieDZIspFCgbAlZ2+qIDU
                        rQ==
                    </ds:X509Certificate>
                </ds:X509Data>
            </ds:KeyInfo>
        </md:KeyDescriptor>
        <md:SingleLogoutService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
                Location="https://localhost:9443/samlsso"
                ResponseLocation="https://localhost:9443/samlsso"/>

        <md:SingleSignOnService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                Location="https://localhost:9443/samlsso"/>

        <md:SingleSignOnService
                Binding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
                Location="https://localhost:9443/samlsso"/>

        <md:SingleSignOnService
                Binding="urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser"
                hoksso:ProtocolBinding="urn:oasis:names:tc:SAML:2.0:bindings:HTTP-POST"
                xmlns:hoksso="urn:oasis:names:tc:SAML:2.0:profiles:holder-of-key:SSO:browser"
                Location="https://localhost:9443/samlsso"/>
    </md:IDPSSODescriptor>
</md:EntityDescriptor>

任何人都可以帮我配置Spring Security SAML以正确启用Holder-of-key配置文件吗?

修改

好的,我的坏。由于IdP不要求客户端证书,似乎我正在使用的这个版本的“WSO2 IS”(v4.5.0),不支持发出SAML HoK主题确认断言(我相应地更新了问题)。我将尝试使用最新版本的WSO2 Identity Server(v5.0.0)并分享结果。

我仍然不确定我的弹簧配置是否正确。

由于

1 个答案:

答案 0 :(得分:0)

上述Spring SAML配置足以在SP端启用Holder-of-key配置文件。我尝试使用SimpleSAMLphp作为IdP并且它有效。

似乎WSO2不支持HoK网络浏览器SSO配置文件(如果我错了请纠正我),而是支持通过安全令牌服务(STS)获取/发出HoK消息。