1717package org .springframework .boot .autoconfigure .security .saml2 ;
1818
1919import java .io .InputStream ;
20+ import java .security .GeneralSecurityException ;
21+ import java .security .Key ;
22+ import java .security .KeyStore ;
23+ import java .security .PrivateKey ;
24+ import java .security .cert .Certificate ;
2025import java .security .cert .CertificateFactory ;
2126import java .security .cert .X509Certificate ;
2227import java .security .interfaces .RSAPrivateKey ;
2530import java .util .Map ;
2631import java .util .function .Consumer ;
2732
33+ import org .springframework .beans .factory .ObjectProvider ;
2834import org .springframework .boot .autoconfigure .condition .ConditionalOnMissingBean ;
2935import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .AssertingParty ;
3036import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .AssertingParty .Verification ;
37+ import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .Bundle ;
3138import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .Decryption ;
3239import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .Registration ;
33- import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .Registration .Signing ;
40+ import org .springframework .boot .autoconfigure .security .saml2 .Saml2RelyingPartyProperties .Registration .Signing . Credential ;
3441import org .springframework .boot .context .properties .PropertyMapper ;
42+ import org .springframework .boot .ssl .SslBundle ;
43+ import org .springframework .boot .ssl .SslBundleKey ;
44+ import org .springframework .boot .ssl .SslBundles ;
3545import org .springframework .context .annotation .Bean ;
3646import org .springframework .context .annotation .Conditional ;
3747import org .springframework .context .annotation .Configuration ;
5767 * @author Moritz Halbritter
5868 * @author Lasse Lindqvist
5969 * @author Lasse Wulff
70+ * @author Scott Frederick
6071 */
6172@ Configuration (proxyBeanMethods = false )
6273@ Conditional (RegistrationConfiguredCondition .class )
6374@ ConditionalOnMissingBean (RelyingPartyRegistrationRepository .class )
6475class Saml2RelyingPartyRegistrationConfiguration {
6576
6677 @ Bean
67- RelyingPartyRegistrationRepository relyingPartyRegistrationRepository (Saml2RelyingPartyProperties properties ) {
78+ RelyingPartyRegistrationRepository relyingPartyRegistrationRepository (Saml2RelyingPartyProperties properties ,
79+ ObjectProvider <SslBundles > sslBundles ) {
6880 List <RelyingPartyRegistration > registrations = properties .getRegistration ()
6981 .entrySet ()
7082 .stream ()
71- .map (this :: asRegistration )
83+ .map (( entry ) -> asRegistration ( entry , sslBundles . getIfAvailable ()) )
7284 .toList ();
7385 return new InMemoryRelyingPartyRegistrationRepository (registrations );
7486 }
7587
76- private RelyingPartyRegistration asRegistration (Map .Entry <String , Registration > entry ) {
77- return asRegistration (entry .getKey (), entry .getValue ());
88+ private RelyingPartyRegistration asRegistration (Map .Entry <String , Registration > entry , SslBundles sslBundles ) {
89+ return asRegistration (entry .getKey (), entry .getValue (), sslBundles );
7890 }
7991
80- private RelyingPartyRegistration asRegistration (String id , Registration properties ) {
92+ private RelyingPartyRegistration asRegistration (String id , Registration properties , SslBundles sslBundles ) {
8193 boolean usingMetadata = StringUtils .hasText (properties .getAssertingparty ().getMetadataUri ());
8294 Builder builder = (!usingMetadata ) ? RelyingPartyRegistration .withRegistrationId (id )
8395 : createBuilderUsingMetadata (properties .getAssertingparty ()).registrationId (id );
@@ -87,19 +99,19 @@ private RelyingPartyRegistration asRegistration(String id, Registration properti
8799 builder .signingX509Credentials ((credentials ) -> properties .getSigning ()
88100 .getCredentials ()
89101 .stream ()
90- .map (this :: asSigningCredential )
102+ .map (( signing ) -> asSigningCredential ( signing , sslBundles ) )
91103 .forEach (credentials ::add ));
92104 builder .decryptionX509Credentials ((credentials ) -> properties .getDecryption ()
93105 .getCredentials ()
94106 .stream ()
95- .map (this :: asDecryptionCredential )
107+ .map (( decryption ) -> asDecryptionCredential ( decryption , sslBundles ) )
96108 .forEach (credentials ::add ));
97109 builder .assertingPartyDetails (
98110 (details ) -> details .verificationX509Credentials ((credentials ) -> properties .getAssertingparty ()
99111 .getVerification ()
100112 .getCredentials ()
101113 .stream ()
102- .map (this :: asVerificationCredential )
114+ .map (( verification ) -> asVerificationCredential ( verification , sslBundles ) )
103115 .forEach (credentials ::add )));
104116 builder .singleLogoutServiceLocation (properties .getSinglelogout ().getUrl ());
105117 builder .singleLogoutServiceResponseLocation (properties .getSinglelogout ().getResponseUrl ());
@@ -150,19 +162,37 @@ private void validateSigningCredentials(Registration properties, boolean signReq
150162 }
151163 }
152164
153- private Saml2X509Credential asSigningCredential (Signing .Credential properties ) {
165+ private Saml2X509Credential asSigningCredential (Credential properties , SslBundles sslBundles ) {
166+ Bundle sslBundle = properties .getBundle ();
167+ if (sslBundle != null ) {
168+ PrivateKey privateKey = getPrivateKey (sslBundle .getName (), sslBundles );
169+ X509Certificate certificate = getCertificate (sslBundle , sslBundles );
170+ return new Saml2X509Credential (privateKey , certificate , Saml2X509CredentialType .SIGNING );
171+ }
154172 RSAPrivateKey privateKey = readPrivateKey (properties .getPrivateKeyLocation ());
155173 X509Certificate certificate = readCertificate (properties .getCertificateLocation ());
156174 return new Saml2X509Credential (privateKey , certificate , Saml2X509CredentialType .SIGNING );
157175 }
158176
159- private Saml2X509Credential asDecryptionCredential (Decryption .Credential properties ) {
177+ private Saml2X509Credential asDecryptionCredential (Decryption .Credential properties , SslBundles sslBundles ) {
178+ Bundle sslBundle = properties .getBundle ();
179+ if (sslBundle != null ) {
180+ PrivateKey privateKey = getPrivateKey (sslBundle .getName (), sslBundles );
181+ X509Certificate certificate = getCertificate (sslBundle , sslBundles );
182+ return new Saml2X509Credential (privateKey , certificate , Saml2X509CredentialType .DECRYPTION );
183+ }
160184 RSAPrivateKey privateKey = readPrivateKey (properties .getPrivateKeyLocation ());
161185 X509Certificate certificate = readCertificate (properties .getCertificateLocation ());
162186 return new Saml2X509Credential (privateKey , certificate , Saml2X509CredentialType .DECRYPTION );
163187 }
164188
165- private Saml2X509Credential asVerificationCredential (Verification .Credential properties ) {
189+ private Saml2X509Credential asVerificationCredential (Verification .Credential properties , SslBundles sslBundles ) {
190+ Bundle sslBundle = properties .getBundle ();
191+ if (sslBundle != null ) {
192+ X509Certificate certificate = getCertificate (sslBundle , sslBundles );
193+ return new Saml2X509Credential (certificate , Saml2X509Credential .Saml2X509CredentialType .ENCRYPTION ,
194+ Saml2X509Credential .Saml2X509CredentialType .VERIFICATION );
195+ }
166196 X509Certificate certificate = readCertificate (properties .getCertificateLocation ());
167197 return new Saml2X509Credential (certificate , Saml2X509Credential .Saml2X509CredentialType .ENCRYPTION ,
168198 Saml2X509Credential .Saml2X509CredentialType .VERIFICATION );
@@ -190,4 +220,35 @@ private X509Certificate readCertificate(Resource location) {
190220 }
191221 }
192222
223+ private PrivateKey getPrivateKey (String sslBundle , SslBundles sslBundles ) {
224+ try {
225+ SslBundle bundle = sslBundles .getBundle (sslBundle );
226+ SslBundleKey key = bundle .getKey ();
227+ KeyStore keyStore = bundle .getStores ().getKeyStore ();
228+ Key privateKey = keyStore .getKey (key .getAlias (), key .getPassword ().toCharArray ());
229+ Assert .notNull (privateKey ,
230+ "Private key with alias '" + key .getAlias () + "' was not found in SSL bundle '" + sslBundle + "'" );
231+ Assert .isInstanceOf (PrivateKey .class , privateKey );
232+ return (PrivateKey ) privateKey ;
233+ }
234+ catch (GeneralSecurityException ex ) {
235+ throw new IllegalStateException ("Error getting private key from SSL bundle '" + sslBundle + "'" , ex );
236+ }
237+ }
238+
239+ private X509Certificate getCertificate (Bundle sslBundle , SslBundles sslBundles ) {
240+ try {
241+ SslBundle bundle = sslBundles .getBundle (sslBundle .getName ());
242+ KeyStore keyStore = bundle .getStores ().getKeyStore ();
243+ Certificate certificate = keyStore .getCertificate (sslBundle .getAlias ());
244+ Assert .notNull (certificate , "Certificate with alias '" + sslBundle .getAlias ()
245+ + "' was not found in SSL bundle '" + sslBundle + "'" );
246+ Assert .isInstanceOf (X509Certificate .class , certificate );
247+ return (X509Certificate ) certificate ;
248+ }
249+ catch (GeneralSecurityException ex ) {
250+ throw new IllegalStateException ("Error getting certificate from SSL bundle '" + sslBundle + "'" , ex );
251+ }
252+ }
253+
193254}
0 commit comments