21

I have generated testIdp.cer file by copying 509 entry of the IDP I am planning to connect. Then I created JKS file by executing the following command

keytool -importcert -alias adfssigning -keystore C:\Users\user\Desktop\samlKeystore.jks -file    C:\Users\user\Desktop\testIdp.cer

When executed it has asked to enter a password for which I have given a password. For the question "Trust this certificate? [no]:", I have given "y" as input. Message came out as "Certificate was added to keystore".

Then I have configured the following details in 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>

But when I run the application, I get the following two exceptions when the server is starting and when I load the homepage of the application. Can anyone let me know if I am missing anything else.

This exception is occuring when I start the server

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)

This exception is occuring when I run the homepage of my application

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)
SM KUMAR
  • 475
  • 2
  • 8
  • 13
  • 1
    Hi Kumar, How you solved your issue ? I too face the same kind of problem. Kindly go through this link. http://stackoverflow.com/questions/33369965/trusted-certificate-entries-are-not-password-protected-java Please guide me a solution – praneeth Oct 28 '15 at 14:55

7 Answers7

11

Your .cer certificate contains only a public key, you mustn't define <entry key="adfssigning" value="mypassword"/> for public keys; it can only be used for private ones. Simply take out the adfssigning entry and make sure to include a private key instead - just like in the Spring SAML sample application.

The SAML keystore can contain two basic types of keys - public and private ones (plus their certificates). Each key has an alias which is used to refer to it. The keystore itself can be protected by a password (provided in the second constructor parameter), plus each private key can be also protected by an additional password (these are defined in third parameter of the constructor in a map of alias->password). The public keys which you import to the keystore (just like you did with the command above) mustn't be defined in this map. They will be automatically available after being imported without additional declarations. For Spring SAML to work, the keystore must contain at least one private key (the sample application contains private key with alias apollo) and its alias needs to be provided in the third parameter of the constructor.

Your example above fails, because you have imported a public key, but included it in the map which can only be used for private keys.

Vladimír Schäfer
  • 15,375
  • 2
  • 51
  • 71
  • @vschafer Do you mean to say that nalle123 mapped to argument 2 and 3 of the constructor in the spring SAML sample application correspond to the same private key? As per documentation argument 2 corresponds to password of the keystore file. In the spring saml sample application, I believe that it is just a coincidence that password of the keystore file and the private key are the same. How Could I retrieve the private key? – SM KUMAR Oct 03 '14 at 09:31
  • @vschafer Do you mean to say that nalle123 mapped to argument 2 and 3 of the constructor in the spring SAML sample application correspond to the same private key? As per documentation argument 2 corresponds to password of the keystore file. In the spring saml sample application, I believe that it is just a coincidence that password of the keystore file and the private key are the same. How can I create JKS? I currently have only the public certificate which is added into a .cer file and I am using the command keytool -importcert -alias adfssigning -keystore samlKeystore.jks -file testIdp.cer – SM KUMAR Oct 03 '14 at 10:09
  • I've updated the answer with additional explanation. For details on how to create JKS and import keys please consult the Spring SAML manual or Java documentation. – Vladimír Schäfer Oct 04 '14 at 14:07
  • 1
    @vschafer I have refered the Spring SAML manual. But I am still facing issues with the private key. I have created a JKS file with the command as mentioned in the manual which is as follows `keytool -genkeypair -alias some-alias -keypass changeit -keystore samlKeystore.jks` – SM KUMAR Oct 06 '14 at 11:18
  • What kind of issues are you facing - any exceptions, errors - where have you posted them? – Vladimír Schäfer Oct 06 '14 at 14:06
11

Vladimir answered correctly the question why the error occurs. In my answer I want to show how you can import a certificate to the keystore to solve that problem:

You have to import the certificate and private key which could not be done directly by keytool.

The detailed described solution is found here: https://stackoverflow.com/a/8224863/1909531

Here's an excerpt:

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]
Community
  • 1
  • 1
Matthias M
  • 12,906
  • 17
  • 87
  • 116
4

After trying everything, deleting and recreating the jks files multiple times, nothing worked. I then happened to scroll this page and found Pankaj's answer and that was it. I was using the wrong alias in the properties file. As correctly mentioned by Pankaj, We should be using the alias of the PrivateKeyEntry and not the trustedCertEntry in the properties file.

Steps are then as follows :

  1. Create a JKS file using the command below. This would also add the PrivateKeyEntry to the JKS file.

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

  2. Import the IDP cert into it. This would add the trustedCertEntry to the file.

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

  3. Modify your properties file to use the alias you gave while creating the JKS file i.e. the alias for PrivateKeyEntry

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

  4. restart your server.

One other mistake I did in the beginning was that I got a metadata.xml file from IDP and had to create a cert file. I forgot to add the "-----BEGIN CERTIFICATE-----" and "-----END CERTIFICATE-----" before and after the cert, which then generated an invalid cert and gave me grief. Teh cert should be in the format below

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

This error occurs also when you don't have a private key in your Keystore. SAML uses the private key to generate the Service provider meta data used to communicate with the IDP. Just add one to the Keystore like this:

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

Fill in the questions and set validity to an appropriate number of days. (In my example it's valid for 100 years) Remember to add the public certificate from IDP. Then you should be ready to go.

1

For those looking for answers in java config please comment out the line passwords.put("mykeyalias", "mystorepass"); .... shown in code snippet below.

@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");
}
1

After all the above solutions,if the problem is still there, Probably worth checking whether your are using correct alias while using the cert in keystore. in my case, due to having multiple cert entry, i entered incorrect alias(in fact one with Entry type: trustedCertEntry which caused issue. while you should use one with Entry type: PrivateKeyEntry for that just check the existing cert using

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

Get the public certificate using openssl command:

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

Import it into the Keystore:

keytool -import -alias "new-qet-alias" -keystore /usr/share/tomcat8/webapps/ROOT/WEB-INF/classes/saml/samlKeystore.jks -file mycertfile.pem
Velu
  • 1,681
  • 1
  • 22
  • 26