39
39
import org .opensaml .saml .saml2 .core .SubjectConfirmation ;
40
40
import org .opensaml .saml .saml2 .core .SubjectConfirmationData ;
41
41
import org .opensaml .saml .saml2 .core .impl .AuthnStatementBuilder ;
42
+ import org .opensaml .saml .saml2 .core .impl .IssuerBuilder ;
42
43
import org .opensaml .saml .saml2 .encryption .Encrypter ;
43
44
import org .opensaml .security .credential .BasicCredential ;
44
45
import org .opensaml .security .credential .Credential ;
83
84
import static org .hamcrest .Matchers .contains ;
84
85
import static org .hamcrest .Matchers .containsInAnyOrder ;
85
86
import static org .hamcrest .Matchers .containsString ;
87
+ import static org .hamcrest .Matchers .endsWith ;
86
88
import static org .hamcrest .Matchers .equalTo ;
89
+ import static org .hamcrest .Matchers .hasLength ;
87
90
import static org .hamcrest .Matchers .instanceOf ;
88
91
import static org .hamcrest .Matchers .is ;
89
92
import static org .hamcrest .Matchers .iterableWithSize ;
@@ -106,6 +109,9 @@ public class SamlAuthenticatorTests extends SamlResponseHandlerTests {
106
109
+ "Attributes with a name clash may prevent authentication or interfere will role mapping. "
107
110
+ "Change your IdP configuration to use a different attribute *"
108
111
+ " that will not clash with any of [*]" ;
112
+ private static final String SIGNATURE_VALIDATION_FAILED_LOG_MESSAGE = "The XML Signature of this SAML message cannot be validated. "
113
+ + "Please verify that the saml realm uses the correct SAML metadata file/URL for this Identity Provider. "
114
+ + "The issuer included in the SAML message was [https://idp.saml.elastic.test/]" ;
109
115
110
116
private SamlAuthenticator authenticator ;
111
117
@@ -741,16 +747,29 @@ public void testIncorrectSigningKeyIsRejected() throws Exception {
741
747
// check that the content is valid when signed by the correct key-pair
742
748
assertThat (authenticator .authenticate (token (signer .transform (xml , idpSigningCertificatePair ))), notNullValue ());
743
749
744
- // check is rejected when signed by a different key-pair
745
- final Tuple <X509Certificate , PrivateKey > wrongKey = readKeyPair ("RSA_4096_updated" );
746
- final ElasticsearchSecurityException exception = expectThrows (
747
- ElasticsearchSecurityException .class ,
748
- () -> authenticator .authenticate (token (signer .transform (xml , wrongKey )))
749
- );
750
- assertThat (exception .getMessage (), containsString ("SAML Signature" ));
751
- assertThat (exception .getMessage (), containsString ("could not be validated" ));
752
- assertThat (exception .getCause (), nullValue ());
753
- assertThat (SamlUtils .isSamlException (exception ), is (true ));
750
+ try (var mockLog = MockLog .capture (authenticator .getClass ())) {
751
+ mockLog .addExpectation (
752
+ new MockLog .SeenEventExpectation (
753
+ "Invalid Signature" ,
754
+ authenticator .getClass ().getName (),
755
+ Level .WARN ,
756
+ SIGNATURE_VALIDATION_FAILED_LOG_MESSAGE
757
+ )
758
+ );
759
+
760
+ // check is rejected when signed by a different key-pair
761
+ final Tuple <X509Certificate , PrivateKey > wrongKey = readKeyPair ("RSA_4096_updated" );
762
+ final ElasticsearchSecurityException exception = expectThrows (
763
+ ElasticsearchSecurityException .class ,
764
+ () -> authenticator .authenticate (token (signer .transform (xml , wrongKey )))
765
+ );
766
+ assertThat (exception .getMessage (), containsString ("SAML Signature" ));
767
+ assertThat (exception .getMessage (), containsString ("could not be validated" ));
768
+ assertThat (exception .getCause (), nullValue ());
769
+ assertThat (SamlUtils .isSamlException (exception ), is (true ));
770
+
771
+ mockLog .assertAllExpectationsMatched ();
772
+ }
754
773
}
755
774
756
775
public void testSigningKeyIsReloadedForEachRequest () throws Exception {
@@ -1301,24 +1320,80 @@ public void testFailureWhenIdPCredentialsAreEmpty() throws Exception {
1301
1320
authenticator = buildAuthenticator (() -> emptyList (), emptyList ());
1302
1321
final String xml = getSimpleResponseAsString (clock .instant ());
1303
1322
final SamlToken token = token (signResponse (xml ));
1304
- final ElasticsearchSecurityException exception = expectSamlException (() -> authenticator .authenticate (token ));
1305
- assertThat (exception .getCause (), nullValue ());
1306
- assertThat (exception .getMessage (), containsString ("SAML Signature" ));
1307
- assertThat (exception .getMessage (), containsString ("could not be validated" ));
1308
- // Restore the authenticator with credentials for the rest of the test cases
1309
- authenticator = buildAuthenticator (() -> buildOpenSamlCredential (idpSigningCertificatePair ), emptyList ());
1323
+
1324
+ try (var mockLog = MockLog .capture (authenticator .getClass ())) {
1325
+ mockLog .addExpectation (
1326
+ new MockLog .SeenEventExpectation (
1327
+ "Invalid signature" ,
1328
+ authenticator .getClass ().getName (),
1329
+ Level .WARN ,
1330
+ SIGNATURE_VALIDATION_FAILED_LOG_MESSAGE
1331
+ )
1332
+ );
1333
+
1334
+ final ElasticsearchSecurityException exception = expectSamlException (() -> authenticator .authenticate (token ));
1335
+ assertThat (exception .getCause (), nullValue ());
1336
+ assertThat (exception .getMessage (), containsString ("SAML Signature" ));
1337
+ assertThat (exception .getMessage (), containsString ("could not be validated" ));
1338
+
1339
+ mockLog .awaitAllExpectationsMatched ();
1340
+ }
1310
1341
}
1311
1342
1312
1343
public void testFailureWhenIdPCredentialsAreNull () throws Exception {
1313
1344
authenticator = buildAuthenticator (() -> singletonList (null ), emptyList ());
1314
1345
final String xml = getSimpleResponseAsString (clock .instant ());
1315
1346
final SamlToken token = token (signResponse (xml ));
1316
- final ElasticsearchSecurityException exception = expectSamlException (() -> authenticator .authenticate (token ));
1317
- assertThat (exception .getCause (), nullValue ());
1318
- assertThat (exception .getMessage (), containsString ("SAML Signature" ));
1319
- assertThat (exception .getMessage (), containsString ("could not be validated" ));
1320
- // Restore the authenticator with credentials for the rest of the test cases
1321
- authenticator = buildAuthenticator (() -> buildOpenSamlCredential (idpSigningCertificatePair ), emptyList ());
1347
+
1348
+ try (var mockLog = MockLog .capture (authenticator .getClass ())) {
1349
+ mockLog .addExpectation (
1350
+ new MockLog .SeenEventExpectation (
1351
+ "Invalid signature" ,
1352
+ authenticator .getClass ().getName (),
1353
+ Level .WARN ,
1354
+ SIGNATURE_VALIDATION_FAILED_LOG_MESSAGE
1355
+ )
1356
+ );
1357
+ mockLog .addExpectation (
1358
+ new MockLog .SeenEventExpectation (
1359
+ "Null credentials" ,
1360
+ authenticator .getClass ().getName (),
1361
+ Level .WARN ,
1362
+ "Exception while attempting to validate SAML Signature. "
1363
+ + "The issuer included in the SAML message was [https://idp.saml.elastic.test/]"
1364
+ )
1365
+ );
1366
+
1367
+ final ElasticsearchSecurityException exception = expectSamlException (() -> authenticator .authenticate (token ));
1368
+ assertThat (exception .getCause (), nullValue ());
1369
+ assertThat (exception .getMessage (), containsString ("SAML Signature" ));
1370
+ assertThat (exception .getMessage (), containsString ("could not be validated" ));
1371
+
1372
+ mockLog .awaitAllExpectationsMatched ();
1373
+ }
1374
+ }
1375
+
1376
+ public void testDescribeNullIssuer () {
1377
+ final Issuer issuer = randomFrom (new IssuerBuilder ().buildObject (), null );
1378
+ assertThat (SamlAuthenticator .describeIssuer (issuer ), equalTo ("" ));
1379
+ }
1380
+
1381
+ public void testDescribeIssuer () {
1382
+ final Issuer issuer = new IssuerBuilder ().buildObject ();
1383
+ issuer .setValue ("https://idp.saml.elastic.test/" );
1384
+ assertThat (
1385
+ SamlAuthenticator .describeIssuer (issuer ),
1386
+ equalTo (" The issuer included in the SAML message was [https://idp.saml.elastic.test/]" )
1387
+ );
1388
+ }
1389
+
1390
+ public void testDescribeVeryLongIssuer () {
1391
+ final Issuer issuer = new IssuerBuilder ().buildObject ();
1392
+ issuer .setValue ("https://idp.saml.elastic.test/" + randomAlphaOfLength (512 ));
1393
+
1394
+ final String description = SamlAuthenticator .describeIssuer (issuer );
1395
+ assertThat (description , hasLength (562 ));
1396
+ assertThat (description , endsWith ("..." ));
1322
1397
}
1323
1398
1324
1399
private interface CryptoTransform {
0 commit comments