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

Posted

技术标签:

【中文标题】使用来自 Okta 的证书的 SAML 问题【英文标题】:SAML Issue Using Cert From Okta 【发布时间】:2016-11-22 16:25:50 【问题描述】:

我正在尝试将 Okta 集成到已经实施了 Spring Security 的 Spring 应用程序中。我已成功将 spring saml 添加到项目中,并且能够成功登录应用程序。但是它使用的是默认的 java 密钥库,我想按照文档中的建议使用另一个 jks (http://docs.spring.io/spring-security-saml/docs/current/reference/html/security.html)。

关于 jks 的 spring saml 扩展的工作方式,我有几个问题。

    示例 jks 包含两个键。一个是 PrivateKeyEntry,一个是trustedCertEntry。 “trustedCertEntry”是应该从 IDP 收集的公钥吗? 我相信 JKS 用于解密断言消息,而不是用于 https 握手。这个假设正确吗?

使用提供的 JKS 与 apollo 和 startcom 时,我能够成功登录。但是,当我在 Okta 下的 SAML 配置中启用断言加密(加密算法:AES256-CBC,密钥传输算法:RSA-OAEP)时,它开始失败。我相信这是因为我没有使用 IDP 的公钥,所以我获得了我的 Okta 证书文件。

我做了以下创建一个新的 jks 并导入证书文件:

keytool -genkeypair -alias self-signed -keypass default1! -keystore samlKeystore.jks

keytool -importcert -alias okta-pub -file okta.cert -keystore samlKeystore.jks

所以现在我的密钥库如下:

keytool -list -keystore samlKeystore.jks
Enter keystore password:
Keystore type: JKS
Keystore provider: SUN

Your keystore contains 2 entries

okta-pub, Jul 19, 2016, trustedCertEntry,
Certificate fingerprint (SHA1): F2:2C:97:68:47:AF:17:B3:B0:9D:C0:07:09:2F:9A:90:DF:79:E5:CD
self-signed, Jul 19, 2016, PrivateKeyEntry,
Certificate fingerprint (SHA1): 99:21:35:CA:AA:AF:33:44:81:78:67:95:7A:1D:1D:6A:BA:5C:96:5D

我将我的安全上下文文件更新为:

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

当我尝试进行 SAML 登录时,我遇到了这个异常:

[talledLocalContainer] 190716 12.43.03,777    ERROR (Decrypter.java:639) Failed to decrypt EncryptedKey, valid decryption key could not be resolved
[talledLocalContainer] 190716 12.43.03,777    ERROR (Decrypter.java:532) Failed to decrypt EncryptedData using either EncryptedData KeyInfoCredentialResolver or EncryptedKeyResolver + EncryptedKey KeyInfoCredentialResolver
[talledLocalContainer] 190716 12.43.03,778    ERROR (Decrypter.java:143) SAML Decrypter encountered an error decrypting element content
[talledLocalContainer] org.opensaml.xml.encryption.DecryptionException: Failed to decrypt EncryptedData

我已尝试使用此处提到的 JCE 无限强度库:Decrypting encrypted assertion using SAML 2.0 in java using OpenSAML。但这并没有解决我的问题。

有什么建议吗?我创建的 jks 文件是否正确?

编辑 1: 这是完整的堆栈跟踪:

[talledLocalContainer] 190716 13.45.27,717    ERROR (Decrypter.java:143) SAML Decrypter encountered an error decrypting element content
[talledLocalContainer] org.opensaml.xml.encryption.DecryptionException: Failed to decrypt EncryptedData
[talledLocalContainer]  at org.opensaml.xml.encryption.Decrypter.decryptDataToDOM(Decrypter.java:535) ~[xmltooling-1.4.1.jar:?]
[talledLocalContainer]  at org.opensaml.xml.encryption.Decrypter.decryptDataToList(Decrypter.java:442) ~[xmltooling-1.4.1.jar:?]
[talledLocalContainer]  at org.opensaml.xml.encryption.Decrypter.decryptData(Decrypter.java:403) ~[xmltooling-1.4.1.jar:?]
[talledLocalContainer]  at org.opensaml.saml2.encryption.Decrypter.decryptData(Decrypter.java:141) [opensaml-2.6.1.jar:?]
[talledLocalContainer]  at org.opensaml.saml2.encryption.Decrypter.decrypt(Decrypter.java:69) [opensaml-2.6.1.jar:?]
[talledLocalContainer]  at org.springframework.security.saml.websso.WebSSOProfileConsumerImpl.processAuthenticationResponse(WebSSOProfileConsumerImpl.java:199) [spring-security-saml2-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
[talledLocalContainer]  at org.springframework.security.saml.SAMLAuthenticationProvider.authenticate(SAMLAuthenticationProvider.java:87) [spring-security-saml2-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
[talledLocalContainer]  at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:156) [spring-security-core-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.saml.SAMLProcessingFilter.attemptAuthentication(SAMLProcessingFilter.java:87) [spring-security-saml2-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:211) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:166) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at com.aspectsecurity.contrast.teamserver.security.auth.rest.RestAuthenticationFilter.doFilter(RestAuthenticationFilter.java:67) [RestAuthenticationFilter.class:?]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:110) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter.doFilterInternal(WebAsyncManagerIntegrationFilter.java:50) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.session.ConcurrentSessionFilter.doFilter(ConcurrentSessionFilter.java:125) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:87) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.saml.metadata.MetadataGeneratorFilter.doFilter(MetadataGeneratorFilter.java:87) [spring-security-saml2-core-1.0.2.RELEASE.jar:1.0.2.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:342) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy.doFilterInternal(FilterChainProxy.java:192) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:160) [spring-security-web-3.2.9.RELEASE.jar:3.2.9.RELEASE]
[talledLocalContainer]  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:344) [spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
[talledLocalContainer]  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:261) [spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99) [spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
[talledLocalContainer]  at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) [spring-web-4.1.8.RELEASE.jar:4.1.8.RELEASE]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.61]
[talledLocalContainer]  at com.aspectsecurity.contrast.teamserver.webapp.filter.WebSecurityFilter.doFilter(WebSecurityFilter.java:79) [WebSecurityFilter.class:?]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.61]
[talledLocalContainer]  at com.aspectsecurity.contrast.teamserver.webapp.filter.ESAPIThreadLocalFilter.doFilter(ESAPIThreadLocalFilter.java:34) [ESAPIThreadLocalFilter.class:?]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.logging.log4j.web.Log4jServletFilter.doFilter(Log4jServletFilter.java:71) [log4j-web-2.4.1.jar:2.4.1]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:241) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:208) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:220) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:122) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:170) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:950) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:116) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:423) [catalina.jar:7.0.61]
[talledLocalContainer]  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1079) [tomcat-coyote.jar:7.0.61]
[talledLocalContainer]  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:620) [tomcat-coyote.jar:7.0.61]
[talledLocalContainer]  at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:318) [tomcat-coyote.jar:7.0.61]
[talledLocalContainer]  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [?:1.7.0_79]
[talledLocalContainer]  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [?:1.7.0_79]
[talledLocalContainer]  at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-coyote.jar:7.0.61]
[talledLocalContainer]  at java.lang.Thread.run(Thread.java:745) [?:1.7.0_79]

【问题讨论】:

【参考方案1】:

示例 jks 包含两个键。一个是 PrivateKeyEntry 和一个 是trustedCertEntry。 “trustedCertEntry”是公钥吗? 应该从 IDP 那里收集?

是的,您添加到密钥库的 IDP 的公共证书将显示为“trustedCertEntry”。

我相信 JKS 用于解密断言消息,而不是 用于 https 握手。这个假设正确吗?

这是正确的。在这种情况下,JKS 不用于 https。

与文档所述相比,您生成密钥库的方式看起来是正确的。我最近生成了自己的密钥库以使用以下内容:

--generate keystore
keytool -genkeypair -alias mysaml -keypass password -keystore samlKeystore.jks -keyalg RSA -keysize 2048
--export cert for import into IDP
keytool -export -keystore samlKeystore.jks -alias myalias -file mysaml.cer
--add cert form IDP
keytool -importcert -alias myidp -file myidp.cer -keystore samlKeystore.jks

由于遇到一些加密错误,我记得使用 RSA,但不记得是否与您的问题相同。

我建议仔细检查 JCE 无限强度库的安装。很容易安装不正确,即如果您将其解压缩到错误的位置。

【讨论】:

感谢您的信息!关于您提供的 keytool 命令;为什么要将密钥库导出为证书然后再次添加?我从 IDP 获得了一个证书文件,并用它执行了导入命令。您是否刚刚对 RSA 使用了 -keyalg RSA 命令? 第一个命令生成密钥库。第二个命令导出可以加载到 IDP 中的公共证书。第三个是如何加载 IDP 证书的示例。是的,我使用 -keyalg RSA for 使其成为 RSA。 我的问题是我没有从您列出的第二个 keytool 命令导出 .cer 文件。感谢您的帮助! 如果您最终使用 CA 签名证书(根据您的要求),并且 CA 根证书已加载到 IDP,则不再需要手动添加证书。我使用委托证书和 ADFS 作为 IDP 完成了这项工作。如果它是自签名的,则进行签名验证的唯一方法是手动将证书加载到 IDP 中。 您没有导出私钥。那将是非常糟糕的。它正在创建一个公共证书,您可以通过打开 .cer 文件并查看证书的详细信息来验证它。

以上是关于使用来自 Okta 的证书的 SAML 问题的主要内容,如果未能解决你的问题,请参考以下文章

MSIS0037:未找到颁发者的签名验证证书

如何使用 SP 密钥库 spring saml 中的证书

SAML SP:信任 IdP 的证书

使用 SAML 2.0 的自签名证书

使用自签名证书进行 Saml 2 断言

Spring SAML 安全证书缓存问题