21
21
import java .security .cert .X509Certificate ;
22
22
import java .time .Clock ;
23
23
import java .time .Instant ;
24
- import java .util .Collection ;
24
+ import java .util .ArrayList ;
25
+ import java .util .Collections ;
25
26
import java .util .LinkedHashMap ;
27
+ import java .util .List ;
26
28
import java .util .Map ;
27
29
import java .util .UUID ;
28
30
31
+ import net .shibboleth .utilities .java .support .resolver .CriteriaSet ;
29
32
import net .shibboleth .utilities .java .support .xml .SerializeSupport ;
30
33
import org .joda .time .DateTime ;
31
34
import org .opensaml .core .config .ConfigurationService ;
37
40
import org .opensaml .saml .saml2 .core .impl .AuthnRequestBuilder ;
38
41
import org .opensaml .saml .saml2 .core .impl .AuthnRequestMarshaller ;
39
42
import org .opensaml .saml .saml2 .core .impl .IssuerBuilder ;
43
+ import org .opensaml .saml .security .impl .SAMLMetadataSignatureSigningParametersResolver ;
40
44
import org .opensaml .security .SecurityException ;
41
45
import org .opensaml .security .credential .BasicCredential ;
42
46
import org .opensaml .security .credential .Credential ;
43
47
import org .opensaml .security .credential .CredentialSupport ;
44
48
import org .opensaml .security .credential .UsageType ;
45
49
import org .opensaml .xmlsec .SignatureSigningParameters ;
50
+ import org .opensaml .xmlsec .SignatureSigningParametersResolver ;
51
+ import org .opensaml .xmlsec .criterion .SignatureSigningConfigurationCriterion ;
46
52
import org .opensaml .xmlsec .crypto .XMLSigningUtil ;
53
+ import org .opensaml .xmlsec .impl .BasicSignatureSigningConfiguration ;
47
54
import org .opensaml .xmlsec .signature .support .SignatureConstants ;
48
- import org .opensaml .xmlsec .signature .support .SignatureException ;
49
55
import org .opensaml .xmlsec .signature .support .SignatureSupport ;
50
56
import org .w3c .dom .Element ;
51
57
58
64
import org .springframework .security .saml2 .provider .service .registration .Saml2MessageBinding ;
59
65
import org .springframework .util .Assert ;
60
66
import org .springframework .util .StringUtils ;
67
+ import org .springframework .web .util .UriComponentsBuilder ;
61
68
import org .springframework .web .util .UriUtils ;
62
69
63
70
/**
@@ -105,9 +112,17 @@ public String createAuthenticationRequest(Saml2AuthenticationRequest request) {
105
112
request .getAssertionConsumerServiceUrl (), this .protocolBindingResolver .convert (null ));
106
113
for (org .springframework .security .saml2 .credentials .Saml2X509Credential credential : request .getCredentials ()) {
107
114
if (credential .isSigningCredential ()) {
108
- Credential cred = getSigningCredential (credential .getCertificate (), credential .getPrivateKey (),
109
- request .getIssuer ());
110
- return serialize (sign (authnRequest , cred ));
115
+ X509Certificate certificate = credential .getCertificate ();
116
+ PrivateKey privateKey = credential .getPrivateKey ();
117
+ BasicCredential cred = CredentialSupport .getSimpleCredential (certificate , privateKey );
118
+ cred .setEntityId (request .getIssuer ());
119
+ cred .setUsageType (UsageType .SIGNING );
120
+ SignatureSigningParameters parameters = new SignatureSigningParameters ();
121
+ parameters .setSigningCredential (cred );
122
+ parameters .setSignatureAlgorithm (SignatureConstants .ALGO_ID_SIGNATURE_RSA_SHA256 );
123
+ parameters .setSignatureReferenceDigestMethod (SignatureConstants .ALGO_ID_DIGEST_SHA256 );
124
+ parameters .setSignatureCanonicalizationAlgorithm (SignatureConstants .ALGO_ID_C14N_EXCL_OMIT_COMMENTS );
125
+ return serialize (sign (authnRequest , parameters ));
111
126
}
112
127
}
113
128
throw new IllegalArgumentException ("No signing credential provided" );
@@ -132,16 +147,13 @@ public Saml2RedirectAuthenticationRequest createRedirectAuthenticationRequest(
132
147
String deflatedAndEncoded = Saml2Utils .samlEncode (Saml2Utils .samlDeflate (xml ));
133
148
result .samlRequest (deflatedAndEncoded ).relayState (context .getRelayState ());
134
149
if (context .getRelyingPartyRegistration ().getAssertingPartyDetails ().getWantAuthnRequestsSigned ()) {
135
- Collection <Saml2X509Credential > signingCredentials = context .getRelyingPartyRegistration ()
136
- .getSigningX509Credentials ();
137
- for (Saml2X509Credential credential : signingCredentials ) {
138
- Credential cred = getSigningCredential (credential .getCertificate (), credential .getPrivateKey (), "" );
139
- Map <String , String > signedParams = signQueryParameters (cred , deflatedAndEncoded ,
140
- context .getRelayState ());
141
- return result .samlRequest (signedParams .get ("SAMLRequest" )).relayState (signedParams .get ("RelayState" ))
142
- .sigAlg (signedParams .get ("SigAlg" )).signature (signedParams .get ("Signature" )).build ();
150
+ Map <String , String > parameters = new LinkedHashMap <>();
151
+ parameters .put ("SAMLRequest" , deflatedAndEncoded );
152
+ if (StringUtils .hasText (context .getRelayState ())) {
153
+ parameters .put ("RelayState" , context .getRelayState ());
143
154
}
144
- throw new Saml2Exception ("No signing credential provided" );
155
+ sign (parameters , context .getRelyingPartyRegistration ());
156
+ return result .sigAlg (parameters .get ("SigAlg" )).signature (parameters .get ("Signature" )).build ();
145
157
}
146
158
return result .build ();
147
159
}
@@ -211,59 +223,39 @@ public void setProtocolBinding(String protocolBinding) {
211
223
}
212
224
213
225
private AuthnRequest sign (AuthnRequest authnRequest , RelyingPartyRegistration relyingPartyRegistration ) {
214
- for (Saml2X509Credential credential : relyingPartyRegistration .getSigningX509Credentials ()) {
215
- Credential cred = getSigningCredential (credential .getCertificate (), credential .getPrivateKey (),
216
- relyingPartyRegistration .getEntityId ());
217
- return sign (authnRequest , cred );
218
- }
219
- throw new IllegalArgumentException ("No signing credential provided" );
226
+ SignatureSigningParameters parameters = resolveSigningParameters (relyingPartyRegistration );
227
+ return sign (authnRequest , parameters );
220
228
}
221
229
222
- private AuthnRequest sign (AuthnRequest authnRequest , Credential credential ) {
223
- SignatureSigningParameters parameters = new SignatureSigningParameters ();
224
- parameters .setSigningCredential (credential );
225
- parameters .setSignatureAlgorithm (SignatureConstants .ALGO_ID_SIGNATURE_RSA_SHA256 );
226
- parameters .setSignatureReferenceDigestMethod (SignatureConstants .ALGO_ID_DIGEST_SHA256 );
227
- parameters .setSignatureCanonicalizationAlgorithm (SignatureConstants .ALGO_ID_C14N_EXCL_OMIT_COMMENTS );
230
+ private AuthnRequest sign (AuthnRequest authnRequest , SignatureSigningParameters parameters ) {
228
231
try {
229
232
SignatureSupport .signObject (authnRequest , parameters );
230
233
return authnRequest ;
231
234
}
232
- catch (MarshallingException | SignatureException | SecurityException ex ) {
235
+ catch (Exception ex ) {
233
236
throw new Saml2Exception (ex );
234
237
}
235
238
}
236
239
237
- private Credential getSigningCredential (X509Certificate certificate , PrivateKey privateKey , String entityId ) {
238
- BasicCredential cred = CredentialSupport .getSimpleCredential (certificate , privateKey );
239
- cred .setEntityId (entityId );
240
- cred .setUsageType (UsageType .SIGNING );
241
- return cred ;
240
+ private void sign (Map <String , String > components , RelyingPartyRegistration relyingPartyRegistration ) {
241
+ SignatureSigningParameters parameters = resolveSigningParameters (relyingPartyRegistration );
242
+ sign (components , parameters );
242
243
}
243
244
244
- private Map <String , String > signQueryParameters (Credential credential , String samlRequest , String relayState ) {
245
- Assert .notNull (samlRequest , "samlRequest cannot be null" );
246
- String algorithmUri = SignatureConstants .ALGO_ID_SIGNATURE_RSA_SHA256 ;
247
- StringBuilder queryString = new StringBuilder ();
248
- queryString .append ("SAMLRequest" ).append ("=" ).append (UriUtils .encode (samlRequest , StandardCharsets .ISO_8859_1 ))
249
- .append ("&" );
250
- if (StringUtils .hasText (relayState )) {
251
- queryString .append ("RelayState" ).append ("=" )
252
- .append (UriUtils .encode (relayState , StandardCharsets .ISO_8859_1 )).append ("&" );
245
+ private void sign (Map <String , String > components , SignatureSigningParameters parameters ) {
246
+ Credential credential = parameters .getSigningCredential ();
247
+ String algorithmUri = parameters .getSignatureAlgorithm ();
248
+ components .put ("SigAlg" , algorithmUri );
249
+ UriComponentsBuilder builder = UriComponentsBuilder .newInstance ();
250
+ for (Map .Entry <String , String > component : components .entrySet ()) {
251
+ builder .queryParam (component .getKey (), UriUtils .encode (component .getValue (), StandardCharsets .ISO_8859_1 ));
253
252
}
254
- queryString . append ( "SigAlg" ). append ( "=" ). append ( UriUtils . encode ( algorithmUri , StandardCharsets . ISO_8859_1 ) );
253
+ String queryString = builder . build ( true ). toString (). substring ( 1 );
255
254
try {
256
255
byte [] rawSignature = XMLSigningUtil .signWithURI (credential , algorithmUri ,
257
- queryString .toString (). getBytes (StandardCharsets .UTF_8 ));
256
+ queryString .getBytes (StandardCharsets .UTF_8 ));
258
257
String b64Signature = Saml2Utils .samlEncode (rawSignature );
259
- Map <String , String > result = new LinkedHashMap <>();
260
- result .put ("SAMLRequest" , samlRequest );
261
- if (StringUtils .hasText (relayState )) {
262
- result .put ("RelayState" , relayState );
263
- }
264
- result .put ("SigAlg" , algorithmUri );
265
- result .put ("Signature" , b64Signature );
266
- return result ;
258
+ components .put ("Signature" , b64Signature );
267
259
}
268
260
catch (SecurityException ex ) {
269
261
throw new Saml2Exception (ex );
@@ -280,4 +272,40 @@ private String serialize(AuthnRequest authnRequest) {
280
272
}
281
273
}
282
274
275
+ private SignatureSigningParameters resolveSigningParameters (RelyingPartyRegistration relyingPartyRegistration ) {
276
+ List <Credential > credentials = resolveSigningCredentials (relyingPartyRegistration );
277
+ List <String > algorithms = Collections .singletonList (SignatureConstants .ALGO_ID_SIGNATURE_RSA_SHA256 );
278
+ List <String > digests = Collections .singletonList (SignatureConstants .ALGO_ID_DIGEST_SHA256 );
279
+ String canonicalization = SignatureConstants .ALGO_ID_C14N_EXCL_OMIT_COMMENTS ;
280
+ SignatureSigningParametersResolver resolver = new SAMLMetadataSignatureSigningParametersResolver ();
281
+ CriteriaSet criteria = new CriteriaSet ();
282
+ BasicSignatureSigningConfiguration signingConfiguration = new BasicSignatureSigningConfiguration ();
283
+ signingConfiguration .setSigningCredentials (credentials );
284
+ signingConfiguration .setSignatureAlgorithms (algorithms );
285
+ signingConfiguration .setSignatureReferenceDigestMethods (digests );
286
+ signingConfiguration .setSignatureCanonicalizationAlgorithm (canonicalization );
287
+ criteria .add (new SignatureSigningConfigurationCriterion (signingConfiguration ));
288
+ try {
289
+ SignatureSigningParameters parameters = resolver .resolveSingle (criteria );
290
+ Assert .notNull (parameters , "Failed to resolve any signing credential" );
291
+ return parameters ;
292
+ }
293
+ catch (Exception ex ) {
294
+ throw new Saml2Exception (ex );
295
+ }
296
+ }
297
+
298
+ private List <Credential > resolveSigningCredentials (RelyingPartyRegistration relyingPartyRegistration ) {
299
+ List <Credential > credentials = new ArrayList <>();
300
+ for (Saml2X509Credential x509Credential : relyingPartyRegistration .getSigningX509Credentials ()) {
301
+ X509Certificate certificate = x509Credential .getCertificate ();
302
+ PrivateKey privateKey = x509Credential .getPrivateKey ();
303
+ BasicCredential credential = CredentialSupport .getSimpleCredential (certificate , privateKey );
304
+ credential .setEntityId (relyingPartyRegistration .getEntityId ());
305
+ credential .setUsageType (UsageType .SIGNING );
306
+ credentials .add (credential );
307
+ }
308
+ return credentials ;
309
+ }
310
+
283
311
}
0 commit comments