Running mappers during account linking
Closes #11195 Co-authored-by: mposolda <mposolda@gmail.com> Co-authored-by: toddkazakov
This commit is contained in:
parent
41e253c054
commit
aff6cc1cbd
2 changed files with 91 additions and 33 deletions
|
@ -950,7 +950,11 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
|||
}
|
||||
} else {
|
||||
this.session.users().addFederatedIdentity(this.realmModel, authenticatedUser, newModel);
|
||||
federatedUser = authenticatedUser;
|
||||
}
|
||||
|
||||
updateFederatedIdentity(context, federatedUser);
|
||||
|
||||
context.getIdp().authenticationFinished(authSession, context);
|
||||
|
||||
AuthenticationManager.setClientScopesInSession(authSession);
|
||||
|
|
|
@ -25,24 +25,27 @@ import org.junit.Assert;
|
|||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.keycloak.admin.client.resource.ClientResource;
|
||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||
import org.keycloak.admin.client.resource.RealmResource;
|
||||
import org.keycloak.broker.provider.HardcodedAttributeMapper;
|
||||
import org.keycloak.common.Profile;
|
||||
import org.keycloak.common.util.Base64Url;
|
||||
import org.keycloak.models.Constants;
|
||||
import org.keycloak.models.IdentityProviderMapperModel;
|
||||
import org.keycloak.models.IdentityProviderMapperSyncMode;
|
||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||
import org.keycloak.representations.AccessTokenResponse;
|
||||
import org.keycloak.representations.idm.ClientRepresentation;
|
||||
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||
import org.keycloak.representations.idm.RealmRepresentation;
|
||||
import org.keycloak.representations.idm.RoleRepresentation;
|
||||
import org.keycloak.representations.idm.UserRepresentation;
|
||||
import org.keycloak.services.resources.LoginActionsService;
|
||||
import org.keycloak.services.resources.RealmsResource;
|
||||
import org.keycloak.testsuite.ActionURIUtils;
|
||||
import org.keycloak.testsuite.adapter.AbstractServletsAdapterTest;
|
||||
import org.keycloak.testsuite.arquillian.annotation.AppServerContainer;
|
||||
import org.keycloak.testsuite.arquillian.annotation.DisableFeature;
|
||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||
import org.keycloak.testsuite.utils.arquillian.ContainerConstants;
|
||||
import org.keycloak.testsuite.broker.BrokerTestTools;
|
||||
|
@ -61,7 +64,9 @@ import java.net.URL;
|
|||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT;
|
||||
import static org.keycloak.models.AccountRoles.MANAGE_ACCOUNT_LINKS;
|
||||
|
@ -82,6 +87,9 @@ public class ClientInitiatedAccountLinkTest extends AbstractServletsAdapterTest
|
|||
public static final String CHILD_IDP = "child";
|
||||
public static final String PARENT_IDP = "parent-idp";
|
||||
public static final String PARENT_USERNAME = "parent";
|
||||
private static final String HARDCODED_ATTRIBUTE_MAPPER_NAME = "my_hardcoded_mapper";
|
||||
private static final String USER_ATTRIBUTE = "hardcoded_attribute";
|
||||
private static final String USER_ATTRIBUTE_VALUE = "hardcoded_value";
|
||||
|
||||
@Page
|
||||
protected LoginUpdateProfilePage loginUpdateProfilePage;
|
||||
|
@ -383,26 +391,7 @@ public class ClientInitiatedAccountLinkTest extends AbstractServletsAdapterTest
|
|||
|
||||
@Test
|
||||
public void testAccountLink() throws Exception {
|
||||
RealmResource realm = adminClient.realms().realm(CHILD_IDP);
|
||||
List<FederatedIdentityRepresentation> links = realm.users().get(childUserId).getFederatedIdentity();
|
||||
Assert.assertTrue(links.isEmpty());
|
||||
|
||||
UriBuilder linkBuilder = UriBuilder.fromUri(appPage.getInjectedUrl().toString())
|
||||
.path("link");
|
||||
String linkUrl = linkBuilder.clone()
|
||||
.queryParam("realm", CHILD_IDP)
|
||||
.queryParam("provider", PARENT_IDP).build().toString();
|
||||
System.out.println("linkUrl: " + linkUrl);
|
||||
navigateTo(linkUrl);
|
||||
Assert.assertTrue(loginPage.isCurrent(CHILD_IDP));
|
||||
Assert.assertTrue(driver.getPageSource().contains(PARENT_IDP));
|
||||
loginPage.login("child", "password");
|
||||
Assert.assertTrue(loginPage.isCurrent(PARENT_IDP));
|
||||
loginPage.login(PARENT_USERNAME, "password");
|
||||
System.out.println("After linking: " + driver.getCurrentUrl());
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertTrue(driver.getCurrentUrl().startsWith(linkBuilder.toTemplate()));
|
||||
Assert.assertTrue(driver.getPageSource().contains("Account Linked"));
|
||||
linkAccount();
|
||||
|
||||
OAuthClient.AccessTokenResponse response = oauth.doGrantAccessTokenRequest(CHILD_IDP, "child", "password", null, "client-linking", "password");
|
||||
Assert.assertNotNull(response.getAccessToken());
|
||||
|
@ -411,19 +400,14 @@ public class ClientInitiatedAccountLinkTest extends AbstractServletsAdapterTest
|
|||
String firstToken = getToken(response, httpClient);
|
||||
Assert.assertNotNull(firstToken);
|
||||
|
||||
|
||||
navigateTo(linkUrl);
|
||||
navigateToAccountLinkPage();
|
||||
Assert.assertTrue(driver.getPageSource().contains("Account Linked"));
|
||||
String nextToken = getToken(response, httpClient);
|
||||
Assert.assertNotNull(nextToken);
|
||||
Assert.assertNotEquals(firstToken, nextToken);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
links = realm.users().get(childUserId).getFederatedIdentity();
|
||||
RealmResource realm = adminClient.realms().realm(CHILD_IDP);
|
||||
List<FederatedIdentityRepresentation> links = realm.users().get(childUserId).getFederatedIdentity();
|
||||
Assert.assertFalse(links.isEmpty());
|
||||
|
||||
realm.users().get(childUserId).removeFederatedIdentity(PARENT_IDP);
|
||||
|
@ -431,8 +415,6 @@ public class ClientInitiatedAccountLinkTest extends AbstractServletsAdapterTest
|
|||
Assert.assertTrue(links.isEmpty());
|
||||
|
||||
logoutAll();
|
||||
|
||||
|
||||
}
|
||||
|
||||
// TODO remove this once DYNAMIC_SCOPES feature is enabled by default
|
||||
|
@ -590,6 +572,78 @@ public class ClientInitiatedAccountLinkTest extends AbstractServletsAdapterTest
|
|||
WaitUtils.waitForPageToLoad();
|
||||
}
|
||||
|
||||
|
||||
@Test
|
||||
public void testAccountLinkWithHardcodedMapper() throws Exception {
|
||||
driver.manage().timeouts().pageLoadTimeout(1, TimeUnit.DAYS);
|
||||
addHardcodedAttributeMapper();
|
||||
linkAccount();
|
||||
assertHardcodedAttributeHasBeenAssigned();
|
||||
removeHardcodedAttribute();
|
||||
removeHardcodedAttributeMapper();
|
||||
logoutAll();
|
||||
}
|
||||
|
||||
private void addHardcodedAttributeMapper() {
|
||||
IdentityProviderResource provider = adminClient.realms().realm(CHILD_IDP).identityProviders().get(PARENT_IDP);
|
||||
|
||||
IdentityProviderMapperRepresentation mapper = new IdentityProviderMapperRepresentation();
|
||||
mapper.setIdentityProviderAlias(PARENT_IDP);
|
||||
mapper.setName(HARDCODED_ATTRIBUTE_MAPPER_NAME);
|
||||
mapper.setIdentityProviderMapper("hardcoded-attribute-idp-mapper");
|
||||
mapper.setConfig(Map.of(
|
||||
IdentityProviderMapperModel.SYNC_MODE, IdentityProviderMapperSyncMode.FORCE.toString(),
|
||||
HardcodedAttributeMapper.ATTRIBUTE, USER_ATTRIBUTE,
|
||||
HardcodedAttributeMapper.ATTRIBUTE_VALUE, USER_ATTRIBUTE_VALUE)
|
||||
);
|
||||
|
||||
mapper.setIdentityProviderAlias(PARENT_IDP);
|
||||
provider.addMapper(mapper).close();
|
||||
}
|
||||
|
||||
private void removeHardcodedAttributeMapper() {
|
||||
IdentityProviderResource provider = adminClient.realms().realm(CHILD_IDP).identityProviders().get(PARENT_IDP);
|
||||
Optional<IdentityProviderMapperRepresentation> mapper = provider.getMappers().stream()
|
||||
.filter(m -> m.getName().equals(HARDCODED_ATTRIBUTE_MAPPER_NAME)).findFirst();
|
||||
|
||||
Assert.assertFalse(mapper.isEmpty());
|
||||
|
||||
provider.delete(mapper.get().getId());
|
||||
}
|
||||
|
||||
private void assertHardcodedAttributeHasBeenAssigned() {
|
||||
UserRepresentation user = adminClient.realm(CHILD_IDP).users().get(childUserId).toRepresentation();
|
||||
Assert.assertEquals(USER_ATTRIBUTE_VALUE, user.firstAttribute(USER_ATTRIBUTE));
|
||||
}
|
||||
|
||||
private void removeHardcodedAttribute() {
|
||||
UserRepresentation user = adminClient.realm(CHILD_IDP).users().get(childUserId).toRepresentation();
|
||||
user.getAttributes().remove(USER_ATTRIBUTE);
|
||||
adminClient.realm(CHILD_IDP).users().get(user.getId()).update(user);
|
||||
}
|
||||
|
||||
private void linkAccount() {
|
||||
RealmResource realm = adminClient.realms().realm(CHILD_IDP);
|
||||
List<FederatedIdentityRepresentation> links = realm.users().get(childUserId).getFederatedIdentity();
|
||||
Assert.assertTrue(links.isEmpty());
|
||||
|
||||
navigateToAccountLinkPage();
|
||||
Assert.assertTrue(loginPage.isCurrent(CHILD_IDP));
|
||||
Assert.assertTrue(driver.getPageSource().contains(PARENT_IDP));
|
||||
loginPage.login("child", "password");
|
||||
Assert.assertTrue(loginPage.isCurrent(PARENT_IDP));
|
||||
loginPage.login(PARENT_USERNAME, "password");
|
||||
System.out.println("After linking: " + driver.getCurrentUrl());
|
||||
System.out.println(driver.getPageSource());
|
||||
Assert.assertTrue(driver.getPageSource().contains("Account Linked"));
|
||||
}
|
||||
|
||||
private void navigateToAccountLinkPage() {
|
||||
UriBuilder linkBuilder = UriBuilder.fromUri(appPage.getInjectedUrl().toString())
|
||||
.path("link");
|
||||
String linkUrl = linkBuilder.clone()
|
||||
.queryParam("realm", CHILD_IDP)
|
||||
.queryParam("provider", PARENT_IDP).build().toString();
|
||||
System.out.println("linkUrl: " + linkUrl);
|
||||
navigateTo(linkUrl);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue