OKTA 的 Spring Security Saml 配置错误

Posted

技术标签:

【中文标题】OKTA 的 Spring Security Saml 配置错误【英文标题】:Spring Security Saml configuration error with OKTA 【发布时间】:2018-07-12 19:09:41 【问题描述】:

可能是这个问题之前已经回答了,但我找不到我的问题的任何答案,所以我问你我的问题。

我正在尝试使用 OKTA 实现基于 SAML2 的 SSO。为此,我在 oktapreviw 创建了一个开发帐户。我在此链接下载了 spring securty saml2 示例 http://projects.spring.io/spring-security-saml/#quick-start 并通过使用此链接 https://docs.spring.io/spring-security-saml/docs/1.0.x/reference/html/chapter-idp-guide.html#d5e1816

我采用了我的配置,这在 localhost 上运行良好

现在我们来到现实世界,我尝试在测试环境中进行配置。在测试环境中,我们将安装了 HAProxy 的 linux 服务器作为 Web 服务器,在 haproxy 后面,我们的服务提供程序在 Tomcat 上运行。

目前我们正在为我们的 haproxy 使用自动签名证书。但现在我的项目不工作,它给了我错误:

org.springframework.security.authentication.AuthenticationServiceException: Incoming SAML message is invalid

我在 SecurityContext.xml 中的配置是:

<!-- Enable auto-wiring -->
<context:annotation-config/>

<!-- Scan for auto-wiring classes in spring saml packages -->
<context:component-scan base-package="org.springframework.security.saml"/>

<!-- Unsecured pages -->
<security:http security="none" pattern="/favicon.ico"/>
<security:http security="none" pattern="/images/**"/>
<security:http security="none" pattern="/css/**"/>
<security:http security="none" pattern="/logout.jsp"/>
<security:http security="none" pattern="/ids/serveur/**"/>
<security:http security="none" pattern="/ids/geoportal/**"/>
<security:http security="none" pattern="/rest/static/**"/>

<!-- Security for the administration UI -->
<security:http pattern="/saml/web/**" use-expressions="false">
    <security:access-denied-handler error-page="/saml/web/metadata/login"/>
    <security:form-login login-processing-url="/saml/web/login" login-page="/saml/web/metadata/login" default-target-url="/saml/web/metadata"/>
    <security:intercept-url pattern="/saml/web/metadata/login" access="IS_AUTHENTICATED_ANONYMOUSLY"/>
    <security:intercept-url pattern="/saml/web/**" access="ROLE_ADMIN"/>
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
</security:http>

<!-- Secured pages with SAML as entry point -->
<security:http entry-point-ref="samlEntryPoint" use-expressions="false">
    <security:intercept-url pattern="/**" access="IS_AUTHENTICATED_FULLY"/>
    <security:custom-filter before="FIRST" ref="metadataGeneratorFilter"/>
    <security:custom-filter after="BASIC_AUTH_FILTER" ref="samlFilter"/>
</security:http>

<!-- Filters for processing of SAML messages -->
<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/logout/**" filters="samlLogoutFilter"/>
        <security:filter-chain pattern="/saml/metadata/**" filters="metadataDisplayFilter"/>
        <security:filter-chain pattern="/saml/SSO/**" filters="samlWebSSOProcessingFilter"/>
        <security:filter-chain pattern="/saml/SSOHoK/**" filters="samlWebSSOHoKProcessingFilter"/>
        <security:filter-chain pattern="/saml/SingleLogout/**" filters="samlLogoutProcessingFilter"/>
        <security:filter-chain pattern="/saml/discovery/**" filters="samlIDPDiscovery"/>
    </security:filter-chain-map>
</bean>

<!-- Handler deciding where to redirect user after successful login -->
<bean id="successRedirectHandler"
      class="org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler">
    <property name="defaultTargetUrl" value="/"/>
</bean>

<!-- Use the following for interpreting RelayState coming from unsolicited response as redirect URL:
<bean id="successRedirectHandler" class="org.springframework.security.saml.SAMLRelayStateSuccessHandler">
   <property name="defaultTargetUrl" value="/" />
</bean>
-->

<!-- Handler deciding where to redirect user after failed login -->
<bean id="failureRedirectHandler"
      class="org.springframework.security.web.authentication.SimpleUrlAuthenticationFailureHandler">
    <property name="useForward" value="true"/>
    <property name="defaultFailureUrl" value="/error.jsp"/>
</bean>

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

<security:authentication-manager alias="authenticationManager">
    <!-- Register authentication manager for SAML provider -->
    <security:authentication-provider ref="samlAuthenticationProvider"/>
    <!-- Register authentication manager for administration UI -->
    <security:authentication-provider>
        <security:user-service id="adminInterfaceService">
            <security:user name="admin" password="admin" authorities="ROLE_ADMIN"/>
        </security:user-service>
    </security:authentication-provider>
</security:authentication-manager>

<!-- Logger for SAML messages and events -->
<bean id="samlLogger" class="org.springframework.security.saml.log.SAMLDefaultLogger"/>

<!-- Central storage of cryptographic keys -->
<bean id="keyManager" class="org.springframework.security.saml.key.JKSKeyManager">
    <constructor-arg value="classpath:security/samlKeystore.jks"/>
    <constructor-arg type="java.lang.String" value="nalle123"/>
    <constructor-arg>
        <map>
            <entry key="apollo" value="nalle123"/>
        </map>
    </constructor-arg>
    <constructor-arg type="java.lang.String" value="apollo"/>
</bean>

<!-- Entry point to initialize authentication, default values taken from properties file -->
<bean id="samlEntryPoint" class="org.springframework.security.saml.SAMLEntryPoint">
    <property name="defaultProfileOptions">
        <bean class="org.springframework.security.saml.websso.WebSSOProfileOptions">
            <property name="includeScoping" value="false"/>
        </bean>
    </property>
</bean>

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

<!-- 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="extendedMetadata">
                <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                    <property name="idpDiscoveryEnabled" value="false"/>
                </bean>
            </property>
        </bean>
    </constructor-arg>
</bean>

<!-- The filter is waiting for connections on URL suffixed with filterSuffix and presents SP metadata there -->
<bean id="metadataDisplayFilter" class="org.springframework.security.saml.metadata.MetadataDisplayFilter"/>

<!-- Configure HTTP Client to accept certificates from the keystore for HTTPS verification -->

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


<!-- IDP Metadata configuration - paths to metadata of IDPs in circle of trust is here -->
<bean id="metadata" class="org.springframework.security.saml.metadata.CachingMetadataManager">
    <constructor-arg>
        <list>
            <!-- Example of classpath metadata with Extended Metadata -->
            <bean class="org.springframework.security.saml.metadata.ExtendedMetadataDelegate">
                <constructor-arg>
                    <bean class="org.opensaml.saml2.metadata.provider.ResourceBackedMetadataProvider">
                        <constructor-arg>
                            <bean class="java.util.Timer"/>
                        </constructor-arg>
                        <constructor-arg>
                            <bean class="org.opensaml.util.resource.ClasspathResource">
                                <constructor-arg value="/metadata/okta.xml"/>
                            </bean>
                        </constructor-arg>
                        <property name="parserPool" ref="parserPool"/>
                    </bean>
                </constructor-arg>
                <constructor-arg>
                    <bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
                    </bean>
                </constructor-arg>
            </bean>
            <!-- Example of HTTP metadata without Extended Metadata -->
            <bean class="org.opensaml.saml2.metadata.provider.HTTPMetadataProvider">
                <!-- URL containing the metadata -->
                <constructor-arg>
                    <value type="java.lang.String">https://dev-880700.oktapreview.com/app/exkdlhbscqPei3k6d0h7/sso/saml/metadata</value>
                </constructor-arg>
                <!-- Timeout for metadata loading in ms -->
                <constructor-arg>
                    <value type="int">15000</value>
                </constructor-arg>
                <property name="parserPool" ref="parserPool"/>
            </bean>
            <!-- Example of file system metadata without Extended Metadata -->
            <!--
            <bean class="org.opensaml.saml2.metadata.provider.FilesystemMetadataProvider">
                <constructor-arg>
                    <value type="java.io.File">/usr/local/metadata/idp.xml</value>
                </constructor-arg>
                <property name="parserPool" ref="parserPool"/>
            </bean>
            -->
        </list>
    </constructor-arg>
    <!-- OPTIONAL used when one of the metadata files contains information about this service provider -->
    <!-- <property name="hostedSPName" value=""/> -->
    <!-- OPTIONAL property: can tell the system which IDP should be used for authenticating user by default. -->
    <!-- <property name="defaultIDP" value="http://localhost:8080/opensso"/> -->
</bean>

<!-- SAML Authentication Provider responsible for validating of received SAML messages -->
<bean id="samlAuthenticationProvider" class="org.springframework.security.saml.SAMLAuthenticationProvider">
    <!-- OPTIONAL property: can be used to store/load user data after login -->
    <!--
    <property name="userDetails" ref="bean" />
    -->
</bean>

<!-- Provider of default SAML Context -->
<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderImpl"/>

<!-- Processing filter for WebSSO profile messages -->
<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>

<!-- 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>

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

<!-- 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>

<!-- 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>

<!-- 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>

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

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

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

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

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

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

<!-- 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>

<!-- Initialization of OpenSAML library-->
<bean class="org.springframework.security.saml.SAMLBootstrap"/>

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

<!-- 
    XML parser pool needed for OpenSAML parsing

    WARNING: If customizing a ParserPool implementation See https://shibboleth.net/community/advisories/secadv_20131213.txt
             Specifically the following should be explicitly set to avoid exploits:

             1) set pool property 'expandEntityReferences' to 'false'
             2) set feature 'javax.xml.XMLConstants.FEATURE_SECURE_PROCESSING' to true
             3) set feature 'http://apache.org/xml/features/disallow-doctype-decl' to true. This is a Xerces-specific feature,
                including derivatives such as the internal JAXP implementations supplied with the Oracle and OpenJDK JREs. For
                other JAXP implementations, consult the documentation for the implementation for guidance on how to achieve a
                similar configuration.
-->
<bean id="parserPool" class="org.opensaml.xml.parse.StaticBasicParserPool" init-method="initialize"/>

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

现在我有两个假设:

    我的自动签名证书是否对我造成了问题 或者我必须在某处声明此自动签名证书的配置

有关信息:我在 haproxy 中声明了该项目,并且我的没有安全性的页面可以通过 HAProxy 访问。我还测试了帖子 Spring-SAML : Incoming SAML message is invalid 中给出的解决方案,但我仍然有同样的问题。

非常感谢您的帮助

阿亚兹

编辑 05 Féverier:

我测试过,这里是我可以提取日志文件的信息:

URI“#id51308797331193271793210762”验证成功 引用具有类型 使用提供的凭据中的密钥验证签名 使用候选凭据的签名验证成功 使用 KeyInfo 派生凭据成功验证签名 正在尝试建立对 KeyInfo 派生凭据的信任 无法根据受信任的密钥验证不受信任的凭据 根据受信任的密钥成功验证不受信任的凭据 成功建立对 KeyInfo 派生凭据的信任 协议消息签名验证成功,消息类型:urn:oasis:names:tc:SAML:2.0:protocolResponse 通过协议消息签名对上下文发布者实体 ID http://www.okta.com/exkdlhbscqPei3k6d0h7 的身份验证成功 成功解码消息。 根据接收方端点检查 SAML 消息的预期目标端点 预期的消息目标端点:https://dev-XXX.XXX.net/accessids/saml/SSO 实际消息接收端点:http://dev-XXX.XXX.net/accessids/saml/SSO SAML 消息预期目标端点“https://dev-XXX.XXX.net/accessids/saml/SSO”与接收端点“http://dev-XXX.XXX.net/accessids/saml/SSO”不匹配 传入的 SAML 消息无效 org.opensaml.xml.security.SecurityException:SAML 消息预期目标端点与收件人端点不匹配 在 org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.checkEndpointURI(BaseSAMLMessageDecoder.java:217) 在 org.opensaml.saml2.binding.decoding.BaseSAML2MessageDecoder.decode(BaseSAML2MessageDecoder.java:72) 在 org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:105) 在 org.springframework.security.saml.processor.SAMLProcessorImpl.retrieveMessage(SAMLProcessorImpl.java:172) 在 org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:77) 在 org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:195) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:166) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87) 在 org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) 在 org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) 在 org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) 在 org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) 在 org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259) 在 org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:240) 在 org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:207) 在 org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:212) 在 org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:94) 在 org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:504) 在 org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:141) 在 org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) 在 org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) 在 org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:88) 在 org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:502) 在 org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1132) 在 org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:684) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1533) 在 org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1489) 在 java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

【问题讨论】:

在 log4j.properties 文件中将日志级别改为 debug 后能否分享完整的日志?? 谢谢阿甘。我刚刚共享了日志文件的最后几行。再次感谢 我也想这样做,但在此链接projects.spring.io/spring-security-saml/#quick-start 上找不到示例。我是 spring-security 的新手,使用 saml @user3363891 【参考方案1】:

消息端点不匹配:

SAML 消息的预期目标端点与收件人不匹配 端点

期望将消息发送到(预期消息目标端点):

https://dev-XXX.XXX.net/accessids/saml/SSO

但它被要求发送到(实际消息接收器端点):

http://dev-XXX.XXX.net/accessids/saml/SSO

所以元数据可能是说它应该发送到https,但它被发送到http。 URL 必须完全匹配。

检查您的 haproxy 是否将其从 https 更改为 http

【讨论】:

【参考方案2】:

大家好,感谢您的帮助,

最后我能够解决这个问题,所以我决定在论坛上发布这个来帮助像我这样可能面临类似问题的其他初学者。

一开始我只使用一个 tomcat,然后在 OKTA 上创建了应用程序。我下载并配置了元数据 xml 文件。在 OKTA 项目中,SSO URL 和受众限制 URL 为 http://localhost:8080/....

项目运行良好。然后我在我们的测试环境中使用 HAProxy 部署了项目,并且经常出现错误(如上所述):

org.springframework.security.authentication.AuthenticationServiceException:传入的 SAML 消息无效

有关信息,我修改了 OKTA 项目中的 URL,并使用了 HAProxy 的 URL,即https://dev-xxx.xxx.grdf.net

我在 Windows 服务器上进行开发受到限制,我们的测试和生产环境是基于红帽的。所以我在我的 Windows 机器上安装了 Apache 并创建了一个自动签名证书。所以我试图模拟我的测试环境。在 OKTA 项目中,我使用了 URL https://localhost/,并产生了与 HAProxy 类似的错误。

当我分析日志时,我得到了一个没有声明的印象

entityBaseURL

在第一次调用时,应用程序下载了带有我的端点不知道的 URL 的元数据。所以我添加了这一行来解决我在开发机器上的问题:

<property name="entityBaseURL" value="https://localhost/XXX"/>

但是,当我在 HAProxy 上进行测试时,我又遇到了一个错误:

SAML 消息预期目标端点“https://dev-XXX.XXX.net/accessids/saml/SSO”与接收端点“http://dev-XXX.XXX.net/accessids/saml/SSO”不匹配 传入的 SAML 消息无效 org.opensaml.xml.security.SecurityException:SAML 消息的预期目标端点与 org.opensaml.common.binding.decoding.BaseSAMLMessageDecoder.checkEndpointURI(BaseSAMLMessageDecoder.java:217) 处的收件人端点不匹配

(我昨天也发过)

然后在查看文档时,我找到了关于负载均衡器的一章,因此我修改了配置,并在 SAMLContextProviderImpl 的位置使用了 SAMLContextProviderLB。所以我使用了这个配置:

<bean id="contextProvider" class="org.springframework.security.saml.context.SAMLContextProviderLB">
        <property name="scheme" value="https"/>
        <property name="serverName" value="dev-XXX.XXX.net"/>
        <property name="serverPort" value="443"/>
        <property name="includeServerPortInRequestURL" value="false"/>
        <property name="contextPath" value="/XXXXX"/>
    </bean>

我还在我的 XML 文件中留下了 entityBaseURL:

<bean id="metadataGeneratorFilter" class="org.springframework.security.saml.metadata.MetadataGeneratorFilter">
        <constructor-arg>
            <bean class="org.springframework.security.saml.metadata.MetadataGenerator">
                <property name="entityBaseURL" value="https://dev-XXX.XXX.net/XXXXXX"/>
            </bean>
        </constructor-arg>
    </bean>

这两个参数使我的配置在测试环境中可执行。如果您有任何建议,问题,请随时与我联系。

祝你有美好的一天

【讨论】:

您好,我也遇到了同样的问题?你能帮忙***.com/questions/63901706/…

以上是关于OKTA 的 Spring Security Saml 配置错误的主要内容,如果未能解决你的问题,请参考以下文章

OKTA 的 Spring Security Saml 配置错误

使用 Spring Security OAuth2 和 Okta 处理基于 url 的 RBAC

okta oauth2 Spring security 所有受保护的页面重定向到登录

使用来自 Okta 的证书的 SAML 问题

Spring Security SAML 中的刷新会话

spring-security-oauth2 JwkTokenStore 与自定义用户详细信息服务