HTTP 状态 401 - 身份验证失败:解码传入 SAML 消息时出错

HTTP Status 401 - Authentication Failed: Error decoding incoming SAML message

我按照 spring saml tutorial 中的描述做了所有事情,除了我添加

<dependency>
    <groupId>xml-apis</groupId>
    <artifactId>xml-apis</artifactId>
    <version>1.4.01</version>
</dependency>

在 pom.xml 中克服 w3.dom class 未找到的问题。当我 运行 示例项目时,我得到了 HTTP Status 401 - Authentication Failed: Error decoding incoming SAML message 在浏览器中,同时在控制台中 (CertPathPKIXTrustEvaluator.java:81) ERROR org.springframework.security.saml.trust.MetadataCredentialResolver - PKIX path construction failed for untrusted credential: [subjectName='CN=idp.ssocircle.com' |credential entityID='https://idp.ssocircle.com']: unable to find valid certification path to requested target

包流屏幕截图:

第 2 天: 我 运行 keytool -importcert -alias identtrustca -file ca.cer -keystore samlKeystore.jks 并将 security/samlKeystore.jks 替换为新生成的。 securityContext.xml:

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

那么我有:

Caused by: java.io.IOException: Keystore was tampered with, or password was incorrect
    at sun.security.provider.JavaKeyStore.engineLoad(Unknown Source)
    at sun.security.provider.JavaKeyStore$JKS.engineLoad(Unknown Source)
    at java.security.KeyStore.load(Unknown Source)
    at org.springframework.security.saml.key.JKSKeyManager.initialize(JKSKeyManager.java:117)
    ... 57 more
Caused by: java.security.UnrecoverableKeyException: Password verification failed
    ... 61 more

然后我把密码改成使用时输入的密码 keytool:

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

然后控制台说:

Servlet.service() for servlet [jsp] in context with path [/spring-security-saml2-sample] threw exception
java.lang.RuntimeException: Key for alias apollo not found
    at org.springframework.security.saml.metadata.MetadataGenerator.getServerKeyInfo(MetadataGenerator.java:201)

所以我把apollo改成identtrustca:

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

控制台说:

Servlet.service() for servlet [jsp] in context with path [/spring-security-saml2-sample] threw exception
java.lang.UnsupportedOperationException: trusted certificate entries are not password-protected

然后我读到this and this,所以我删除了入口元素(我相信它是私钥的东西),它变成了:

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

现在问题变成了:

Servlet.service() for servlet [jsp] in context with path [/spring-security-saml2-sample] threw exception
java.lang.RuntimeException: Key with alias identtrustca doesn't have a private key

第 2 天第 2 部分: 现在我明白了,与其创建新的密钥库,不如使用旧的 samlKeystore.jks。如果使用 keytool -list -V -keystore d:\temp\samlKeystore.jks 可以看到它包含 3 个项目(最初它有 2 个)。

我不明白为什么 SP 从 IdP 元数据中获取 public 密钥,但仍然需要 IdP 的 ca.cer?我相信来自 auth 网站的 ca.cer 是 IdP 的证书,尽管它与我通过 openssl s_client -connect idp.ssocircle.com:443 -showcerts

获得的不同

此外,现在我得到的不是 Error decoding incoming SAML message,而是 HTTP Status 401 - Authentication Failed: Response issue time is either too old or with date in the future

第 3 天 当我启动 SP,从 chrome 和 firefox 访问 http://localhost:8080/spring-security-saml2-sample/ 时,当我在一个资源管理器中按下全局注销并刷新另一个时,它没有显示注销页面。我想对于 SSO,从同一个 SP 的全局注销应该忽略多会话,例如,一旦我在一个 "login" 中全局注销,我应该在另一个中自动注销,我应该看到一个注销-其他资源管理器中的页面(如果我刷新)。其实对于多个SP,一个我在一个注销,我曾经登录过的所有SP应该都能看到注销。

第 n 天 通过更改 saml 项目 url,需要修改 idp.ssocircle.com 中的元数据(管理元数据)。否则,idp 网站会显示错误。这是写在docs/reference/htmlsingle/index.html

IDP 元数据中的证书用于对 SAML XML 文档进行数字签名。您失败的证书来自 www.ssocircle.com 的 HTTPS 端点,您的 Spring SAML 在工件解析期间调用该端点。这两个证书通常不同。

SSOCircle 最近更改了为 www.ssocircle.com 颁发证书的证书颁发机构, 中描述的操作是让该 CA 受信任。

您最近的错误可能是由于您的 Spring SAML 机器上没有时间正确同步造成的。