diff --git a/tests/base/src/test/java/org/keycloak/tests/organization/admin/AbstractOrganizationTest.java b/tests/base/src/test/java/org/keycloak/tests/organization/admin/AbstractOrganizationTest.java index d614bb3972cc..4a025112ae62 100644 --- a/tests/base/src/test/java/org/keycloak/tests/organization/admin/AbstractOrganizationTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/organization/admin/AbstractOrganizationTest.java @@ -17,8 +17,10 @@ package org.keycloak.tests.organization.admin; +import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Objects; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.core.Response; @@ -41,17 +43,24 @@ import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.oauth.OAuthClient; import org.keycloak.testframework.realm.ClientBuilder; import org.keycloak.testframework.realm.CredentialBuilder; import org.keycloak.testframework.realm.IdentityProviderBuilder; import org.keycloak.testframework.realm.ManagedRealm; import org.keycloak.testframework.realm.RealmBuilder; import org.keycloak.testframework.realm.RealmConfig; +import org.keycloak.testframework.realm.UserBuilder; +import org.keycloak.testframework.realm.UserConfig; +import org.keycloak.testframework.ui.page.LoginPage; +import org.keycloak.testframework.ui.page.LoginUpdateProfilePage; +import org.keycloak.testframework.ui.page.LoginUsernamePage; import org.keycloak.testframework.util.ApiUtil; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; /** * Base class for organization tests in the new test framework. @@ -235,6 +244,88 @@ protected void setMapperConfig(String key, String value) { orgScopeResource.getProtocolMappers().update(orgMapper.getId(), orgMapper); } + /** + * Builds an IdP representation pointing to a real provider realm's OIDC endpoints. + */ + public static IdentityProviderRepresentation createRealOrgBroker(String alias, ManagedRealm providerRealm) { + IdentityProviderRepresentation idp = new IdentityProviderRepresentation(); + idp.setAlias(alias); + idp.setProviderId("keycloak-oidc"); + idp.setEnabled(true); + idp.setTrustEmail(true); + String providerBaseUrl = providerRealm.getBaseUrl(); + idp.setConfig(new HashMap<>(Map.of( + "clientId", CLIENT_ID, + "clientSecret", CLIENT_SECRET, + "authorizationUrl", providerBaseUrl + "/protocol/openid-connect/auth", + "tokenUrl", providerBaseUrl + "/protocol/openid-connect/token", + "userInfoUrl", providerBaseUrl + "/protocol/openid-connect/userinfo", + "defaultScope", "email profile", + "syncMode", "IMPORT" + ))); + return idp; + } + + /** + * Performs identity-first login through a broker: enters email on the consumer realm login page, + * follows the redirect to the provider realm, fills credentials, and optionally handles first-time + * login profile update. Registers cleanup for the federated user created in the consumer realm. + */ + protected void loginViaBroker(String email, String username, String password, + OAuthClient oauth, LoginUsernamePage loginUsernamePage, LoginPage loginPage, + ManagedRealm providerRealm) { + loginViaBroker(email, username, password, null, oauth, loginUsernamePage, loginPage, null, providerRealm); + } + + protected void loginViaBroker(String email, String username, String password, + String updateEmail, OAuthClient oauth, LoginUsernamePage loginUsernamePage, + LoginPage loginPage, LoginUpdateProfilePage loginUpdateProfilePage, + ManagedRealm providerRealm) { + oauth.openLoginForm(); + loginUsernamePage.fillLoginWithUsernameOnly(email); + loginUsernamePage.submit(); + + assertTrue(Objects.requireNonNull(oauth.getDriver().getCurrentUrl()).contains("/realms/" + providerRealm.getName() + "/"), + "Should be on provider realm login page"); + + loginPage.fillLogin(username, password); + loginPage.submit(); + + if (updateEmail != null) { + loginUpdateProfilePage.update("Firstname", "Lastname", updateEmail); + } + + List users = realm.admin().users().search(username); + assertEquals(1, users.size(), "Federated user should be created in consumer realm"); + + String userId = users.get(0).getId(); + realm.cleanup().add(r -> { + try { + r.users().get(userId).remove(); + } catch (NotFoundException ignored) {} + }); + } + + /** + * Performs broker registration and verifies the user becomes an organization member. + * Equivalent to the old AbstractOrganizationTest.assertBrokerRegistration(). + */ + protected void assertBrokerRegistration(OrganizationResource organization, + String username, String email, + OAuthClient oauth, LoginUsernamePage loginUsernamePage, LoginPage loginPage, + LoginUpdateProfilePage loginUpdateProfilePage, ManagedRealm providerRealm) { + loginViaBroker(email, username, "password", email, + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); + + assertIsMember(email, organization); + } + + protected void assertIsMember(String userEmail, OrganizationResource organization) { + UserRepresentation account = getUserRepresentation(userEmail); + UserRepresentation member = organization.members().member(account.getId()).toRepresentation(); + assertEquals(account.getId(), member.getId()); + } + /** * Creates an OIDC identity provider representation for the given organization name. */ @@ -304,4 +395,15 @@ public RealmBuilder configure(RealmBuilder realm) { ); } } + + public static class AliceUserConf implements UserConfig { + @Override + public UserBuilder configure(UserBuilder builder) { + return builder.username("alice") + .password("password") + .email("alice@neworg.org") + .emailVerified(true) + .name("Alice", "Org"); + } + } } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationGroupMembershipOIDCMapperTest.java b/tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationGroupMembershipOIDCMapperTest.java similarity index 89% rename from testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationGroupMembershipOIDCMapperTest.java rename to tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationGroupMembershipOIDCMapperTest.java index b8b38ca5d721..6fbf9a7fcc1d 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationGroupMembershipOIDCMapperTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationGroupMembershipOIDCMapperTest.java @@ -15,7 +15,7 @@ * limitations under the License. */ -package org.keycloak.testsuite.organization.mapper; +package org.keycloak.tests.organization.mapper; import java.util.HashMap; import java.util.List; @@ -41,12 +41,15 @@ import org.keycloak.representations.idm.OrganizationRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; import org.keycloak.representations.idm.RoleRepresentation; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.oauth.OAuthClient; +import org.keycloak.testframework.oauth.annotations.InjectOAuthClient; +import org.keycloak.testframework.util.ApiUtil; +import org.keycloak.tests.organization.admin.AbstractOrganizationTest; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; -import org.junit.Before; -import org.junit.Test; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.containsInAnyOrder; @@ -61,9 +64,13 @@ import static org.hamcrest.Matchers.notNullValue; import static org.hamcrest.Matchers.startsWith; +@KeycloakIntegrationTest public class OrganizationGroupMembershipOIDCMapperTest extends AbstractOrganizationTest { - @Before + @InjectOAuthClient + OAuthClient oauth; + + @BeforeEach public void addGroupMapper() { // Reset to defaults setMapperConfig(ProtocolMapperUtils.MULTIVALUED, null); @@ -73,7 +80,7 @@ public void addGroupMapper() { setMapperConfig(OrganizationMembershipMapper.ADD_ORGANIZATION_ID, null); // Add the organization group membership mapper to the organization scope - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); @@ -87,7 +94,7 @@ public void addGroupMapper() { return; } - ClientScopeResource orgScopeResource = managedRealm.admin().clientScopes().get(orgScope.getId()); + ClientScopeResource orgScopeResource = realm.admin().clientScopes().get(orgScope.getId()); ProtocolMapperRepresentation groupMapper = new ProtocolMapperRepresentation(); groupMapper.setName("organization-groups"); @@ -105,11 +112,11 @@ public void addGroupMapper() { } private void setGroupMapperConfig(String key, String value) { - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - ClientScopeResource orgScopeResource = managedRealm.admin().clientScopes().get(orgScope.getId()); + ClientScopeResource orgScopeResource = realm.admin().clientScopes().get(orgScope.getId()); ProtocolMapperRepresentation groupMapper = orgScopeResource.getProtocolMappers().getMappers().stream() .filter(m -> "organization-groups".equals(m.getName())) @@ -131,7 +138,7 @@ private void setGroupMapperConfig(String key, String value) { public void testNestedGroupsWithRelativePaths() throws Exception { // Create organization OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); // Add member MemberRepresentation member = addMember(org); @@ -184,7 +191,7 @@ public void testNestedGroupsWithRelativePaths() throws Exception { public void testEmptyGroupsWhenUserHasNoGroups() throws Exception { // Create organization OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); // Add member (but don't add to any groups) addMember(org); @@ -211,8 +218,8 @@ public void testCompositionWithAttributesAndId() throws Exception { OrganizationRepresentation orgA = createOrganization("org-a"); OrganizationRepresentation orgB = createOrganization("org-b"); - OrganizationResource orgAResource = managedRealm.admin().organizations().get(orgA.getId()); - OrganizationResource orgBResource = managedRealm.admin().organizations().get(orgB.getId()); + OrganizationResource orgAResource = realm.admin().organizations().get(orgA.getId()); + OrganizationResource orgBResource = realm.admin().organizations().get(orgB.getId()); // Add member to both orgs MemberRepresentation member = addMember(orgAResource); @@ -275,9 +282,9 @@ public void testCompositionWithStringTypeOrgMapper() throws Exception { OrganizationRepresentation orgB = createOrganization("org-b"); OrganizationRepresentation orgC = createOrganization("org-c"); - OrganizationResource orgAResource = managedRealm.admin().organizations().get(orgA.getId()); - OrganizationResource orgBResource = managedRealm.admin().organizations().get(orgB.getId()); - OrganizationResource orgCResource = managedRealm.admin().organizations().get(orgC.getId()); + OrganizationResource orgAResource = realm.admin().organizations().get(orgA.getId()); + OrganizationResource orgBResource = realm.admin().organizations().get(orgB.getId()); + OrganizationResource orgCResource = realm.admin().organizations().get(orgC.getId()); // Add member to all THREE orgs MemberRepresentation member = addMember(orgAResource); @@ -332,7 +339,7 @@ public void testCompositionWithStringTypeOrgMapper() throws Exception { @SuppressWarnings("unchecked") public void testCustomClaimName() throws Exception { OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); MemberRepresentation member = addMember(org); GroupRepresentation engineering = new GroupRepresentation(); @@ -366,7 +373,7 @@ public void testCustomClaimName() throws Exception { @SuppressWarnings("unchecked") public void testDottedClaimName() throws Exception { OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); MemberRepresentation member = addMember(org); GroupRepresentation engineering = new GroupRepresentation(); @@ -404,7 +411,7 @@ public void testDottedClaimName() throws Exception { @SuppressWarnings("unchecked") public void testNoNpeWhenOrganizationScopeNotRequested() throws Exception { OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); addMember(org); // Authenticate WITHOUT organization scope - should not throw NPE @@ -428,7 +435,7 @@ public void testGroupRoleMappingsInToken() throws Exception { // Create organization OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); // Add member MemberRepresentation member = addMember(org); @@ -443,8 +450,8 @@ public void testGroupRoleMappingsInToken() throws Exception { // Create a realm role and assign to the group RoleRepresentation realmRole = new RoleRepresentation("org-token-test-role", "", false); - managedRealm.admin().roles().create(realmRole); - RoleRepresentation createdRealmRole = managedRealm.admin().roles().get("org-token-test-role").toRepresentation(); + realm.admin().roles().create(realmRole); + RoleRepresentation createdRealmRole = realm.admin().roles().get("org-token-test-role").toRepresentation(); org.groups().group(engineeringId).roles().realmLevel().add(List.of(createdRealmRole)); // Create a client with a role and assign to the group @@ -452,12 +459,12 @@ public void testGroupRoleMappingsInToken() throws Exception { clientRep.setClientId("org-token-test-client"); clientRep.setEnabled(true); String clientUuid; - try (Response response = managedRealm.admin().clients().create(clientRep)) { + try (Response response = realm.admin().clients().create(clientRep)) { clientUuid = ApiUtil.getCreatedId(response); } RoleRepresentation clientRole = new RoleRepresentation("org-token-client-role", "", false); - managedRealm.admin().clients().get(clientUuid).roles().create(clientRole); - RoleRepresentation createdClientRole = managedRealm.admin().clients().get(clientUuid).roles().get("org-token-client-role").toRepresentation(); + realm.admin().clients().get(clientUuid).roles().create(clientRole); + RoleRepresentation createdClientRole = realm.admin().clients().get(clientUuid).roles().get("org-token-client-role").toRepresentation(); org.groups().group(engineeringId).roles().clientLevel(clientUuid).add(List.of(createdClientRole)); // Add member to group @@ -499,7 +506,7 @@ public void testGroupRoleMappingsNotIncludedByDefault() throws Exception { // Don't enable addGroupRoleMappings — default is off OrganizationRepresentation orgRep = createOrganization("acme"); - OrganizationResource org = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource org = realm.admin().organizations().get(orgRep.getId()); MemberRepresentation member = addMember(org); GroupRepresentation engineering = new GroupRepresentation(); @@ -511,8 +518,8 @@ public void testGroupRoleMappingsNotIncludedByDefault() throws Exception { // Create and assign a realm role RoleRepresentation realmRole = new RoleRepresentation("default-off-role", "", false); - managedRealm.admin().roles().create(realmRole); - RoleRepresentation createdRole = managedRealm.admin().roles().get("default-off-role").toRepresentation(); + realm.admin().roles().create(realmRole); + RoleRepresentation createdRole = realm.admin().roles().get("default-off-role").toRepresentation(); org.groups().group(engineeringId).roles().realmLevel().add(List.of(createdRole)); org.groups().group(engineeringId).addMember(member.getId()); @@ -534,11 +541,11 @@ public void testGroupRoleMappingsNotIncludedByDefault() throws Exception { } private void enableGroupRoleMappings() { - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - ClientScopeResource orgScopeResource = managedRealm.admin().clientScopes().get(orgScope.getId()); + ClientScopeResource orgScopeResource = realm.admin().clientScopes().get(orgScope.getId()); ProtocolMapperRepresentation groupMapper = orgScopeResource.getProtocolMappers().getMappers().stream() .filter(m -> OrganizationGroupMembershipMapper.PROVIDER_ID.equals(m.getProtocolMapper())) diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationGroupOidcIdpMapperTest.java b/tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationGroupOidcIdpMapperTest.java similarity index 62% rename from testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationGroupOidcIdpMapperTest.java rename to tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationGroupOidcIdpMapperTest.java index 76c8ac0a74df..c1cfb3988b17 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationGroupOidcIdpMapperTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationGroupOidcIdpMapperTest.java @@ -15,9 +15,10 @@ * limitations under the License. */ -package org.keycloak.testsuite.organization.mapper; +package org.keycloak.tests.organization.mapper; import java.util.List; +import java.util.Map; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.Response.Status; @@ -35,11 +36,24 @@ import org.keycloak.representations.idm.MemberRepresentation; import org.keycloak.representations.idm.OrganizationRepresentation; import org.keycloak.representations.idm.UserRepresentation; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest; - -import com.google.common.collect.ImmutableMap; -import org.junit.Test; +import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.annotations.InjectUser; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.injection.LifeCycle; +import org.keycloak.testframework.oauth.OAuthClient; +import org.keycloak.testframework.oauth.annotations.InjectOAuthClient; +import org.keycloak.testframework.realm.ManagedRealm; +import org.keycloak.testframework.realm.ManagedUser; +import org.keycloak.testframework.ui.annotations.InjectPage; +import org.keycloak.testframework.ui.annotations.InjectWebDriver; +import org.keycloak.testframework.ui.page.LoginPage; +import org.keycloak.testframework.ui.page.LoginUpdateProfilePage; +import org.keycloak.testframework.ui.page.LoginUsernamePage; +import org.keycloak.testframework.ui.webdriver.ManagedWebDriver; +import org.keycloak.testframework.util.ApiUtil; +import org.keycloak.tests.organization.admin.AbstractOrganizationTest; + +import org.junit.jupiter.api.Test; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.hasSize; @@ -48,14 +62,36 @@ import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.fail; - +@KeycloakIntegrationTest public class OrganizationGroupOidcIdpMapperTest extends AbstractOrganizationTest { + @InjectRealm(ref = "provider", config = ProviderRealmConf.class, lifecycle = LifeCycle.METHOD) + ManagedRealm providerRealm; + + @InjectUser(ref = "alice", realmRef = "provider", config = AliceUserConf.class) + ManagedUser aliceFromProviderRealm; + + @InjectWebDriver + ManagedWebDriver driver; + + @InjectOAuthClient + OAuthClient oauth; + + @InjectPage + LoginPage loginPage; + + @InjectPage + LoginUsernamePage loginUsernamePage; + + @InjectPage + LoginUpdateProfilePage loginUpdateProfilePage; + @Test public void testAdvancedClaimToGroupMapperWithOrganizationGroup() { // Create organization with IdP OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); + String idpAlias = organizationName + "-identity-provider"; // Create organization group GroupRepresentation orgGroup = new GroupRepresentation(); @@ -70,27 +106,26 @@ public void testAdvancedClaimToGroupMapperWithOrganizationGroup() { String groupPath = createdGroup.getPath(); // Create AdvancedClaimToGroupMapper with organization group - IdentityProviderRepresentation idp = orgResource.identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation idp = orgResource.identityProviders().get(idpAlias).toRepresentation(); IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation(); mapper.setName("org-group-mapper"); mapper.setIdentityProviderMapper(AdvancedClaimToGroupMapper.PROVIDER_ID); mapper.setIdentityProviderAlias(idp.getAlias()); - mapper.setConfig(ImmutableMap.builder() - .put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString()) - .put(ConfigConstants.GROUP, groupPath) - .put(AdvancedClaimToGroupMapper.CLAIM, "organization") - .put(AdvancedClaimToGroupMapper.CLAIM_VALUE, orgRep.getName()) - .build()); + mapper.setConfig(Map.of( + IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString(), + ConfigConstants.GROUP, groupPath, + AdvancedClaimToGroupMapper.CLAIM, "organization", + AdvancedClaimToGroupMapper.CLAIM_VALUE, orgRep.getName())); String mapperId; - try (Response response = managedRealm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { + try (Response response = realm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); mapperId = ApiUtil.getCreatedId(response); } // Verify mapper was created - IdentityProviderMapperRepresentation createdMapper = managedRealm.admin().identityProviders() + IdentityProviderMapperRepresentation createdMapper = realm.admin().identityProviders() .get(idp.getAlias()) .getMapperById(mapperId); @@ -102,7 +137,8 @@ public void testAdvancedClaimToGroupMapperWithOrganizationGroup() { public void testCreateMapperWithOrganizationSubgroup() { // Create organization with IdP OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); + String idpAlias = organizationName + "-identity-provider"; // Create parent organization group GroupRepresentation parentGroup = new GroupRepresentation(); @@ -128,25 +164,24 @@ public void testCreateMapperWithOrganizationSubgroup() { String childGroupPath = children.get(0).getPath(); // Create mapper with child subgroup - IdentityProviderRepresentation idp = orgResource.identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation idp = orgResource.identityProviders().get(idpAlias).toRepresentation(); IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation(); mapper.setName("subgroup-mapper"); mapper.setIdentityProviderMapper(HardcodedGroupMapper.PROVIDER_ID); mapper.setIdentityProviderAlias(idp.getAlias()); - mapper.setConfig(ImmutableMap.builder() - .put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString()) - .put(ConfigConstants.GROUP, childGroupPath) - .build()); + mapper.setConfig(Map.of( + IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString(), + ConfigConstants.GROUP, childGroupPath)); String mapperId; - try (Response response = managedRealm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { + try (Response response = realm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); mapperId = ApiUtil.getCreatedId(response); } // Verify mapper was created with subgroup path - IdentityProviderMapperRepresentation createdMapper = managedRealm.admin().identityProviders() + IdentityProviderMapperRepresentation createdMapper = realm.admin().identityProviders() .get(idp.getAlias()) .getMapperById(mapperId); @@ -157,16 +192,16 @@ public void testCreateMapperWithOrganizationSubgroup() { @Test public void testGetGroupsEndpointForNonOrganizationIdp() { // Create IdP NOT linked to organization - IdentityProviderRepresentation nonOrgIdp = bc.setUpIdentityProvider(); + IdentityProviderRepresentation nonOrgIdp = createOrgBroker("non-org"); nonOrgIdp.setAlias("non-org-idp"); - try (Response response = managedRealm.admin().identityProviders().create(nonOrgIdp)) { + try (Response response = realm.admin().identityProviders().create(nonOrgIdp)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); } - getCleanup().addCleanup(() -> managedRealm.admin().identityProviders().get("non-org-idp").remove()); + realm.cleanup().add(r -> r.identityProviders().get("non-org-idp").remove()); // Create organization with groups OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); GroupRepresentation orgGroup = new GroupRepresentation(); orgGroup.setName("test-org-group"); @@ -176,7 +211,7 @@ public void testGetGroupsEndpointForNonOrganizationIdp() { // Try to get groups for non-org IdP - should return NOT_FOUND try { - managedRealm.admin().organizations().get(orgRep.getId()) + realm.admin().organizations().get(orgRep.getId()) .identityProviders().get("non-org-idp").getGroups(null, null, false, null, null, true, false); fail("Should have failed with NotFoundException"); } catch (jakarta.ws.rs.NotFoundException e) { @@ -186,9 +221,11 @@ public void testGetGroupsEndpointForNonOrganizationIdp() { @Test public void testUserAddedToOrganizationGroupViaMapper() { - // Create organization with group - OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + // Create organization with real broker + String idpAlias = organizationName + "-identity-provider"; + OrganizationRepresentation orgRep = createOrganization(realm, organizationName, + createRealOrgBroker(idpAlias, providerRealm), organizationName + ".org"); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); GroupRepresentation orgGroup = new GroupRepresentation(); orgGroup.setName("mapper-test-group"); @@ -201,27 +238,27 @@ public void testUserAddedToOrganizationGroupViaMapper() { String groupPath = orgResource.groups().group(groupId).toRepresentation(false).getPath(); // Add hardcoded group mapper to the organization IdP - IdentityProviderRepresentation idp = orgResource.identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation idp = orgResource.identityProviders().get(idpAlias).toRepresentation(); IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation(); mapper.setName("org-group-mapper"); mapper.setIdentityProviderMapper(HardcodedGroupMapper.PROVIDER_ID); mapper.setIdentityProviderAlias(idp.getAlias()); - mapper.setConfig(ImmutableMap.builder() - .put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString()) - .put(ConfigConstants.GROUP, groupPath) - .put(ConfigConstants.GROUP_TYPE, GroupModel.Type.ORGANIZATION.name()) - .build()); + mapper.setConfig(Map.of( + IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString(), + ConfigConstants.GROUP, groupPath, + ConfigConstants.GROUP_TYPE, GroupModel.Type.ORGANIZATION.name())); - try (Response response = managedRealm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { + try (Response response = realm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); } // Authenticate via IdP - user should be added to org group - assertBrokerRegistration(orgResource, bc.getUserLogin(), bc.getUserEmail()); + assertBrokerRegistration(orgResource, aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getEmail(), + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); // Verify user is member of the organization group - UserRepresentation user = getUserRepresentation(bc.getUserEmail()); + UserRepresentation user = getUserRepresentation(aliceFromProviderRealm.getEmail()); assertNotNull(user); List groupMembers = orgResource.groups().group(groupId).getMembers(null, null, false); @@ -231,8 +268,10 @@ public void testUserAddedToOrganizationGroupViaMapper() { @Test public void testUserNotAddedToGroupAfterIdpUnlinkedFromOrganization() { - OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + String idpAlias = organizationName + "-identity-provider"; + OrganizationRepresentation orgRep = createOrganization(realm, organizationName, + createRealOrgBroker(idpAlias, providerRealm), organizationName + ".org"); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); GroupRepresentation orgGroup = new GroupRepresentation(); orgGroup.setName("unlink-test-group"); @@ -245,35 +284,35 @@ public void testUserNotAddedToGroupAfterIdpUnlinkedFromOrganization() { String groupPath = orgResource.groups().group(groupId).toRepresentation(false).getPath(); // Add a HardcodedGroupMapper pointing to the org group - IdentityProviderRepresentation idp = orgResource.identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation idp = orgResource.identityProviders().get(idpAlias).toRepresentation(); IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation(); mapper.setName("unlink-test-mapper"); mapper.setIdentityProviderMapper(HardcodedGroupMapper.PROVIDER_ID); mapper.setIdentityProviderAlias(idp.getAlias()); - mapper.setConfig(ImmutableMap.builder() - .put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString()) - .put(ConfigConstants.GROUP, groupPath) - .put(ConfigConstants.GROUP_TYPE, GroupModel.Type.ORGANIZATION.name()) - .build()); + mapper.setConfig(Map.of( + IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString(), + ConfigConstants.GROUP, groupPath, + ConfigConstants.GROUP_TYPE, GroupModel.Type.ORGANIZATION.name())); - try (Response response = managedRealm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { + try (Response response = realm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); } // First login: user IS added to the org group while IdP is still linked - assertBrokerRegistration(orgResource, bc.getUserLogin(), bc.getUserEmail()); + assertBrokerRegistration(orgResource, aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getEmail(), + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); List groupMembers = orgResource.groups().group(groupId).getMembers(null, null, false); assertThat(groupMembers, hasSize(1)); // Log out from both realms - UserRepresentation user = getUserRepresentation(bc.getUserEmail()); - realmsResouce().realm(bc.consumerRealmName()).users().get(user.getId()).logout(); - realmsResouce().realm(bc.providerRealmName()).logoutAll(); + UserRepresentation user = getUserRepresentation(aliceFromProviderRealm.getEmail()); + realm.admin().users().get(user.getId()).logout(); + providerRealm.admin().logoutAll(); // Unlink IdP from organization - the IdP still exists in the realm but is no longer org-linked - try (Response response = orgResource.identityProviders().get(bc.getIDPAlias()).delete()) { + try (Response response = orgResource.identityProviders().get(idpAlias).delete()) { assertThat(response.getStatus(), is(Status.NO_CONTENT.getStatusCode())); } @@ -285,11 +324,10 @@ public void testUserNotAddedToGroupAfterIdpUnlinkedFromOrganization() { // Second login: bypass the org identity-first page (which hides the unlinked IdP) by // navigating directly with kc_idp_hint. The IdP still exists in the realm so login succeeds, // but the mapper cannot resolve the org group and the user is NOT re-added to it. - oauth.client("broker-app"); - oauth.realm(bc.consumerRealmName()); oauth.openLoginForm(); - driver.navigate().to(driver.getCurrentUrl() + "&kc_idp_hint=" + bc.getIDPAlias()); - loginOrgIdp(bc.getUserLogin(), bc.getUserEmail(), false, true); + oauth.getDriver().navigate().to(oauth.getDriver().getCurrentUrl() + "&kc_idp_hint=" + idpAlias); + loginPage.fillLogin(aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getPassword()); + loginPage.submit(); // Verify user was not re-added to the org group groupMembers = orgResource.groups().group(groupId).getMembers(null, null, false); @@ -298,50 +336,54 @@ public void testUserNotAddedToGroupAfterIdpUnlinkedFromOrganization() { @Test public void testRealmGroupAllowedWithOrganizationIdp() { - OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + String idpAlias = organizationName + "-identity-provider"; + OrganizationRepresentation orgRep = createOrganization(realm, organizationName, + createRealOrgBroker(idpAlias, providerRealm), organizationName + ".org"); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); // Create REALM group in the consumer realm GroupRepresentation realmGroup = new GroupRepresentation(); realmGroup.setName("realm-test-group"); - try (Response response = realmsResouce().realm(bc.consumerRealmName()).groups().add(realmGroup)) { + try (Response response = realm.admin().groups().add(realmGroup)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); } - String groupPath = realmsResouce().realm(bc.consumerRealmName()).getGroupByPath("/realm-test-group").getPath(); + String groupPath = realm.admin().getGroupByPath("/realm-test-group").getPath(); // Add mapper with REALM group to organization IdP - IdentityProviderRepresentation idp = orgResource.identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation idp = orgResource.identityProviders().get(idpAlias).toRepresentation(); IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation(); mapper.setName("realm-group-mapper"); mapper.setIdentityProviderMapper(HardcodedGroupMapper.PROVIDER_ID); mapper.setIdentityProviderAlias(idp.getAlias()); - mapper.setConfig(ImmutableMap.builder() - .put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString()) - .put(ConfigConstants.GROUP, groupPath) - .build()); + mapper.setConfig(Map.of( + IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString(), + ConfigConstants.GROUP, groupPath)); - try (Response response = managedRealm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { + try (Response response = realm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); } // Authenticate via IdP - realm groups are always allowed - assertBrokerRegistration(orgResource, bc.getUserLogin(), bc.getUserEmail()); + assertBrokerRegistration(orgResource, aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getEmail(), + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); // Verify user is member of the realm group - UserRepresentation user = getUserRepresentation(bc.getUserEmail()); + UserRepresentation user = getUserRepresentation(aliceFromProviderRealm.getEmail()); assertNotNull(user); - List userGroups = realmsResouce().realm(bc.consumerRealmName()).users().get(user.getId()).groups(); + List userGroups = realm.admin().users().get(user.getId()).groups(); assertThat(userGroups, hasSize(1)); assertThat(userGroups.get(0).getPath(), is(groupPath)); } @Test public void testHardcodedGroupMapperDoesNotAssignOrganizationGroupMembershipWhenOrganizationIsDisabled() { - OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource orgResource = managedRealm.admin().organizations().get(orgRep.getId()); + String idpAlias = organizationName + "-identity-provider"; + OrganizationRepresentation orgRep = createOrganization(realm, organizationName, + createRealOrgBroker(idpAlias, providerRealm), organizationName + ".org"); + OrganizationResource orgResource = realm.admin().organizations().get(orgRep.getId()); GroupRepresentation orgGroup = new GroupRepresentation(); orgGroup.setName("disabled-org-test-group"); @@ -353,24 +395,24 @@ public void testHardcodedGroupMapperDoesNotAssignOrganizationGroupMembershipWhen String groupPath = orgResource.groups().group(groupId).toRepresentation(false).getPath(); - IdentityProviderRepresentation idp = orgResource.identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation idp = orgResource.identityProviders().get(idpAlias).toRepresentation(); IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation(); mapper.setName("disabled-org-test-mapper"); mapper.setIdentityProviderMapper(HardcodedGroupMapper.PROVIDER_ID); mapper.setIdentityProviderAlias(idp.getAlias()); - mapper.setConfig(ImmutableMap.builder() - .put(IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.IMPORT.toString()) - .put(ConfigConstants.GROUP, groupPath) - .put(ConfigConstants.GROUP_TYPE, GroupModel.Type.ORGANIZATION.name()) - .build()); + mapper.setConfig(Map.of( + IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.IMPORT.toString(), + ConfigConstants.GROUP, groupPath, + ConfigConstants.GROUP_TYPE, GroupModel.Type.ORGANIZATION.name())); - try (Response response = managedRealm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { + try (Response response = realm.admin().identityProviders().get(idp.getAlias()).addMapper(mapper)) { assertThat(response.getStatus(), is(Status.CREATED.getStatusCode())); } // First login: org is enabled, user IS added to org group - assertBrokerRegistration(orgResource, bc.getUserLogin(), bc.getUserEmail()); + assertBrokerRegistration(orgResource, aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getEmail(), + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); List groupMembers = orgResource.groups().group(groupId).getMembers(null, null, false); assertThat(groupMembers, hasSize(1)); @@ -382,7 +424,7 @@ public void testHardcodedGroupMapperDoesNotAssignOrganizationGroupMembershipWhen } // Verify the org-linked IdP now appears disabled (org-aware wrapper) - IdentityProviderRepresentation updatedIdp = managedRealm.admin().identityProviders().get(bc.getIDPAlias()).toRepresentation(); + IdentityProviderRepresentation updatedIdp = realm.admin().identityProviders().get(idpAlias).toRepresentation(); assertThat("IdP should appear disabled when org is disabled", updatedIdp.isEnabled(), is(false)); // Group membership assigned while the org was enabled is unaffected by the org being disabled diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationOIDCProtocolMapperTest.java b/tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationOIDCProtocolMapperTest.java similarity index 66% rename from testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationOIDCProtocolMapperTest.java rename to tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationOIDCProtocolMapperTest.java index 15cd1936c2ea..7a89c7c1befd 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/organization/mapper/OrganizationOIDCProtocolMapperTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/organization/mapper/OrganizationOIDCProtocolMapperTest.java @@ -15,9 +15,8 @@ * limitations under the License. */ -package org.keycloak.testsuite.organization.mapper; +package org.keycloak.tests.organization.mapper; -import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; import java.util.HashMap; @@ -35,7 +34,6 @@ import org.keycloak.common.util.MultivaluedHashMap; import org.keycloak.common.util.UriUtils; import org.keycloak.models.ClientScopeModel; -import org.keycloak.models.OrganizationModel; import org.keycloak.models.utils.ModelToRepresentation; import org.keycloak.organization.protocol.mappers.oidc.OrganizationMembershipMapper; import org.keycloak.organization.utils.Organizations; @@ -51,29 +49,38 @@ import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.ClientScopeRepresentation; import org.keycloak.representations.idm.FederatedIdentityRepresentation; -import org.keycloak.representations.idm.IdentityProviderRepresentation; import org.keycloak.representations.idm.MemberRepresentation; import org.keycloak.representations.idm.OrganizationDomainRepresentation; import org.keycloak.representations.idm.OrganizationRepresentation; import org.keycloak.representations.idm.ProtocolMapperRepresentation; -import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.oidc.TokenMetadataRepresentation; +import org.keycloak.testframework.annotations.InjectRealm; +import org.keycloak.testframework.annotations.InjectUser; +import org.keycloak.testframework.annotations.KeycloakIntegrationTest; +import org.keycloak.testframework.injection.LifeCycle; +import org.keycloak.testframework.oauth.OAuthClient; +import org.keycloak.testframework.oauth.annotations.InjectOAuthClient; import org.keycloak.testframework.realm.ClientBuilder; -import org.keycloak.testsuite.admin.ApiUtil; -import org.keycloak.testsuite.admin.Users; -import org.keycloak.testsuite.broker.KcOidcBrokerConfiguration; -import org.keycloak.testsuite.organization.admin.AbstractOrganizationTest; -import org.keycloak.testsuite.updaters.RealmAttributeUpdater; -import org.keycloak.testsuite.util.BrowserTabUtil; +import org.keycloak.testframework.realm.CredentialBuilder; +import org.keycloak.testframework.realm.ManagedRealm; +import org.keycloak.testframework.realm.ManagedUser; +import org.keycloak.testframework.ui.annotations.InjectPage; +import org.keycloak.testframework.ui.annotations.InjectWebDriver; +import org.keycloak.testframework.ui.page.LoginPage; +import org.keycloak.testframework.ui.page.LoginUpdateProfilePage; +import org.keycloak.testframework.ui.page.LoginUsernamePage; +import org.keycloak.testframework.ui.page.SelectOrganizationPage; +import org.keycloak.testframework.ui.webdriver.ManagedWebDriver; +import org.keycloak.testframework.util.ApiUtil; +import org.keycloak.tests.organization.admin.AbstractOrganizationTest; import org.keycloak.testsuite.util.oauth.AccessTokenResponse; import org.keycloak.testsuite.util.oauth.IntrospectionResponse; -import org.keycloak.testsuite.util.oauth.OAuthClient; import org.keycloak.testsuite.util.oauth.UserInfoResponse; -import org.junit.Before; -import org.junit.Test; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim; @@ -93,9 +100,34 @@ import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; +@KeycloakIntegrationTest public class OrganizationOIDCProtocolMapperTest extends AbstractOrganizationTest { - @Before + @InjectRealm(ref = "provider", config = ProviderRealmConf.class, lifecycle = LifeCycle.METHOD) + ManagedRealm providerRealm; + + @InjectUser(ref = "alice", realmRef = "provider", config = AliceUserConf.class) + ManagedUser aliceFromProviderRealm; + + @InjectWebDriver + ManagedWebDriver driver; + + @InjectOAuthClient + OAuthClient oauth; + + @InjectPage + LoginPage loginPage; + + @InjectPage + LoginUsernamePage loginUsernamePage; + + @InjectPage + LoginUpdateProfilePage loginUpdateProfilePage; + + @InjectPage + SelectOrganizationPage selectOrganizationPage; + + @BeforeEach public void onBefore() { setMapperConfig(ProtocolMapperUtils.MULTIVALUED, null); setMapperConfig(OIDCAttributeMapperHelper.JSON_TYPE, null); @@ -104,8 +136,8 @@ public void onBefore() { @Test public void testPasswordGrantType() throws Exception { - OrganizationResource orga = managedRealm.admin().organizations().get(createOrganization("org-a").getId()); - OrganizationResource orgb = managedRealm.admin().organizations().get(createOrganization("org-b").getId()); + OrganizationResource orga = realm.admin().organizations().get(createOrganization("org-a").getId()); + OrganizationResource orgb = realm.admin().organizations().get(createOrganization("org-b").getId()); addMember(orga); @@ -136,8 +168,8 @@ public void testPasswordGrantType() throws Exception { @Test @SuppressWarnings("unchecked") public void testMultipleOrganizationScopes() throws Exception { - OrganizationResource orga = managedRealm.admin().organizations().get(createOrganization("org-a").getId()); - OrganizationResource orgb = managedRealm.admin().organizations().get(createOrganization("org-b").getId()); + OrganizationResource orga = realm.admin().organizations().get(createOrganization("org-a").getId()); + OrganizationResource orgb = realm.admin().organizations().get(createOrganization("org-b").getId()); addMember(orga); @@ -183,10 +215,10 @@ public void testMultipleOrganizationScopes() throws Exception { @Test public void testOrganizationNotAddedByGroupMapper() throws Exception { - OrganizationResource organization = managedRealm.admin().organizations().get(createOrganization().getId()); + OrganizationResource organization = realm.admin().organizations().get(createOrganization().getId()); addMember(organization); - ClientRepresentation client = managedRealm.admin().clients().findByClientId("direct-grant").get(0); - ClientResource clientResource = managedRealm.admin().clients().get(client.getId()); + ClientRepresentation client = realm.admin().clients().findByClientId("direct-grant").get(0); + ClientResource clientResource = realm.admin().clients().get(client.getId()); clientResource.getProtocolMappers().createMapper(createGroupMapper()).close(); oauth.client("direct-grant", "password"); @@ -202,61 +234,65 @@ public void testOrganizationNotAddedByGroupMapper() throws Exception { @Test public void testOrganizationScopeMapsSpecificOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); // resolve organization based on the organization scope value oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization:" + orgA.getAlias()); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - Assertions.assertFalse(loginPage.isPasswordInputPresent()); - assertTrue(loginPage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); - assertFalse(loginPage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); - assertFalse(driver.getPageSource().contains("Your email domain matches")); + assertFalse(loginPage.isPasswordInputPresent()); + assertTrue(loginUsernamePage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); + assertFalse(loginUsernamePage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); + assertFalse(driver.driver().getPageSource().contains("Your email domain matches")); // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization:" + orgB.getAlias(); oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); assertFalse(loginPage.isPasswordInputPresent()); - assertTrue(loginPage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); - assertFalse(loginPage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); - loginPage.loginUsername(member.getEmail()); + assertTrue(loginUsernamePage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); + assertFalse(loginUsernamePage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); assertTrue(loginPage.isPasswordInputPresent()); assertTrue(loginPage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); assertFalse(loginPage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); assertScopeAndClaims(orgScope, orgB); } @Test public void testOrganizationScopeMapsAllOrganizations() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); // resolve organization based on the organization scope value oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization:" + orgA.getAlias()); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); assertFalse(loginPage.isPasswordInputPresent()); - assertTrue(loginPage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); - assertFalse(loginPage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); + assertTrue(loginUsernamePage.isSocialButtonPresent(orgA.getAlias() + "-identity-provider")); + assertFalse(loginUsernamePage.isSocialButtonPresent(orgB.getAlias() + "-identity-provider")); // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization:*"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -285,16 +321,18 @@ public void testOrganizationScopeMapsAllOrganizations() { @Test public void testOrganizationScopeAnyMapsSingleOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); // resolve organization based on the organization scope value - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); assertScopeAndClaims(orgScope, orgA); } @@ -302,20 +340,22 @@ public void testOrganizationScopeAnyMapsSingleOrganization() { @Test public void testOrganizationScopeAnyAskUserToSelectOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization"); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); - assertFalse(driver.getPageSource().contains("kc-select-try-another-way-form")); + assertFalse(driver.driver().getPageSource().contains("kc-select-try-another-way-form")); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); selectOrganizationPage.selectOrganization(orgB.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -324,20 +364,23 @@ public void testOrganizationScopeAnyAskUserToSelectOrganization() { assertThat(organizations.contains(orgA.getAlias()), is(false)); assertThat(organizations.contains(orgB.getAlias()), is(true)); - managedRealm.admin().users().get(member.getId()).logout(); - oauth.realm(bc.consumerRealmName()); + realm.admin().users().get(member.getId()).logout(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); orgB.setEnabled(false); - managedRealm.admin().organizations().get(orgB.getId()).update(orgB).close(); - oauth.realm(bc.consumerRealmName()); + realm.admin().organizations().get(orgB.getId()).update(orgB).close(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); loginPage.assertCurrent(); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); accessToken = oauth.verifyToken(response.getAccessToken()); @@ -350,20 +393,22 @@ public void testOrganizationScopeAnyAskUserToSelectOrganization() { @Test public void testOrganizationScopeSelectDisabledOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization"); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); - assertFalse(driver.getPageSource().contains("kc-select-try-another-way-form")); + assertFalse(driver.driver().getPageSource().contains("kc-select-try-another-way-form")); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); selectOrganizationPage.selectOrganization(orgB.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -372,20 +417,23 @@ public void testOrganizationScopeSelectDisabledOrganization() { assertThat(organizations.contains(orgA.getAlias()), is(false)); assertThat(organizations.contains(orgB.getAlias()), is(true)); - managedRealm.admin().users().get(member.getId()).logout(); - oauth.realm(bc.consumerRealmName()); + realm.admin().users().get(member.getId()).logout(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); orgB.setEnabled(false); - managedRealm.admin().organizations().get(orgB.getId()).update(orgB).close(); - oauth.realm(bc.consumerRealmName()); + realm.admin().organizations().get(orgB.getId()).update(orgB).close(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); loginPage.assertCurrent(); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); accessToken = oauth.verifyToken(response.getAccessToken()); @@ -398,20 +446,22 @@ public void testOrganizationScopeSelectDisabledOrganization() { @Test public void testOrganizationScopeSpecifyDisabledOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization"); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); - assertFalse(driver.getPageSource().contains("kc-select-try-another-way-form")); + assertFalse(driver.driver().getPageSource().contains("kc-select-try-another-way-form")); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); selectOrganizationPage.selectOrganization(orgB.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -420,23 +470,26 @@ public void testOrganizationScopeSpecifyDisabledOrganization() { assertThat(organizations.contains(orgA.getAlias()), is(false)); assertThat(organizations.contains(orgB.getAlias()), is(true)); - managedRealm.admin().users().get(member.getId()).logout(); - oauth.realm(bc.consumerRealmName()); + realm.admin().users().get(member.getId()).logout(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); orgB.setEnabled(false); - managedRealm.admin().organizations().get(orgB.getId()).update(orgB).close(); + realm.admin().organizations().get(orgB.getId()).update(orgB).close(); oauth.scope("organization:" + orgB.getAlias()); oauth.openLoginForm(); assertTrue(driver.getCurrentUrl().contains("Invalid+scopes%3A+openid+organization")); oauth.scope("organization:" + orgA.getAlias()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); accessToken = oauth.verifyToken(response.getAccessToken()); @@ -447,7 +500,7 @@ public void testOrganizationScopeSpecifyDisabledOrganization() { oauth.openLoginForm(); Assertions.assertTrue(oauth.parseLoginResponse().isSuccess()); orgA.setEnabled(false); - managedRealm.admin().organizations().get(orgA.getId()).update(orgA).close(); + realm.admin().organizations().get(orgA.getId()).update(orgA).close(); oauth.openLoginForm(); assertTrue(driver.getCurrentUrl().contains("Invalid+scopes%3A+openid+organization")); @@ -463,152 +516,157 @@ public void testOrganizationScopeSpecifyDisabledOrganization() { @Test public void testMultipleTabsTrackingDifferentOrganizationSelectionHoldAcrossTokenRefresh() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization"); - try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) { - //first tab - select orgA - oauth.realm(bc.consumerRealmName()); - oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - selectOrganizationPage.selectOrganization(orgA.getAlias()); - loginPage.login(memberPassword); - AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab1RefreshToken = response.getRefreshToken(); - - //second tab - select orgB - tabUtil.newTab(oauth.loginForm().build()); - assertThat(tabUtil.getCountOfTabs(), is(2)); - selectOrganizationPage.assertCurrent(); - selectOrganizationPage.selectOrganization(orgB.getAlias()); - response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab2RefreshToken = response.getRefreshToken(); - - //refresh first tab - ensure still orgA - tabUtil.switchToTab(0); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertThat(response.getScope(), containsString("organization")); - AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); - List organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgA.getAlias()), is(true)); - - //refresh second tab - ensure still orgB - tabUtil.switchToTab(1); - response = oauth.doRefreshTokenRequest(tab2RefreshToken); - assertThat(response.getScope(), containsString("organization")); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgB.getAlias()), is(true)); - } + var tabUtil = driver.tabs(); + //first tab - select orgA + oauth.realm(realm.getName()); + oauth.openLoginForm(); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + selectOrganizationPage.selectOrganization(orgA.getAlias()); + loginPage.fillPassword(memberPassword); + loginPage.submit(); + AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab1RefreshToken = response.getRefreshToken(); + + //second tab - select orgB + tabUtil.newTab(oauth.loginForm().build()); + assertThat(tabUtil.getCountOfTabs(), is(2)); + selectOrganizationPage.assertCurrent(); + selectOrganizationPage.selectOrganization(orgB.getAlias()); + response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab2RefreshToken = response.getRefreshToken(); + + //refresh first tab - ensure still orgA + tabUtil.switchToTab(0); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertThat(response.getScope(), containsString("organization")); + AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); + List organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgA.getAlias()), is(true)); + + //refresh second tab - ensure still orgB + tabUtil.switchToTab(1); + response = oauth.doRefreshTokenRequest(tab2RefreshToken); + assertThat(response.getScope(), containsString("organization")); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgB.getAlias()), is(true)); } @Test public void testUserInfoEndpoint() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization"); - try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) { - //first tab - select orgA - oauth.realm(bc.consumerRealmName()); - oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - selectOrganizationPage.selectOrganization(orgA.getAlias()); - loginPage.login(memberPassword); - AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab1AccessToken = response.getAccessToken(); - - //second tab - select orgB - tabUtil.newTab(oauth.loginForm().build()); - assertThat(tabUtil.getCountOfTabs(), is(2)); - selectOrganizationPage.assertCurrent(); - selectOrganizationPage.selectOrganization(orgB.getAlias()); - response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab2AccessToken = response.getAccessToken(); - - UserInfoResponse userInfoResponse = oauth.userInfoRequest(tab1AccessToken).send(); - UserInfo userInfo = userInfoResponse.getUserInfo(); - List organizations = (List) userInfo.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgA.getAlias()), is(true)); - - userInfoResponse = oauth.userInfoRequest(tab2AccessToken).send(); - userInfo = userInfoResponse.getUserInfo(); - organizations = (List) userInfo.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgB.getAlias()), is(true)); - } + var tabUtil = driver.tabs(); + //first tab - select orgA + oauth.realm(realm.getName()); + oauth.openLoginForm(); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + selectOrganizationPage.selectOrganization(orgA.getAlias()); + loginPage.fillPassword(memberPassword); + loginPage.submit(); + AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab1AccessToken = response.getAccessToken(); + + //second tab - select orgB + tabUtil.newTab(oauth.loginForm().build()); + assertThat(tabUtil.getCountOfTabs(), is(2)); + selectOrganizationPage.assertCurrent(); + selectOrganizationPage.selectOrganization(orgB.getAlias()); + response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab2AccessToken = response.getAccessToken(); + + UserInfoResponse userInfoResponse = oauth.userInfoRequest(tab1AccessToken).send(); + UserInfo userInfo = userInfoResponse.getUserInfo(); + List organizations = (List) userInfo.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgA.getAlias()), is(true)); + + userInfoResponse = oauth.userInfoRequest(tab2AccessToken).send(); + userInfo = userInfoResponse.getUserInfo(); + organizations = (List) userInfo.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgB.getAlias()), is(true)); } @Test - public void testIntrospectionEndpoint() throws IOException { + public void testIntrospectionEndpoint() throws Exception { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization"); - try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) { - //first tab - select orgA - oauth.realm(bc.consumerRealmName()); - oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - selectOrganizationPage.selectOrganization(orgA.getAlias()); - loginPage.login(memberPassword); - AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab1AccessToken = response.getAccessToken(); - - //second tab - select orgB - tabUtil.newTab(oauth.loginForm().build()); - assertThat(tabUtil.getCountOfTabs(), is(2)); - selectOrganizationPage.assertCurrent(); - selectOrganizationPage.selectOrganization(orgB.getAlias()); - response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab2AccessToken = response.getAccessToken(); - - IntrospectionResponse userInfoResponse = oauth.introspectionRequest(tab1AccessToken).send(); - TokenMetadataRepresentation metadata = userInfoResponse.asTokenMetadata(); - List organizations = (List) metadata.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgA.getAlias()), is(true)); - - userInfoResponse = oauth.introspectionRequest(tab2AccessToken).send(); - metadata = userInfoResponse.asTokenMetadata(); - organizations = (List) metadata.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgB.getAlias()), is(true)); - } + var tabUtil = driver.tabs(); + //first tab - select orgA + oauth.realm(realm.getName()); + oauth.openLoginForm(); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + selectOrganizationPage.selectOrganization(orgA.getAlias()); + loginPage.fillPassword(memberPassword); + loginPage.submit(); + AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab1AccessToken = response.getAccessToken(); + + //second tab - select orgB + tabUtil.newTab(oauth.loginForm().build()); + assertThat(tabUtil.getCountOfTabs(), is(2)); + selectOrganizationPage.assertCurrent(); + selectOrganizationPage.selectOrganization(orgB.getAlias()); + response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab2AccessToken = response.getAccessToken(); + + IntrospectionResponse introspectionResponse = oauth.introspectionRequest(tab1AccessToken).send(); + TokenMetadataRepresentation metadata = introspectionResponse.asTokenMetadata(); + List organizations = (List) metadata.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgA.getAlias()), is(true)); + + introspectionResponse = oauth.introspectionRequest(tab2AccessToken).send(); + metadata = introspectionResponse.asTokenMetadata(); + organizations = (List) metadata.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgB.getAlias()), is(true)); } @Test public void testRefreshTokenWithAllOrganizationsAskingForSpecificOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization:*"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -633,17 +691,18 @@ public void testRefreshTokenWithAllOrganizationsAskingForSpecificOrganization() @Test public void testRefreshTokenWithAllOrganizationsAskingForAny() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization:*"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -663,18 +722,19 @@ public void testRefreshTokenWithAllOrganizationsAskingForAny() { @Test public void testRefreshTokenWithSingleOrganizationsAskingAllOrganizations() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization:orga"; String orgScope = originalScope; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -700,18 +760,19 @@ public void testRefreshTokenWithSingleOrganizationsAskingAllOrganizations() { @Test public void testRefreshTokenWithSingleOrganizationsAskingDifferentOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization:orga"; String orgScope = originalScope; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -731,20 +792,22 @@ public void testRefreshTokenWithSingleOrganizationsAskingDifferentOrganization() @Test public void testRefreshTokenScopeWithOrganizationSelectionAskingForSameOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization"; oauth.scope(originalScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); selectOrganizationPage.selectOrganization(orgB.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -777,20 +840,22 @@ public void testRefreshTokenScopeWithOrganizationSelectionAskingForSameOrganizat @Test public void testRefreshTokenScopeWithOrganizationSelectionAskingForDifferentOrganization() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization"; oauth.scope(originalScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); selectOrganizationPage.selectOrganization(orgB.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -812,20 +877,22 @@ public void testRefreshTokenScopeWithOrganizationSelectionAskingForDifferentOrga @Test public void testRefreshTokenScopeWithOrganizationSelectionAskingForAll() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization"; oauth.scope(originalScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.assertCurrent(); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgA.getAlias())); assertTrue(selectOrganizationPage.isOrganizationButtonPresent(orgB.getAlias())); selectOrganizationPage.selectOrganization(orgB.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString("organization")); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -853,16 +920,18 @@ public void testRefreshTokenScopeWithOrganizationSelectionAskingForAll() { @Test public void testRefreshTokenScopeWithSingleOrganizationAskingForAll() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization:" + orgA.getAlias(); oauth.scope(originalScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(originalScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -891,9 +960,9 @@ public void testRefreshTokenScopeWithSingleOrganizationAskingForAll() { @Test public void testPasswordGrantWithAllOrganizationsAndRefresh() throws Exception { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); oauth.client("direct-grant", "password"); oauth.scope("openid organization:*"); @@ -926,130 +995,131 @@ public void testPasswordGrantWithAllOrganizationsAndRefresh() throws Exception { @Test public void testMultipleTabsWithMixedScopeFormats() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); - - try (BrowserTabUtil tabUtil = BrowserTabUtil.getInstanceAndSetEnv(driver)) { - // first tab - organization:* (all orgs) - oauth.scope("organization:*"); - oauth.realm(bc.consumerRealmName()); - oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); - AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization:*")); - String tab1RefreshToken = response.getRefreshToken(); - AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); - List organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(2)); - assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); - - // second tab - organization (ANY, select orgB) - oauth.scope("organization"); - tabUtil.newTab(oauth.loginForm().build()); - assertThat(tabUtil.getCountOfTabs(), is(2)); - selectOrganizationPage.assertCurrent(); - selectOrganizationPage.selectOrganization(orgB.getAlias()); - response = assertSuccessfulCodeGrant(oauth); - assertThat(response.getScope(), containsString("organization")); - String tab2RefreshToken = response.getRefreshToken(); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgB.getAlias()), is(true)); - - // refresh first tab - should still have all organizations (not contaminated by tab 2's org selection) - tabUtil.switchToTab(0); - oauth.scope(null); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertThat(response.getScope(), containsString("organization:*")); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(2)); - assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); - - // refresh second tab - should still have only orgB - tabUtil.switchToTab(1); - oauth.scope(null); - response = oauth.doRefreshTokenRequest(tab2RefreshToken); - assertThat(response.getScope(), containsString("organization")); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations.contains(orgB.getAlias()), is(true)); - - // refresh second tab changing scopes to ask for orgA, should not be allowed since the user selection in - // that tab was orgB - tabUtil.switchToTab(1); - oauth.scope("organization:" + orgA.getAlias()); - response = oauth.doRefreshTokenRequest(tab2RefreshToken); - assertThat(response.getScope(), not(containsString("organization"))); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations, is(nullValue())); - - // refresh first tab changing scopes ALL -> SINGLE - tabUtil.switchToTab(0); - oauth.scope("organization:" + orgA.getAlias()); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertThat(response.getScope(), containsString("organization:" + orgA.getAlias())); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(1)); - assertThat(organizations, containsInAnyOrder(orgA.getAlias())); - - // try to refresh first tab changing scopes SINGLE -> ANY, not allowed - tabUtil.switchToTab(0); - oauth.scope("organization"); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusCode()); - assertEquals("ANY organization scope is not allowed in this context", response.getError()); - - // try to refresh first tab changing scopes SINGLE -> ALL - tabUtil.switchToTab(0); - oauth.scope("organization:*"); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertThat(response.getScope(), containsString("organization:*")); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(2)); - assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); - - // try to refresh second tab changing scopes ANY -> ALL - tabUtil.switchToTab(1); - oauth.scope("organization:*"); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertThat(response.getScope(), containsString("organization:*")); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(2)); - assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); - - // try to refresh second tab changing scopes ALL -> ANY - tabUtil.switchToTab(1); - oauth.scope("organization"); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusCode()); - assertEquals("ANY organization scope is not allowed in this context", response.getError()); - - // refresh second tab resetting scopes so that the scopes from the last successful refresh are respected - tabUtil.switchToTab(1); - oauth.scope(null); - response = oauth.doRefreshTokenRequest(tab1RefreshToken); - assertThat(response.getScope(), containsString("organization:*")); - accessToken = oauth.verifyToken(response.getAccessToken()); - organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); - assertThat(organizations.size(), is(2)); - assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); - } + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + oauth.client("broker-app", "broker-app-secret"); + + var tabUtil = driver.tabs(); + // first tab - organization:* (all orgs) + oauth.scope("organization:*"); + oauth.realm(realm.getName()); + oauth.openLoginForm(); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); + AccessTokenResponse response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization:*")); + String tab1RefreshToken = response.getRefreshToken(); + AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); + List organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(2)); + assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); + + // second tab - organization (ANY, select orgB) + oauth.scope("organization"); + tabUtil.newTab(oauth.loginForm().build()); + assertThat(tabUtil.getCountOfTabs(), is(2)); + selectOrganizationPage.assertCurrent(); + selectOrganizationPage.selectOrganization(orgB.getAlias()); + response = assertSuccessfulCodeGrant(oauth); + assertThat(response.getScope(), containsString("organization")); + String tab2RefreshToken = response.getRefreshToken(); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgB.getAlias()), is(true)); + + // refresh first tab - should still have all organizations (not contaminated by tab 2's org selection) + tabUtil.switchToTab(0); + oauth.scope(null); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertThat(response.getScope(), containsString("organization:*")); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(2)); + assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); + + // refresh second tab - should still have only orgB + tabUtil.switchToTab(1); + oauth.scope(null); + response = oauth.doRefreshTokenRequest(tab2RefreshToken); + assertThat(response.getScope(), containsString("organization")); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations.contains(orgB.getAlias()), is(true)); + + // refresh second tab changing scopes to ask for orgA, should not be allowed since the user selection in + // that tab was orgB + tabUtil.switchToTab(1); + oauth.scope("organization:" + orgA.getAlias()); + response = oauth.doRefreshTokenRequest(tab2RefreshToken); + assertThat(response.getScope(), not(containsString("organization"))); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations, is(nullValue())); + + // refresh first tab changing scopes ALL -> SINGLE + tabUtil.switchToTab(0); + oauth.scope("organization:" + orgA.getAlias()); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertThat(response.getScope(), containsString("organization:" + orgA.getAlias())); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(1)); + assertThat(organizations, containsInAnyOrder(orgA.getAlias())); + + // try to refresh first tab changing scopes SINGLE -> ANY, not allowed + tabUtil.switchToTab(0); + oauth.scope("organization"); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusCode()); + assertEquals("ANY organization scope is not allowed in this context", response.getError()); + + // try to refresh first tab changing scopes SINGLE -> ALL + tabUtil.switchToTab(0); + oauth.scope("organization:*"); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertThat(response.getScope(), containsString("organization:*")); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(2)); + assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); + + // try to refresh second tab changing scopes ANY -> ALL + tabUtil.switchToTab(1); + oauth.scope("organization:*"); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertThat(response.getScope(), containsString("organization:*")); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(2)); + assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); + + // try to refresh second tab changing scopes ALL -> ANY + tabUtil.switchToTab(1); + oauth.scope("organization"); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertEquals(Status.BAD_REQUEST.getStatusCode(), response.getStatusCode()); + assertEquals("ANY organization scope is not allowed in this context", response.getError()); + + // refresh second tab resetting scopes so that the scopes from the last successful refresh are respected + tabUtil.switchToTab(1); + oauth.scope(null); + response = oauth.doRefreshTokenRequest(tab1RefreshToken); + assertThat(response.getScope(), containsString("organization:*")); + accessToken = oauth.verifyToken(response.getAccessToken()); + organizations = (List) accessToken.getOtherClaims().get(OAuth2Constants.ORGANIZATION); + assertThat(organizations.size(), is(2)); + assertThat(organizations, containsInAnyOrder(orgA.getAlias(), orgB.getAlias())); } @Test public void testIncludeOrganizationAttributes() throws Exception { OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource organization = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource organization = realm.admin().organizations().get(orgRep.getId()); addMember(organization); setMapperConfig(OrganizationMembershipMapper.ADD_ORGANIZATION_ATTRIBUTES, Boolean.TRUE.toString()); @@ -1093,7 +1163,7 @@ public void testIncludeOrganizationAttributes() throws Exception { @SuppressWarnings("unchecked") public void testIncludeOrganizationId() throws Exception { OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource organization = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource organization = realm.admin().organizations().get(orgRep.getId()); addMember(organization); setMapperConfig(OrganizationMembershipMapper.ADD_ORGANIZATION_ID, Boolean.TRUE.toString()); @@ -1133,9 +1203,9 @@ public void testIncludeOrganizationId() throws Exception { @Test public void testOrganizationsClaimAsList() throws Exception { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); setMapperConfig(OIDCAttributeMapperHelper.JSON_TYPE, "String"); oauth.client("direct-grant", "password"); @@ -1151,9 +1221,9 @@ public void testOrganizationsClaimAsList() throws Exception { @Test public void testOrganizationsClaimSingleValued() throws Exception { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); setMapperConfig(ProtocolMapperUtils.MULTIVALUED, Boolean.FALSE.toString()); oauth.client("direct-grant", "password"); @@ -1170,7 +1240,7 @@ public void testOrganizationsClaimSingleValued() throws Exception { public void testInvalidOrganizationScope() throws MalformedURLException { oauth.client("broker-app", "broker-app-secret"); oauth.scope("organization:unknown"); - oauth.realm(TEST_REALM_NAME); + oauth.realm(realm.getName()); oauth.openLoginForm(); MultivaluedHashMap queryParams = UriUtils.decodeQueryString(new URL(driver.getCurrentUrl()).getQuery()); assertEquals("invalid_scope", queryParams.getFirst("error")); @@ -1178,38 +1248,38 @@ public void testInvalidOrganizationScope() throws MalformedURLException { @Test public void testAuthenticatingUsingBroker() { - OrganizationResource organization = managedRealm.admin().organizations().get(createOrganization().getId()); - IdentityProviderRepresentation idp = organization.identityProviders().get(bc.getIDPAlias()).toRepresentation(); - idp.getConfig().put(OrganizationModel.ORGANIZATION_DOMAIN_ATTRIBUTE, "neworg.org"); - managedRealm.admin().identityProviders().get(bc.getIDPAlias()).update(idp); + String idpAlias = organizationName + "-identity-provider"; + OrganizationRepresentation orgRep = createOrganization(realm, organizationName, + createRealOrgBroker(idpAlias, providerRealm), organizationName + ".org"); + OrganizationResource organization = realm.admin().organizations().get(orgRep.getId()); oauth.scope(OAuth2Constants.ORGANIZATION); - openIdentityFirstLoginPage(bc.getUserEmail(), true, idp.getAlias(), false, false); - - loginOrgIdp(bc.getUserEmail(), bc.getUserEmail(),true, true); + assertBrokerRegistration(organization, aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getEmail(), + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); - assertIsMember(bc.getUserEmail(), organization); - UserRepresentation user = managedRealm.admin().users().search(bc.getUserEmail()).get(0); - List federatedIdentities = managedRealm.admin().users().get(user.getId()).getFederatedIdentity(); + UserRepresentation user = realm.admin().users().search(aliceFromProviderRealm.getEmail()).get(0); + List federatedIdentities = realm.admin().users().get(user.getId()).getFederatedIdentity(); assertEquals(1, federatedIdentities.size()); - assertEquals(bc.getIDPAlias(), federatedIdentities.get(0).getIdentityProvider()); + assertEquals(idpAlias, federatedIdentities.get(0).getIdentityProvider()); } @Test public void testMapDifferentOrganizationWhenReAuthenticating() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization:orga"; String orgScope = originalScope; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1220,7 +1290,7 @@ public void testMapDifferentOrganizationWhenReAuthenticating() { assertThat(organizations.contains(orgA.getAlias()), is(true)); orgScope = "organization:orgb"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); @@ -1235,19 +1305,20 @@ public void testMapDifferentOrganizationWhenReAuthenticating() { @Test public void testSelectOrganizationMapDifferentOrganizationWhenReAuthenticating() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization"; String orgScope = originalScope; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.selectOrganization(orgA.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1258,7 +1329,7 @@ public void testSelectOrganizationMapDifferentOrganizationWhenReAuthenticating() assertThat(organizations.contains(orgA.getAlias()), is(true)); orgScope = "organization:orgb"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); @@ -1273,22 +1344,23 @@ public void testSelectOrganizationMapDifferentOrganizationWhenReAuthenticating() @Test public void testForceSelectingOrganizationWhenReAuthenticatingUsingDifferentClient() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - ClientRepresentation client = managedRealm.admin().clients().findByClientId("broker-app").get(0); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + ClientRepresentation client = realm.admin().clients().findByClientId("broker-app").get(0); client.setId(null); client.setClientId("broker-app2"); - managedRealm.admin().clients().create(client).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization + realm.admin().clients().create(client).close(); oauth.client("broker-app", "broker-app-secret"); String originalScope = "organization:orga"; String orgScope = originalScope; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1300,7 +1372,7 @@ public void testForceSelectingOrganizationWhenReAuthenticatingUsingDifferentClie orgScope = "organization"; oauth.client("broker-app2", "broker-app-secret"); oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); selectOrganizationPage.selectOrganization(orgB.getAlias()); response = assertSuccessfulCodeGrant(); @@ -1316,19 +1388,20 @@ public void testForceSelectingOrganizationWhenReAuthenticatingUsingDifferentClie @Test public void testReAuthenticationUserMemberOfSingleOrganizationUsingDifferentClient() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); - ClientRepresentation client = managedRealm.admin().clients().findByClientId("broker-app").get(0); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + ClientRepresentation client = realm.admin().clients().findByClientId("broker-app").get(0); client.setId(null); client.setClientId("broker-app2"); - managedRealm.admin().clients().create(client).close(); + realm.admin().clients().create(client).close(); client.setProtocolMappers(null); - managedRealm.admin().clients().create(client).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization + realm.admin().clients().create(client).close(); oauth.client("broker-app", "broker-app-secret"); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); assertSuccessfulCodeGrant(); oauth.client("broker-app2", "broker-app-secret"); oauth.openLoginForm(); @@ -1347,18 +1420,19 @@ public void testReAuthenticationUserMemberOfSingleOrganizationUsingDifferentClie @Test public void testReAuthenticationUserNotMemberOfOrganizationUsingDifferentClient() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); - managedRealm.admin().organizations().get(orgA.getId()).members().member(member.getId()).delete().close(); - ClientRepresentation client = managedRealm.admin().clients().findByClientId("broker-app").get(0); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + realm.admin().organizations().get(orgA.getId()).members().member(member.getId()).delete().close(); + ClientRepresentation client = realm.admin().clients().findByClientId("broker-app").get(0); client.setId(null); client.setClientId("broker-app2"); - managedRealm.admin().clients().create(client).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization + realm.admin().clients().create(client).close(); oauth.client("broker-app", "broker-app-secret"); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); assertSuccessfulCodeGrant(); oauth.client("broker-app2", "broker-app-secret"); oauth.openLoginForm(); @@ -1378,18 +1452,19 @@ public void testReAuthenticationUserNotMemberOfOrganizationUsingDifferentClient( @Test public void testDoNotAskToSelectOrganizationIfOrganizationScopeNotPresent() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.selectOrganization(orgA.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1403,18 +1478,20 @@ public void testDoNotAskToSelectOrganizationIfOrganizationScopeNotPresent() { @Test public void testSelectDifferentOrganizationWhenReAuthenticating() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); // identity-first login will respect the organization provided in the scope even though the user email maps to a different organization oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); selectOrganizationPage.selectOrganization(orgA.getAlias()); - loginPage.login(memberPassword); + loginPage.fillPassword(memberPassword); + loginPage.submit(); AccessTokenResponse response = assertSuccessfulCodeGrant(); assertThat(response.getScope(), containsString(orgScope)); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1438,12 +1515,12 @@ public void testSelectDifferentOrganizationWhenReAuthenticating() { @Test public void testCustomOrganizationScopeName() { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - ClientScopeResource orgScopeResource = managedRealm.admin().clientScopes().get(orgScope.getId()); + ClientScopeResource orgScopeResource = realm.admin().clientScopes().get(orgScope.getId()); ProtocolMapperRepresentation orgMapper = orgScopeResource.getProtocolMappers().getMappers().stream() .filter(m -> OIDCLoginProtocolFactory.ORGANIZATION.equals(m.getName())) .findAny() @@ -1452,27 +1529,29 @@ public void testCustomOrganizationScopeName() { orgScope.setProtocolMappers(List.of(orgMapper)); orgScope.setId(null); orgScope.setName("org"); - String createdId = ApiUtil.getCreatedId(managedRealm.admin().clientScopes().create(orgScope)); - managedRealm.admin().addDefaultDefaultClientScope(createdId); - ClientRepresentation client = managedRealm.admin().clients().findByClientId("broker-app").get(0); - managedRealm.admin().clients().get(client.getId()).addDefaultClientScope(createdId); - getCleanup().addCleanup(() -> managedRealm.admin().clientScopes().get(createdId).remove()); + String createdId = ApiUtil.getCreatedId(realm.admin().clientScopes().create(orgScope)); + realm.admin().addDefaultDefaultClientScope(createdId); + ClientRepresentation client = realm.admin().clients().findByClientId("broker-app").get(0); + realm.admin().clients().get(client.getId()).addDefaultClientScope(createdId); + realm.cleanup().add(r -> r.clientScopes().get(createdId).remove()); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); String scopeName = "org:" + orgA.getAlias(); oauth.scope(scopeName); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); assertScopeAndClaims(scopeName, orgA); } @Test public void testCustomOrganizationScopeNameAllOrganizations() { - OrganizationResource orga = managedRealm.admin().organizations().get(createOrganization("org-a").getId()); - OrganizationResource orgb = managedRealm.admin().organizations().get(createOrganization("org-b").getId()); + OrganizationResource orga = realm.admin().organizations().get(createOrganization("org-a").getId()); + OrganizationResource orgb = realm.admin().organizations().get(createOrganization("org-b").getId()); addMember(orga); @@ -1483,11 +1562,11 @@ public void testCustomOrganizationScopeNameAllOrganizations() { Assertions.assertTrue(orga.members().list(-1, -1).stream().map(UserRepresentation::getId).anyMatch(member.getId()::equals)); Assertions.assertTrue(orgb.members().list(-1, -1).stream().map(UserRepresentation::getId).anyMatch(member.getId()::equals)); - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - ClientScopeResource orgScopeResource = managedRealm.admin().clientScopes().get(orgScope.getId()); + ClientScopeResource orgScopeResource = realm.admin().clientScopes().get(orgScope.getId()); ProtocolMapperRepresentation orgMapper = orgScopeResource.getProtocolMappers().getMappers().stream() .filter(m -> OIDCLoginProtocolFactory.ORGANIZATION.equals(m.getName())) .findAny() @@ -1496,19 +1575,21 @@ public void testCustomOrganizationScopeNameAllOrganizations() { orgScope.setProtocolMappers(List.of(orgMapper)); orgScope.setId(null); orgScope.setName("org"); - String createdId = ApiUtil.getCreatedId(managedRealm.admin().clientScopes().create(orgScope)); - managedRealm.admin().addDefaultDefaultClientScope(createdId); - ClientRepresentation client = managedRealm.admin().clients().findByClientId("broker-app").get(0); - managedRealm.admin().clients().get(client.getId()).addDefaultClientScope(createdId); - getCleanup().addCleanup(() -> managedRealm.admin().clientScopes().get(createdId).remove()); + String createdId = ApiUtil.getCreatedId(realm.admin().clientScopes().create(orgScope)); + realm.admin().addDefaultDefaultClientScope(createdId); + ClientRepresentation client = realm.admin().clients().findByClientId("broker-app").get(0); + realm.admin().clients().get(client.getId()).addDefaultClientScope(createdId); + realm.cleanup().add(r -> r.clientScopes().get(createdId).remove()); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); String scopeName = "org:*"; oauth.scope(scopeName); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); String code = oauth.parseLoginResponse().getCode(); AccessTokenResponse response = oauth.doAccessTokenRequest(code); @@ -1524,8 +1605,8 @@ public void testCustomOrganizationScopeNameAllOrganizations() { @Test @SuppressWarnings("unchecked") public void testCustomOrganizationScopeNameMultipleSpecific() throws Exception { - OrganizationResource orga = managedRealm.admin().organizations().get(createOrganization("org-a").getId()); - OrganizationResource orgb = managedRealm.admin().organizations().get(createOrganization("org-b").getId()); + OrganizationResource orga = realm.admin().organizations().get(createOrganization("org-a").getId()); + OrganizationResource orgb = realm.admin().organizations().get(createOrganization("org-b").getId()); addMember(orga); @@ -1537,11 +1618,11 @@ public void testCustomOrganizationScopeNameMultipleSpecific() throws Exception { assertTrue(orgb.members().list(null, null).stream().map(UserRepresentation::getId).anyMatch(member.getId()::equals)); // Create custom "org" scope with OrganizationMembershipMapper - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - ClientScopeResource orgScopeResource = managedRealm.admin().clientScopes().get(orgScope.getId()); + ClientScopeResource orgScopeResource = realm.admin().clientScopes().get(orgScope.getId()); ProtocolMapperRepresentation orgMapper = orgScopeResource.getProtocolMappers().getMappers().stream() .filter(m -> OIDCLoginProtocolFactory.ORGANIZATION.equals(m.getName())) .findAny() @@ -1550,11 +1631,11 @@ public void testCustomOrganizationScopeNameMultipleSpecific() throws Exception { orgScope.setProtocolMappers(List.of(orgMapper)); orgScope.setId(null); orgScope.setName("org"); - String createdId = ApiUtil.getCreatedId(managedRealm.admin().clientScopes().create(orgScope)); - managedRealm.admin().addDefaultDefaultClientScope(createdId); - ClientRepresentation testApp = managedRealm.admin().clients().findByClientId("test-app").get(0); - managedRealm.admin().clients().get(testApp.getId()).addDefaultClientScope(createdId); - getCleanup().addCleanup(() -> managedRealm.admin().clientScopes().get(createdId).remove()); + String createdId = ApiUtil.getCreatedId(realm.admin().clientScopes().create(orgScope)); + realm.admin().addDefaultDefaultClientScope(createdId); + ClientRepresentation testApp = realm.admin().clients().findByClientId("test-app").get(0); + realm.admin().clients().get(testApp.getId()).addDefaultClientScope(createdId); + realm.cleanup().add(r -> r.clientScopes().get(createdId).remove()); oauth.client("test-app", "password"); @@ -1583,26 +1664,30 @@ public void testCustomOrganizationScopeNameMultipleSpecific() throws Exception { @Test public void testClaimNotMappedIfUserNotMemberWhenDefaultClientScope() { OrganizationRepresentation orgARep = createOrganization("orga", true); - OrganizationResource orgA = managedRealm.admin().organizations().get(orgARep.getId()); + OrganizationResource orgA = realm.admin().organizations().get(orgARep.getId()); MemberRepresentation member = addMember(orgA, "member@" + orgARep.getDomains().iterator().next().getName()); orgA.members().member(member.getId()).delete().close(); - ClientRepresentation clientRep = managedRealm.admin().clients().findByClientId("broker-app").get(0); - ClientResource client = managedRealm.admin().clients().get(clientRep.getId()); + ClientRepresentation clientRep = realm.admin().clients().findByClientId("broker-app").get(0); + ClientResource client = realm.admin().clients().get(clientRep.getId()); ClientScopeRepresentation orgScopeRep = client.getOptionalClientScopes().stream().filter(scope -> "organization".equals(scope.getName())).findAny().orElse(null); client.removeOptionalClientScope(orgScopeRep.getId()); client.addDefaultClientScope(orgScopeRep.getId()); - getCleanup().addCleanup(() -> { - client.removeDefaultClientScope(orgScopeRep.getId()); - client.addOptionalClientScope(orgScopeRep.getId()); + realm.cleanup().add(r -> { + ClientRepresentation cr = r.clients().findByClientId("broker-app").get(0); + ClientResource crc = r.clients().get(cr.getId()); + crc.removeDefaultClientScope(orgScopeRep.getId()); + crc.addOptionalClientScope(orgScopeRep.getId()); }); // resolve organization based on the organization scope value - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); oauth.scope(null); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); String code = oauth.parseLoginResponse().getCode(); AccessTokenResponse response = oauth.doAccessTokenRequest(code); @@ -1631,19 +1716,19 @@ public void testClaimNotMappedIfUserNotMemberWhenScopeOrgRequested() { @Test public void testOrganizationsClaimMappedIfScopeInTokenDisabled() throws Exception { OrganizationRepresentation orgA = createOrganization("orga", true); - MemberRepresentation member = addMember(managedRealm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); + MemberRepresentation member = addMember(realm.admin().organizations().get(orgA.getId()), "member@" + orgA.getDomains().iterator().next().getName()); OrganizationRepresentation orgB = createOrganization("orgb", true); - managedRealm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); + realm.admin().organizations().get(orgB.getId()).members().addMember(member.getId()).close(); - ClientRepresentation clientRep = managedRealm.admin().clients().findByClientId("broker-app").get(0); - ClientResource client = managedRealm.admin().clients().get(clientRep.getId()); + ClientRepresentation clientRep = realm.admin().clients().findByClientId("broker-app").get(0); + ClientResource client = realm.admin().clients().get(clientRep.getId()); ClientScopeRepresentation orgScopeRep = client.getOptionalClientScopes().stream().filter(scope -> "organization".equals(scope.getName())).findAny().orElse(null); orgScopeRep.setAttributes(Map.of(ClientScopeModel.INCLUDE_IN_TOKEN_SCOPE, "false")); - getCleanup().addCleanup(() -> { + realm.cleanup().add(r -> { orgScopeRep.setAttributes(Map.of(ClientScopeModel.INCLUDE_IN_TOKEN_SCOPE, "true")); - managedRealm.admin().clientScopes().get(orgScopeRep.getId()).update(orgScopeRep); + r.clientScopes().get(orgScopeRep.getId()).update(orgScopeRep); }); - managedRealm.admin().clientScopes().get(orgScopeRep.getId()).update(orgScopeRep); + realm.admin().clientScopes().get(orgScopeRep.getId()).update(orgScopeRep); oauth.client("direct-grant", "password"); oauth.scope("openid organization:*"); @@ -1660,7 +1745,7 @@ public void testOrganizationsClaimMappedIfScopeInTokenDisabled() throws Exceptio public void testOrganizationAttributeNamedIdIsOverriddenByOrganizationId() throws Exception { // When an organization has a custom attribute called "id", the organization ID should override it in tokens OrganizationRepresentation orgRep = createOrganization(); - OrganizationResource organization = managedRealm.admin().organizations().get(orgRep.getId()); + OrganizationResource organization = realm.admin().organizations().get(orgRep.getId()); addMember(organization); // Add a custom attribute named "id" to the organization @@ -1693,7 +1778,7 @@ public void testOrganizationAttributeNamedIdIsOverriddenByOrganizationId() throw @Test public void testDomainClaim() { OrganizationRepresentation orgA = createOrganization("orga", true); - OrganizationResource organization = managedRealm.admin().organizations().get(orgA.getId()); + OrganizationResource organization = realm.admin().organizations().get(orgA.getId()); OrganizationDomainRepresentation domain = orgA.getDomains().iterator().next(); MemberRepresentation member = addMember(organization, "member@" + domain.getName()); @@ -1702,17 +1787,19 @@ public void testDomainClaim() { setMapperConfig(OrganizationMembershipMapper.ADD_ORGANIZATION_DOMAIN, Boolean.TRUE.toString()); setMapperConfig(OIDCAttributeMapperHelper.JSON_TYPE, "JSON"); - getCleanup().addCleanup(() -> { + realm.cleanup().add(r -> { setMapperConfig(OrganizationMembershipMapper.ADD_ORGANIZATION_DOMAIN, Boolean.FALSE.toString()); setMapperConfig(OIDCAttributeMapperHelper.JSON_TYPE, "String"); }); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); String orgScope = "organization"; oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); String code = oauth.parseLoginResponse().getCode(); AccessTokenResponse response = oauth.doAccessTokenRequest(code); AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1725,15 +1812,17 @@ public void testDomainClaim() { String memberEmailDomain = Organizations.getEmailDomain(this.memberEmail); memberEmailDomain = "sub." + memberEmailDomain; member.setEmail("test@" + memberEmailDomain); - managedRealm.admin().users().get(member.getId()).update(new UserRepresentation(member)); + realm.admin().users().get(member.getId()).update(new UserRepresentation(member)); orgA.addDomain(new OrganizationDomainRepresentation(memberEmailDomain)); organization.update(orgA).close(); - managedRealm.admin().users().get(member.getId()).logout(); - oauth.realm(bc.consumerRealmName()); + realm.admin().users().get(member.getId()).logout(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); code = oauth.parseLoginResponse().getCode(); response = oauth.doAccessTokenRequest(code); accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1745,15 +1834,17 @@ public void testDomainClaim() { memberEmailDomain = Organizations.getEmailDomain(member.getEmail()); member.setEmail("test@deep." + memberEmailDomain); - managedRealm.admin().users().get(member.getId()).update(new UserRepresentation(member)); + realm.admin().users().get(member.getId()).update(new UserRepresentation(member)); orgA.addDomain(new OrganizationDomainRepresentation("*." + memberEmailDomain)); organization.update(orgA).close(); - managedRealm.admin().users().get(member.getId()).logout(); - oauth.realm(bc.consumerRealmName()); + realm.admin().users().get(member.getId()).logout(); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); code = oauth.parseLoginResponse().getCode(); response = oauth.doAccessTokenRequest(code); accessToken = oauth.verifyToken(response.getAccessToken()); @@ -1823,7 +1914,7 @@ private void assertScopeAndClaims(String orgScope, OrganizationRepresentation or @Test @SuppressWarnings("unchecked") public void testCustomClaimName() throws Exception { - OrganizationResource org = managedRealm.admin().organizations().get(createOrganization("acme").getId()); + OrganizationResource org = realm.admin().organizations().get(createOrganization("acme").getId()); addMember(org); setMapperConfig(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "my_orgs"); @@ -1846,24 +1937,19 @@ public void testCustomOrganizationClaimDoesNotTriggerOrganizationValidation() th user.setEnabled(true); user.setEmail("custom-org-claim@example.com"); user.setUsername("custom-org-claim@example.com"); - Users.setPasswordFor(user, memberPassword); - try (Response response = managedRealm.admin().users().create(user)) { + try (Response response = realm.admin().users().create(user)) { user.setId(ApiUtil.getCreatedId(response)); } - getCleanup().addCleanup(() -> managedRealm.admin().users().get(user.getId()).remove()); - RealmRepresentation realm = managedRealm.admin().toRepresentation(); - realm.setOrganizationsEnabled(false); - managedRealm.admin().update(realm); - getCleanup().addCleanup(() -> { - realm.setOrganizationsEnabled(true); - managedRealm.admin().update(realm); - }); + realm.admin().users().get(user.getId()).resetPassword(CredentialBuilder.password(memberPassword).build()); + realm.cleanup().add(r -> r.users().get(user.getId()).remove()); + + realm.updateWithCleanup(r -> r.organizationsEnabled(false)); // Add a hardcoded-claim mapper that emits an "organization" claim whose value is not a real org alias. // This simulates a customer using their own "organization" attribute unrelated to Keycloak Organizations. - ClientRepresentation clientRep = managedRealm.admin().clients().findByClientId("direct-grant").get(0); - ClientResource clientResource = managedRealm.admin().clients().get(clientRep.getId()); + ClientRepresentation clientRep = realm.admin().clients().findByClientId("direct-grant").get(0); + ClientResource clientResource = realm.admin().clients().get(clientRep.getId()); createMapperAndAddCleanup(clientResource, createHardcodedClaim( "custom-org-mapper", OAuth2Constants.ORGANIZATION, "my-company", "String", true, true, true)); @@ -1917,7 +2003,7 @@ private void assertResponseMissingOrganizationScopeAndClaims(AccessTokenResponse @Test public void testOrganizationClaimNotIssuedWhenOrganizationsDisabledCodeGrant() throws Exception { - OrganizationResource orgA = managedRealm.admin().organizations().get(createOrganization("orga").getId()); + OrganizationResource orgA = realm.admin().organizations().get(createOrganization("orga").getId()); addMember(orgA); // verify organization claim IS present when organizations are enabled (via password grant) @@ -1931,21 +2017,19 @@ public void testOrganizationClaimNotIssuedWhenOrganizationsDisabledCodeGrant() t // now disable organizations on the realm and test the code grant flow // when organizations are disabled, the org authenticator skips (calls attempted()), // so the standard username/password login form is shown - try (RealmAttributeUpdater rau = new RealmAttributeUpdater(managedRealm.admin()) - .setOrganizationsEnabled(Boolean.FALSE) - .update()) { - - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); - oauth.scope("organization:*"); - oauth.realm(bc.consumerRealmName()); - oauth.openLoginForm(); - loginPage.login(memberEmail, memberPassword); - - String code = oauth.parseLoginResponse().getCode(); - response = oauth.doAccessTokenRequest(code); - assertThat(response.getStatusCode(), is(Status.OK.getStatusCode())); - assertResponseMissingOrganizationScopeAndClaims(response); - } + realm.updateWithCleanup(r -> r.organizationsEnabled(false)); + + oauth.client("broker-app", "broker-app-secret"); + oauth.scope("organization:*"); + oauth.realm(realm.getName()); + oauth.openLoginForm(); + loginPage.fillLogin(memberEmail, memberPassword); + loginPage.submit(); + + String code = oauth.parseLoginResponse().getCode(); + response = oauth.doAccessTokenRequest(code); + assertThat(response.getStatusCode(), is(Status.OK.getStatusCode())); + assertResponseMissingOrganizationScopeAndClaims(response); } @Test @@ -1958,20 +2042,20 @@ public void testOrganizationClaimNotIssuedWhenOrganizationsDisabledClientCredent .secret("secret") .serviceAccountsEnabled(true) .build(); - managedRealm.admin().clients().create(serviceClient).close(); - ClientRepresentation createdClient = managedRealm.admin().clients().findByClientId("service-account-org-test").get(0); - getCleanup().addCleanup(() -> managedRealm.admin().clients().get(createdClient.getId()).remove()); + realm.admin().clients().create(serviceClient).close(); + ClientRepresentation createdClient = realm.admin().clients().findByClientId("service-account-org-test").get(0); + realm.cleanup().add(r -> r.clients().get(createdClient.getId()).remove()); // add the organization scope as optional client scope to the service account client - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - managedRealm.admin().clients().get(createdClient.getId()).addOptionalClientScope(orgScope.getId()); + realm.admin().clients().get(createdClient.getId()).addOptionalClientScope(orgScope.getId()); // make the service account user a member of the organization - String serviceAccountUserId = managedRealm.admin().clients().get(createdClient.getId()).getServiceAccountUser().getId(); - managedRealm.admin().organizations().get(orgA.getId()).members().addMember(serviceAccountUserId).close(); + String serviceAccountUserId = realm.admin().clients().get(createdClient.getId()).getServiceAccountUser().getId(); + realm.admin().organizations().get(orgA.getId()).members().addMember(serviceAccountUserId).close(); // first, verify organization claim IS present when organizations are enabled oauth.client("service-account-org-test", "secret"); @@ -1982,22 +2066,19 @@ public void testOrganizationClaimNotIssuedWhenOrganizationsDisabledClientCredent assertThat(accessToken.getOtherClaims().keySet(), hasItem(OAuth2Constants.ORGANIZATION)); // now disable organizations on the realm - try (RealmAttributeUpdater rau = new RealmAttributeUpdater(managedRealm.admin()) - .setOrganizationsEnabled(Boolean.FALSE) - .update()) { - - // attempt client credentials grant with organization scope — should not include organization claim - oauth.client("service-account-org-test", "secret"); - oauth.scope("openid organization:*"); - response = oauth.doClientCredentialsGrantAccessTokenRequest(); - assertThat(response.getStatusCode(), is(200)); - assertResponseMissingOrganizationScopeAndClaims(response); - } + realm.updateWithCleanup(r -> r.organizationsEnabled(false)); + + // attempt client credentials grant with organization scope — should not include organization claim + oauth.client("service-account-org-test", "secret"); + oauth.scope("openid organization:*"); + response = oauth.doClientCredentialsGrantAccessTokenRequest(); + assertThat(response.getStatusCode(), is(200)); + assertResponseMissingOrganizationScopeAndClaims(response); } @Test public void testOrganizationClaimNotIssuedWhenOrganizationsDisabledPasswordGrant() throws Exception { - OrganizationResource orgA = managedRealm.admin().organizations().get(createOrganization("orga").getId()); + OrganizationResource orgA = realm.admin().organizations().get(createOrganization("orga").getId()); addMember(orgA); // verify organization claim IS present when organizations are enabled @@ -2009,22 +2090,19 @@ public void testOrganizationClaimNotIssuedWhenOrganizationsDisabledPasswordGrant assertThat(accessToken.getOtherClaims().keySet(), hasItem(OAuth2Constants.ORGANIZATION)); // now disable organizations on the realm - try (RealmAttributeUpdater rau = new RealmAttributeUpdater(managedRealm.admin()) - .setOrganizationsEnabled(Boolean.FALSE) - .update()) { - - // password grant with organization scope — should not include organization claim - oauth.client("direct-grant", "password"); - oauth.scope("openid organization:*"); - response = oauth.doPasswordGrantRequest(memberEmail, memberPassword); - assertThat(response.getStatusCode(), is(200)); - assertResponseMissingOrganizationScopeAndClaims(response); - } + realm.updateWithCleanup(r -> r.organizationsEnabled(false)); + + // password grant with organization scope — should not include organization claim + oauth.client("direct-grant", "password"); + oauth.scope("openid organization:*"); + response = oauth.doPasswordGrantRequest(memberEmail, memberPassword); + assertThat(response.getStatusCode(), is(200)); + assertResponseMissingOrganizationScopeAndClaims(response); } @Test public void testOrganizationClaimNotIssuedOnRefreshWhenOrganizationsDisabled() throws Exception { - OrganizationResource orgA = managedRealm.admin().organizations().get(createOrganization("orga").getId()); + OrganizationResource orgA = realm.admin().organizations().get(createOrganization("orga").getId()); addMember(orgA); // get a token with organization claims while orgs are enabled @@ -2039,20 +2117,17 @@ public void testOrganizationClaimNotIssuedOnRefreshWhenOrganizationsDisabled() t String refreshToken = response.getRefreshToken(); // disable organizations on the realm, then refresh the token - try (RealmAttributeUpdater rau = new RealmAttributeUpdater(managedRealm.admin()) - .setOrganizationsEnabled(Boolean.FALSE) - .update()) { - - // refresh should succeed but the new token should not contain organization claims - response = oauth.doRefreshTokenRequest(refreshToken); - assertThat(response.getStatusCode(), is(200)); - assertResponseMissingOrganizationScopeAndClaims(response); - } + realm.updateWithCleanup(r -> r.organizationsEnabled(false)); + + // refresh should succeed but the new token should not contain organization claims + response = oauth.doRefreshTokenRequest(refreshToken); + assertThat(response.getStatusCode(), is(200)); + assertResponseMissingOrganizationScopeAndClaims(response); } @Test public void testOrganizationScopeFilteredButOtherScopesPreservedWhenOrganizationsDisabled() throws Exception { - OrganizationResource orgA = managedRealm.admin().organizations().get(createOrganization("orga").getId()); + OrganizationResource orgA = realm.admin().organizations().get(createOrganization("orga").getId()); addMember(orgA); // create a dedicated client with direct access grants and the "organization" optional scope @@ -2061,49 +2136,48 @@ public void testOrganizationScopeFilteredButOtherScopesPreservedWhenOrganization .secret("secret") .directAccessGrantsEnabled() .build(); - managedRealm.admin().clients().create(testClient).close(); - ClientRepresentation createdClient = managedRealm.admin().clients().findByClientId("org-scope-test").get(0); - getCleanup().addCleanup(() -> managedRealm.admin().clients().get(createdClient.getId()).remove()); + realm.admin().clients().create(testClient).close(); + ClientRepresentation createdClient = realm.admin().clients().findByClientId("org-scope-test").get(0); + realm.cleanup().add(r -> r.clients().get(createdClient.getId()).remove()); - ClientScopeRepresentation orgScope = managedRealm.admin().clientScopes().findAll().stream() + ClientScopeRepresentation orgScope = realm.admin().clientScopes().findAll().stream() .filter(s -> OIDCLoginProtocolFactory.ORGANIZATION.equals(s.getName())) .findAny() .orElseThrow(); - managedRealm.admin().clients().get(createdClient.getId()).addOptionalClientScope(orgScope.getId()); + realm.admin().clients().get(createdClient.getId()).addOptionalClientScope(orgScope.getId()); // disable organizations on the realm - try (RealmAttributeUpdater rau = new RealmAttributeUpdater(managedRealm.admin()) - .setOrganizationsEnabled(Boolean.FALSE) - .update()) { - - // request the plain "organization" scope (ANY variant, resolved via allOptionalScopes) - // alongside other standard scopes - oauth.client("org-scope-test", "secret"); - oauth.scope("openid email profile organization"); - AccessTokenResponse response = oauth.doPasswordGrantRequest(memberEmail, memberPassword); - assertThat(response.getStatusCode(), is(200)); - - // organization scope should be stripped - assertThat(response.getScope(), not(containsString("organization"))); - AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); - assertThat(accessToken.getOtherClaims().keySet(), not(hasItem(OAuth2Constants.ORGANIZATION))); - - // but email and profile scopes should still be granted - assertThat(response.getScope(), containsString("email")); - assertThat(response.getScope(), containsString("profile")); - } + realm.updateWithCleanup(r -> r.organizationsEnabled(false)); + + // request the plain "organization" scope (ANY variant, resolved via allOptionalScopes) + // alongside other standard scopes + oauth.client("org-scope-test", "secret"); + oauth.scope("openid email profile organization"); + AccessTokenResponse response = oauth.doPasswordGrantRequest(memberEmail, memberPassword); + assertThat(response.getStatusCode(), is(200)); + + // organization scope should be stripped + assertThat(response.getScope(), not(containsString("organization"))); + AccessToken accessToken = oauth.verifyToken(response.getAccessToken()); + assertThat(accessToken.getOtherClaims().keySet(), not(hasItem(OAuth2Constants.ORGANIZATION))); + + // but email and profile scopes should still be granted + assertThat(response.getScope(), containsString("email")); + assertThat(response.getScope(), containsString("profile")); } private void assertClaimNotMapped(String orgScope, OrganizationRepresentation orgARep, boolean grantScope) { - OrganizationResource orgA = managedRealm.admin().organizations().get(orgARep.getId()); + OrganizationResource orgA = realm.admin().organizations().get(orgARep.getId()); MemberRepresentation member = addMember(orgA, "member@" + orgARep.getDomains().iterator().next().getName()); orgA.members().member(member.getId()).delete().close(); - oauth.client("broker-app", KcOidcBrokerConfiguration.CONSUMER_BROKER_APP_SECRET); + oauth.client("broker-app", "broker-app-secret"); oauth.scope(orgScope); - oauth.realm(bc.consumerRealmName()); + oauth.realm(realm.getName()); oauth.openLoginForm(); - loginPage.loginUsername(member.getEmail()); - loginPage.login(memberPassword); + loginUsernamePage.fillLoginWithUsernameOnly(member.getEmail()); + loginUsernamePage.submit(); + loginPage.fillPassword(memberPassword); + loginPage.submit(); String code = oauth.parseLoginResponse().getCode(); AccessTokenResponse response = oauth.doAccessTokenRequest(code); @@ -2120,6 +2194,9 @@ private void createMapperAndAddCleanup(ClientResource clientResource, ProtocolMa mapperId = ApiUtil.getCreatedId(response); } - getCleanup().addCleanup(() -> clientResource.getProtocolMappers().delete(mapperId)); + realm.cleanup().add(r -> { + ClientRepresentation cr = r.clients().findByClientId(clientResource.toRepresentation().getClientId()).get(0); + r.clients().get(cr.getId()).getProtocolMappers().delete(mapperId); + }); } } diff --git a/tests/base/src/test/java/org/keycloak/tests/organization/member/OrganizationMemberTest.java b/tests/base/src/test/java/org/keycloak/tests/organization/member/OrganizationMemberTest.java index c4cf3c77985d..6d93036a2067 100644 --- a/tests/base/src/test/java/org/keycloak/tests/organization/member/OrganizationMemberTest.java +++ b/tests/base/src/test/java/org/keycloak/tests/organization/member/OrganizationMemberTest.java @@ -65,7 +65,6 @@ import org.keycloak.testframework.realm.ManagedRealm; import org.keycloak.testframework.realm.ManagedUser; import org.keycloak.testframework.realm.UserBuilder; -import org.keycloak.testframework.realm.UserConfig; import org.keycloak.testframework.remote.runonserver.InjectRunOnServer; import org.keycloak.testframework.remote.runonserver.RunOnServerClient; import org.keycloak.testframework.ui.annotations.InjectPage; @@ -105,7 +104,7 @@ public class OrganizationMemberTest extends AbstractOrganizationTest { @InjectRealm(ref = "provider", config = AbstractOrganizationTest.ProviderRealmConf.class, lifecycle = LifeCycle.METHOD) ManagedRealm providerRealm; - @InjectUser(ref = "alice", realmRef = "provider", config = AliceUserConf.class) + @InjectUser(ref = "alice", realmRef = "provider", config = AbstractOrganizationTest.AliceUserConf.class) ManagedUser aliceFromProviderRealm; @InjectWebDriver @@ -292,7 +291,7 @@ public void testGetAll() { @Test public void testGetAllDisabledOrganization() { OrganizationRepresentation orgRep = createOrganization(realm, organizationName, - createRealOrgBroker(organizationName + "-identity-provider"), organizationName + ".org"); + createRealOrgBroker(organizationName + "-identity-provider", providerRealm), organizationName + ".org"); OrganizationResource organization = realm.admin().organizations().get(orgRep.getId()); // add some unmanaged members to the organization. @@ -301,7 +300,8 @@ public void testGetAllDisabledOrganization() { } // onboard a test user by authenticating using the organization's provider. - loginViaBroker(aliceFromProviderRealm.getEmail(), aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getPassword()); + loginViaBroker(aliceFromProviderRealm.getEmail(), aliceFromProviderRealm.getUsername(), + aliceFromProviderRealm.getPassword(), oauth, loginUsernamePage, loginPage, providerRealm); // disable the organization and check that fetching its representation has it disabled. orgRep.setEnabled(false); @@ -352,7 +352,7 @@ public void testGetAllDisabledOrganization() { @Test public void testGetAllDisabledOrganizationProvider() throws IOException { OrganizationRepresentation orgRep = createOrganization(realm, organizationName, - createRealOrgBroker(organizationName + "-identity-provider"), organizationName + ".org"); + createRealOrgBroker(organizationName + "-identity-provider", providerRealm), organizationName + ".org"); OrganizationResource organization = realm.admin().organizations().get(orgRep.getId()); // add some unmanaged members to the organization. @@ -361,7 +361,8 @@ public void testGetAllDisabledOrganizationProvider() throws IOException { } // onboard a test user by authenticating using the organization's provider. - loginViaBroker(aliceFromProviderRealm.getEmail(), aliceFromProviderRealm.getUsername(), aliceFromProviderRealm.getPassword()); + loginViaBroker(aliceFromProviderRealm.getEmail(), aliceFromProviderRealm.getUsername(), + aliceFromProviderRealm.getPassword(), oauth, loginUsernamePage, loginPage, providerRealm); // now fetch all users from the realm List members = realm.admin().users().search("*neworg*", null, null); @@ -707,15 +708,16 @@ public void testMemberInMultipleOrganizations() { @Test public void testManagedMemberOnlyRemovedFromHomeOrganization() { OrganizationResource orga = realm.admin().organizations().get( - createOrganization(realm, "org-a", createRealOrgBroker("org-a-identity-provider"), "org-a.org").getId()); + createOrganization(realm, "org-a", createRealOrgBroker("org-a-identity-provider", providerRealm), "org-a.org").getId()); loginViaBroker("alice@org-a.org", aliceFromProviderRealm.getUsername(), - aliceFromProviderRealm.getPassword(), "managed-org-a@org-a.org"); + aliceFromProviderRealm.getPassword(), "managed-org-a@org-a.org", + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); UserRepresentation memberOrgA = orga.members().list(-1, -1).get(0); realm.admin().users().get(memberOrgA.getId()).logout(); providerRealm.admin().logoutAll(); OrganizationResource orgb = realm.admin().organizations().get( - createOrganization(realm, "org-b", createRealOrgBroker("org-b-identity-provider"), "org-b.org").getId()); + createOrganization(realm, "org-b", createRealOrgBroker("org-b-identity-provider", providerRealm), "org-b.org").getId()); UserRepresentation memberOrgB = UserBuilder.create() .username("managed-org-b") .password("password") @@ -728,7 +730,8 @@ public void testManagedMemberOnlyRemovedFromHomeOrganization() { providerRealm.cleanup().add(r -> r.users().get(memberOrgBProviderId).remove()); loginViaBroker("managed-org-b@org-b.org", memberOrgB.getUsername(), - "password", "managed-org-b@org-b.org"); + "password", "managed-org-b@org-b.org", + oauth, loginUsernamePage, loginPage, loginUpdateProfilePage, providerRealm); memberOrgB = orgb.members().list(-1, -1).get(0); orga.members().addMember(memberOrgB.getId()).close(); @@ -923,36 +926,6 @@ public void testSearchMembersBriefVsFullRepresentation() { assertTrue(singleMember.getAttributes().containsKey("testAttr")); } - private void loginViaBroker(String email, String username, String password) { - loginViaBroker(email, username, password, null); - } - - private void loginViaBroker(String email, String username, String password, String updateEmail) { - oauth.openLoginForm(); - loginUsernamePage.fillLoginWithUsernameOnly(email); - loginUsernamePage.submit(); - - assertTrue(driver.getCurrentUrl().contains("/realms/" + providerRealm.getName() + "/"), - "Should be on provider realm login page"); - - loginPage.fillLogin(username, password); - loginPage.submit(); - - if (updateEmail != null) { - loginUpdateProfilePage.update("Firstname", "Lastname", updateEmail); - } - - List users = realm.admin().users().search(username); - assertEquals(1, users.size(), "Federated user should be created in consumer realm"); - - String userId = users.get(0).getId(); - realm.cleanup().add(r -> { - try { - r.users().get(userId).remove(); - } catch (NotFoundException ignored) {} - }); - } - private void loginViaNonOrgIdP(String idpAlias) { oauth.openLoginForm(); @@ -966,37 +939,8 @@ private void loginViaNonOrgIdP(String idpAlias) { loginPage.submit(); } - private IdentityProviderRepresentation createRealOrgBroker(String alias) { - IdentityProviderRepresentation idp = new IdentityProviderRepresentation(); - idp.setAlias(alias); - idp.setProviderId("keycloak-oidc"); - idp.setEnabled(true); - idp.setTrustEmail(true); - String providerBaseUrl = providerRealm.getBaseUrl(); - idp.setConfig(new HashMap<>(Map.of( - "clientId", CLIENT_ID, - "clientSecret", CLIENT_SECRET, - "authorizationUrl", providerBaseUrl + "/protocol/openid-connect/auth", - "tokenUrl", providerBaseUrl + "/protocol/openid-connect/token", - "userInfoUrl", providerBaseUrl + "/protocol/openid-connect/userinfo", - "defaultScope", "email profile", - "syncMode", "IMPORT" - ))); - return idp; - } - private UserRepresentation getUserRepFromMemberRep(MemberRepresentation member) { return new UserRepresentation(member); } - static class AliceUserConf implements UserConfig { - @Override - public UserBuilder configure(UserBuilder builder) { - return builder.username("alice") - .password("password") - .email("alice@neworg.org") - .emailVerified(true) - .name("Alice", "Org"); - } - } }