受信任的证书条目不是受密码保护的SpringSAML



我已经通过复制我计划连接的IDP的509条目生成了testIdp.cer文件。然后我通过执行以下命令创建了JKS文件

keytool -importcert -alias adfssigning -keystore C:UsersuserDesktopsamlKeystore.jks -file    C:UsersuserDesktoptestIdp.cer

当执行时,它要求输入一个我已经给出密码的密码。对于问题"信任此证书?[no]:",我给出了"y"作为输入。消息显示为"证书已添加到密钥库"。

然后我在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="mypassword"/>
    <constructor-arg>
        <map>
            <entry key="adfssigning" value="mypassword"/>
        </map>
    </constructor-arg>
    <constructor-arg type="java.lang.String" value="adfssigning"/>
</bean>
<bean class="org.springframework.security.saml.metadata.ExtendedMetadata">
  <property name="alias" value="adfssigning" />
  <property name="signingKey" value="adfssigning"/>     
</bean>

但当我运行应用程序时,当服务器启动和加载应用程序主页时,我会遇到以下两个异常。如果我遗漏了什么,有人能告诉我吗。

当我启动服务器时发生此异常

Caused by: org.opensaml.saml2.metadata.provider.FilterException: Signature trust establishment failed for metadata entry
at org.opensaml.saml2.metadata.provider.SignatureValidationFilter.verifySignature(SignatureValidationFilter.java:327)
at org.opensaml.saml2.metadata.provider.SignatureValidationFilter.processEntityGroup(SignatureValidationFilter.java:240)
at org.opensaml.saml2.metadata.provider.SignatureValidationFilter.doFilter(SignatureValidationFilter.java:158)
at org.opensaml.saml2.metadata.provider.AbstractMetadataProvider.filterMetadata(AbstractMetadataProvider.java:493)
at org.opensaml.saml2.metadata.provider.AbstractReloadingMetadataProvider.processNonExpiredMetadata(AbstractReloadingMetadataProvider.java:395)

当我运行应用程序的主页时,会出现此异常

java.lang.UnsupportedOperationException: trusted certificate entries are not password-protected
at java.security.KeyStoreSpi.engineGetEntry(Unknown Source)
at java.security.KeyStore.getEntry(Unknown Source)
at org.opensaml.xml.security.credential.KeyStoreCredentialResolver.resolveFromSource(KeyStoreCredentialResolver.java:132)

您的.cer证书只包含公钥,不能为公钥定义<entry key="adfssigning" value="mypassword"/>;它只能用于私人用途。只需取出adfssigning条目,并确保包含一个私钥,就像SpringSAML示例应用程序中一样。

SAML密钥库可以包含两种基本类型的密钥——公钥和私钥(以及它们的证书)。每个密钥都有一个用来引用它的别名。密钥库本身可以由密码保护(在第二个构造函数参数中提供),每个私钥也可以由一个额外的密码保护(这些密码在alias->password映射中的构造函数的第三个参数中定义)。导入到密钥库的公钥(就像上面的命令一样)不能在这个映射中定义。它们将在导入后自动可用,无需额外声明。为了使Spring SAML工作,密钥库必须至少包含一个私钥(示例应用程序包含别名为apollo的私钥),并且其别名需要在构造函数的第三个参数中提供。

上面的示例失败了,因为您导入了一个公钥,但将其包含在只能用于私钥的映射中。

Vladimir正确回答了为什么发生错误的问题。在我的回答中,我想向展示如何将证书导入密钥库以解决该问题:

您必须导入证书私钥,这是keytool无法直接完成的。

详细描述的解决方案如下:https://stackoverflow.com/a/8224863/1909531

摘录如下:

openssl pkcs12 -export -in server.crt -inkey server.key 
           -out server.p12 -name [some-alias] 
           -CAfile ca.crt -caname root
keytool -importkeystore 
    -deststorepass [changeit] -destkeypass [changeit] -destkeystore server.keystore 
    -srckeystore server.p12 -srcstoretype PKCS12 -srcstorepass some-password 
    -alias [some-alias]

在尝试了所有操作,多次删除和重新创建jks文件后,都没有成功。然后我碰巧滚动了一下这个页面,找到了Pankaj的答案,就这样。我在属性文件中使用了错误的别名。正如Pankaj正确提到的,我们应该在属性文件中使用PrivateKeyEntry的别名,而不是trustedCertEntry。

步骤如下:

  1. 使用下面的命令创建一个JKS文件。这也会将PrivateKeyEntry添加到JKS文件中。

    keytool-genkeypair-alias some_alias-keypass some_password-keyalg RSA-keysize 2048-keystore samlKeystore.jks-validity 1825

  2. 将IDP证书导入其中。这会将trustedCertEntry添加到文件中。

    keytool-importcert-alias some_other_alias-file file_name-keystore samlKeystore.jks

  3. 修改您的属性文件以使用您在创建JKS文件时提供的别名,即PrivateKeyEntry 的别名

    sso.keystore.privatekey.alias=some_aliassso.keystore.default.certificate.alias=some_alias

  4. 重新启动服务器。

我一开始犯的另一个错误是,我从IDP获得了一个metadata.xml文件,并且必须创建一个cert文件。我忘了加上"-----开始证书-----";以及"-----结束证书-----";在证书前后,这产生了一个无效的证书,让我很难过。证书应采用以下的格式

-----BEGIN CERTIFICATE-----
BLAH-BLAH-BLAH-CERT
-----END CERTIFICATE-----

当您的密钥库中没有私钥时,也会发生此错误。SAML使用私钥生成用于与IDP通信的服务提供商元数据。只需像这样在密钥库中添加一个:

keytool -genkey -v -keystore some_key_store.jks -alias some_alias -keyalg RSA -keysize 2048 -validity 36500

填写问题并将有效期设置为适当的天数。(在我的例子中,它的有效期为100年)请记住添加来自IDP的公共证书。那么你应该准备好出发了。

对于那些在java配置中寻找答案的人,请注释掉这行passwords.put("mykeyalias","mystorepass")。。。。如下面的代码片段所示。

@Bean
public KeyManager keyManager() {
    DefaultResourceLoader loader = new DefaultResourceLoader();
    Resource storeFile = loader.getResource("classpath:saml-keystore.jks");
    Map<String, String> passwords = new HashMap<>();
    // passwords.put("mykeyalias", "mystorepass");
    return new JKSKeyManager(storeFile, "mystorepass", passwords, "mykeyalias");
}

在以上所有解决方案之后,如果问题仍然存在,可能值得检查您在使用密钥库中的证书时是否使用了正确的别名。在我的情况下,由于有多个证书条目,我输入了不正确的别名(实际上是条目类型为trustedCertEntry的别名,这导致了问题。而您应该使用条目类型为PrivateKeyEntry的别名为此,只需使用检查现有证书

keytool -list -keystore "$JKS_CERT_PATH"  -storepass "$JKS_CERT_PASSPHRASE"  -noprompt -v

使用openssl命令获取公共证书:

openssl s_client -showcerts -connect iam-sso.google.net:443 </dev/null 2>/dev/null|openssl x509 -outform PEM >mycertfile.pem

将其导入密钥库:

keytool -import -alias "new-qet-alias" -keystore /usr/share/tomcat8/webapps/ROOT/WEB-INF/classes/saml/samlKeystore.jks -file mycertfile.pem

最新更新