Expected Behavior Ability to do something like this:
RelyingPartyRegistration.Builder builder;
KeyStore keyStore;
Credential credential = new KeyStoreX509CredentialAdapter(keyStore, "alias", "password".toCharArray());
builder.decryptionX509Credentials(creds -> creds.add(credential))
builder.signingX509Credentials(creds -> creds.add(credential))
Current Behavior Currently have to do something like this:
RelyingPartyRegistration.Builder builder;
KeyStore keyStore;
X509Credential credential = new KeyStoreX509CredentialAdapter(keyStore, "alias", "password".toCharArray());
Saml2X509Credential samlCred = new Saml2X509Credential(
credential.getPrivateKey(),
credential.getEntityCertificate(),
Saml2X509Credential.Saml2X509CredentialType.DECRYPTION,
Saml2X509Credential.Saml2X509CredentialType.SIGNING
);
builder.decryptionX509Credentials(creds -> creds.add(samlCred));
builder.signingX509Credentials(creds -> creds.add(samlCred));
Context
OpenSAML provides org.opensaml.security.credential.Credential
and multiple implementations to cover various useful cases. Spring Security instead provides org.springframework.security.saml2.core.Saml2X509Credential
with much more restricted functionality. However, internally Spring just uses the Saml2X509Credential
to build a Credential
.
Comment From: OrangeDog
This is similar to https://github.com/spring-projects/spring-boot/issues/40610 but they're probably orthogonal issues.
Comment From: jzheaux
In order for Spring Security to use OpenSAML's Credential
interally, I think it would be best to introduce an interface for SamlX509Credential
. I'm not certain on the name, but Saml2X509CredentialAccessor
might work.
I propose doing the following:
- Add the interface
- Provide another implementation that holds and adapts OpenSAML's
X509Credential
- Add the appropriate methods to
RelyingPartyRegistration
that use the new interface - Update
OpenSaml5Template
andOpenSaml4Template
to check for this implementation and extract the underlyingX509Credential
accordingly. The last one might look something like this:
private static BasicX509Credential fromSaml2X509Credential(Saml2X509CredentialAccessor key, String entityId) {
if (key instanceof OpenSamlX509Credential credential) {
return credential.getX509Credential();
}
BasicX509Credential cred = CredentialSupport.getSimpleCredential(key.getCertificate(), key.getPrivateKey());
cred.setEntityId(entityId);
return cred;
}
Comment From: therepanic
Hi, @jzheaux! I guess we would also need to implement current Saml2X509Credential
from Saml2X509CredentialAccessor
? Also we would have to completely replace Saml2X509Credential
with Saml2X509CredentialAccessor
in RelyingPartyRegistration
? You have described the instruction completely clear and if you don't mind you can assign me and I can do it.
Comment From: OrangeDog
In order for Spring Security to use OpenSAML's
Credential
inter[n]ally
To be clear, it already does. But no API is exposed for it, so you currently have to convert it to something else first, and then Spring Security converts it straight back.
The goal here is to use a KeyStore
for SAML credentials in as little code as possible. Both Spring Boot and OpenSAML provide helpful utilities for loading keys from anywhere you could think of, but Spring Security SAML does not accept any of their outputs.