I'm using Spring Boot 2.4. In my WebSecurityConfig (extends WebSecurityConfigurerAdapter) I have the following piece of code for our dev environment:
@Bean
RelyingPartyRegistrationRepository replyingPartyRegistrationRepository() {
System.err.println("Metadatalocation is ||" + metadataLocation + "||");
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(metadataLocation)
.registrationId("my-id-here")
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
and for staging/production I'd need this version (with key and certificate) based off https://github.com/spring-projects/spring-security-samples/blob/b2310d91fe198138d07bad17b5c86a2f13b698ae/servlet/spring-boot/java/saml2/login/src/main/java/example/SecurityConfiguration.java#L76 because we'll connect with the real idp there.
@Bean
RelyingPartyRegistrationRepository replyingPartyRegistrationRepository(
@Value("classpath:credentials/tls.key") RSAPrivateKey privateKey) {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(metadataLocation)
.registrationId("my-other-id-here")
.signingX509Credentials(
(c) -> c.add(Saml2X509Credential.signing(privateKey, relyingPartyCertificate())))
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
My issue is how to integrate this into one method that can work for both environments. Executing the right code for either version (with and without key/certificate) can be done using an if statement based on application.properties value indicating the environment (or perhaps simply by checking if the RSAPrivateKey exists in this environment or not)
The issue, however, is the injection @Value("classpath:credentials/tls.key") RSAPrivateKey privateKey
which will throw an error if that classpath location does not exist.
attempted solutions
I've tried passing a default value using
@Value("#{\"classpath:credentials/tls.key\" ?: null}")
(and many variations of that) hoping it would insert 'null' if the file cannot be found, but I guess the File Not Found exception occurs as soon as the attempt is made so this doesn't work.I've also tried varations of
Resource resource = resourceLoader.getResource("classpath:credentials/tls.key");
but then how do I convert that Resource into a RSAPrivateKey?I suppose a workaround is to put a fake/empty RSA key file in that location in the dev environment, have it be loaded, and then ignore it, but that feels very hacky..
PS: Part of my problem is that I don't understand how Spring Boot can even 'cast'/convert a classpath file to an RSAPrivateKey object? It works because the injection does succeed if an RSA file is present. I can't seem to find any documentation on how the classpath:
-prefix actually does its magic. All examples of @Value("classpath:...")
involve loading a Resource
Thank you for any insights you could offer.