|
10 | 10 | import org.keycloak.dom.saml.v2.assertion.AttributeStatementType; |
11 | 11 | import org.keycloak.dom.saml.v2.assertion.AttributeType; |
12 | 12 | import org.keycloak.dom.saml.v2.assertion.AudienceRestrictionType; |
| 13 | +import org.keycloak.dom.saml.v2.assertion.NameIDType; |
13 | 14 | import org.keycloak.dom.saml.v2.assertion.StatementAbstractType; |
14 | 15 | import org.keycloak.dom.saml.v2.protocol.ResponseType; |
15 | 16 | import org.keycloak.protocol.saml.SamlPrincipalType; |
|
61 | 62 | import static org.hamcrest.Matchers.notNullValue; |
62 | 63 | import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_CONS_NAME; |
63 | 64 | import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME; |
| 65 | +import static org.junit.Assert.assertEquals; |
64 | 66 | import static org.junit.Assert.assertThat; |
| 67 | +import static org.junit.Assert.assertTrue; |
| 68 | + |
65 | 69 | import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude; |
66 | 70 | import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer; |
67 | 71 |
|
@@ -122,6 +126,7 @@ public void initRealmUrls() { |
122 | 126 | public void resetPrincipalType() { |
123 | 127 | IdentityProviderResource idp = adminClient.realm(REALM_CONS_NAME).identityProviders().get("saml-leaf"); |
124 | 128 | IdentityProviderRepresentation rep = idp.toRepresentation(); |
| 129 | + rep.getConfig().put(SAMLIdentityProviderConfig.NAME_ID_POLICY_FORMAT, JBossSAMLURIConstants.NAMEID_FORMAT_PERSISTENT.get()); |
125 | 130 | rep.getConfig().put(SAMLIdentityProviderConfig.PRINCIPAL_TYPE, SamlPrincipalType.SUBJECT.name()); |
126 | 131 | idp.update(rep); |
127 | 132 | } |
@@ -396,6 +401,109 @@ public void testProviderIdpInitiatedLoginWithPrincipalAttribute() throws Excepti |
396 | 401 | assertThat(fed.getUserId(), is(PROVIDER_REALM_USER_NAME)); |
397 | 402 | assertThat(fed.getUserName(), is(PROVIDER_REALM_USER_NAME)); |
398 | 403 | } |
| 404 | + |
| 405 | + @Test |
| 406 | + public void testProviderTransientIdpInitiatedLogin() throws Exception { |
| 407 | + IdentityProviderResource idp = adminClient.realm(REALM_CONS_NAME).identityProviders().get("saml-leaf"); |
| 408 | + IdentityProviderRepresentation rep = idp.toRepresentation(); |
| 409 | + rep.getConfig().put(SAMLIdentityProviderConfig.NAME_ID_POLICY_FORMAT, JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get()); |
| 410 | + rep.getConfig().put(SAMLIdentityProviderConfig.PRINCIPAL_TYPE, SamlPrincipalType.ATTRIBUTE.name()); |
| 411 | + rep.getConfig().put(SAMLIdentityProviderConfig.PRINCIPAL_ATTRIBUTE, X500SAMLProfileConstants.UID.get()); |
| 412 | + idp.update(rep); |
| 413 | + |
| 414 | + SAMLDocumentHolder samlResponse = new SamlClientBuilder() |
| 415 | + .navigateTo(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker")) |
| 416 | + // Login in provider realm |
| 417 | + .login().user(PROVIDER_REALM_USER_NAME, PROVIDER_REALM_USER_PASSWORD).build() |
| 418 | + |
| 419 | + // Send the response to the consumer realm |
| 420 | + .processSamlResponse(Binding.POST) |
| 421 | + .transformObject(ob -> { |
| 422 | + assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS)); |
| 423 | + ResponseType resp = (ResponseType) ob; |
| 424 | + assertThat(resp.getDestination(), is(getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales"))); |
| 425 | + assertAudience(resp, getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales")); |
| 426 | + |
| 427 | + NameIDType nameId = new NameIDType(); |
| 428 | + nameId.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get())); |
| 429 | + nameId.setValue("subjectId1" ); |
| 430 | + resp.getAssertions().get(0).getAssertion().getSubject().getSubType().addBaseID(nameId); |
| 431 | + |
| 432 | + Set<StatementAbstractType> statements = resp.getAssertions().get(0).getAssertion().getStatements(); |
| 433 | + |
| 434 | + AttributeStatementType attributeType = (AttributeStatementType) statements.stream() |
| 435 | + .filter(statement -> statement instanceof AttributeStatementType).findFirst() |
| 436 | + .orElse(new AttributeStatementType()); |
| 437 | + |
| 438 | + AttributeType attr = new AttributeType(X500SAMLProfileConstants.UID.get()); |
| 439 | + attr.addAttributeValue(PROVIDER_REALM_USER_NAME); |
| 440 | + |
| 441 | + attributeType.addAttribute(new AttributeStatementType.ASTChoiceType(attr)); |
| 442 | + resp.getAssertions().get(0).getAssertion().addStatement(attributeType); |
| 443 | + |
| 444 | + return ob; |
| 445 | + }) |
| 446 | + .build() |
| 447 | + |
| 448 | + // Now login to the second app |
| 449 | + .navigateTo(getSamlIdpInitiatedUrl(REALM_PROV_NAME, "samlbroker-2")) |
| 450 | + |
| 451 | + // Login in provider realm |
| 452 | + .login().sso(true).build() |
| 453 | + |
| 454 | + .processSamlResponse(Binding.POST) |
| 455 | + .transformObject(ob -> { |
| 456 | + assertThat(ob, Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS)); |
| 457 | + ResponseType resp = (ResponseType) ob; |
| 458 | + assertThat(resp.getDestination(), is(getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales2"))); |
| 459 | + assertAudience(resp, getSamlBrokerIdpInitiatedUrl(REALM_CONS_NAME, "sales2")); |
| 460 | + |
| 461 | + NameIDType nameId = new NameIDType(); |
| 462 | + nameId.setFormat(URI.create(JBossSAMLURIConstants.NAMEID_FORMAT_TRANSIENT.get())); |
| 463 | + nameId.setValue("subjectId2" ); |
| 464 | + resp.getAssertions().get(0).getAssertion().getSubject().getSubType().addBaseID(nameId); |
| 465 | + |
| 466 | + Set<StatementAbstractType> statements = resp.getAssertions().get(0).getAssertion().getStatements(); |
| 467 | + |
| 468 | + AttributeStatementType attributeType = (AttributeStatementType) statements.stream() |
| 469 | + .filter(statement -> statement instanceof AttributeStatementType).findFirst() |
| 470 | + .orElse(new AttributeStatementType()); |
| 471 | + |
| 472 | + AttributeType attr = new AttributeType(X500SAMLProfileConstants.UID.get()); |
| 473 | + attr.addAttributeValue(PROVIDER_REALM_USER_NAME); |
| 474 | + |
| 475 | + attributeType.addAttribute(new AttributeStatementType.ASTChoiceType(attr)); |
| 476 | + resp.getAssertions().get(0).getAssertion().addStatement(attributeType); |
| 477 | + |
| 478 | + return ob; |
| 479 | + }) |
| 480 | + .build() |
| 481 | + |
| 482 | + .updateProfile().username(CONSUMER_CHOSEN_USERNAME).email("test@localhost").firstName("Firstname").lastName("Lastname").build() |
| 483 | + .followOneRedirect() |
| 484 | + |
| 485 | + // Obtain the response sent to the app |
| 486 | + .getSamlResponse(Binding.POST); |
| 487 | + |
| 488 | + assertThat(samlResponse.getSamlObject(), Matchers.isSamlResponse(JBossSAMLURIConstants.STATUS_SUCCESS)); |
| 489 | + ResponseType resp = (ResponseType) samlResponse.getSamlObject(); |
| 490 | + assertThat(resp.getDestination(), is(urlRealmConsumer + "/app/auth2/saml")); |
| 491 | + assertAudience(resp, urlRealmConsumer + "/app/auth2"); |
| 492 | + |
| 493 | + UsersResource users = adminClient.realm(REALM_CONS_NAME).users(); |
| 494 | + List<UserRepresentation> userList= users.search(CONSUMER_CHOSEN_USERNAME); |
| 495 | + assertEquals(1, userList.size()); |
| 496 | + String id = userList.get(0).getId(); |
| 497 | + FederatedIdentityRepresentation fed = users.get(id).getFederatedIdentity().get(0); |
| 498 | + assertThat(fed.getUserId(), is(PROVIDER_REALM_USER_NAME)); |
| 499 | + assertThat(fed.getUserName(), is(PROVIDER_REALM_USER_NAME)); |
| 500 | + |
| 501 | + //check that no user with sent subject-id was sent |
| 502 | + userList = users.search("subjectId1"); |
| 503 | + assertTrue(userList.isEmpty()); |
| 504 | + userList = users.search("subjectId2"); |
| 505 | + assertTrue(userList.isEmpty()); |
| 506 | + } |
399 | 507 |
|
400 | 508 | private void assertSingleUserSession(String realmName, String userName, String... expectedClientIds) { |
401 | 509 | final UsersResource users = adminClient.realm(realmName).users(); |
|
0 commit comments