parent
aea6d7da27
commit
3af1134975
4 changed files with 89 additions and 35 deletions
|
@ -174,6 +174,7 @@ public class JpaUserProvider implements UserProvider.Streams, UserCredentialStor
|
||||||
public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
|
public void updateFederatedIdentity(RealmModel realm, UserModel federatedUser, FederatedIdentityModel federatedIdentityModel) {
|
||||||
FederatedIdentityEntity federatedIdentity = findFederatedIdentity(federatedUser, federatedIdentityModel.getIdentityProvider(), LockModeType.PESSIMISTIC_WRITE);
|
FederatedIdentityEntity federatedIdentity = findFederatedIdentity(federatedUser, federatedIdentityModel.getIdentityProvider(), LockModeType.PESSIMISTIC_WRITE);
|
||||||
|
|
||||||
|
federatedIdentity.setUserName(federatedIdentityModel.getUserName());
|
||||||
federatedIdentity.setToken(federatedIdentityModel.getToken());
|
federatedIdentity.setToken(federatedIdentityModel.getToken());
|
||||||
|
|
||||||
em.persist(federatedIdentity);
|
em.persist(federatedIdentity);
|
||||||
|
|
|
@ -990,6 +990,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
|
|
||||||
if (context.getIdpConfig().getSyncMode() == IdentityProviderSyncMode.FORCE) {
|
if (context.getIdpConfig().getSyncMode() == IdentityProviderSyncMode.FORCE) {
|
||||||
setBasicUserAttributes(context, federatedUser);
|
setBasicUserAttributes(context, federatedUser);
|
||||||
|
|
||||||
|
if (!Objects.equals(context.getUsername(), federatedIdentityModel.getUserName())) {
|
||||||
|
federatedIdentityModel = new FederatedIdentityModel(federatedIdentityModel.getIdentityProvider(),
|
||||||
|
federatedIdentityModel.getUserId(), context.getUsername(),
|
||||||
|
federatedIdentityModel.getToken());
|
||||||
|
|
||||||
|
this.session.users().updateFederatedIdentity(this.realmModel, federatedUser, federatedIdentityModel);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip DB write if tokens are null or equal
|
// Skip DB write if tokens are null or equal
|
||||||
|
|
|
@ -112,6 +112,9 @@ public class AccountUpdateProfilePage extends AbstractAccountPage {
|
||||||
submitButton.click();
|
submitButton.click();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void submitWithoutChanges() {
|
||||||
|
submitButton.click();
|
||||||
|
}
|
||||||
|
|
||||||
public void clickCancel() {
|
public void clickCancel() {
|
||||||
cancelButton.click();
|
cancelButton.click();
|
||||||
|
|
|
@ -26,10 +26,12 @@ import org.keycloak.models.utils.TimeBasedOTP;
|
||||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
import org.keycloak.representations.idm.FederatedIdentityRepresentation;
|
||||||
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderMapperRepresentation;
|
||||||
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
import org.keycloak.representations.idm.IdentityProviderRepresentation;
|
||||||
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
import org.keycloak.representations.idm.OAuth2ErrorRepresentation;
|
||||||
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
import org.keycloak.representations.idm.ProtocolMapperRepresentation;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.RoleRepresentation;
|
import org.keycloak.representations.idm.RoleRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.Assert;
|
import org.keycloak.testsuite.Assert;
|
||||||
|
@ -41,18 +43,18 @@ import javax.ws.rs.core.Response;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.hasItems;
|
import static org.hamcrest.Matchers.hasItems;
|
||||||
import static org.hamcrest.Matchers.is;
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.hamcrest.Matchers.not;
|
import static org.hamcrest.Matchers.not;
|
||||||
import static org.hamcrest.Matchers.notNullValue;
|
import static org.hamcrest.Matchers.notNullValue;
|
||||||
import static org.junit.Assert.assertThat;
|
|
||||||
import static org.keycloak.models.utils.TimeBasedOTP.DEFAULT_INTERVAL_SECONDS;
|
import static org.keycloak.models.utils.TimeBasedOTP.DEFAULT_INTERVAL_SECONDS;
|
||||||
import static org.keycloak.testsuite.admin.ApiUtil.removeUserByUsername;
|
import static org.keycloak.testsuite.admin.ApiUtil.removeUserByUsername;
|
||||||
import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configurePostBrokerLoginWithOTP;
|
import static org.keycloak.testsuite.broker.BrokerRunOnServerUtil.configurePostBrokerLoginWithOTP;
|
||||||
|
import static org.keycloak.testsuite.broker.BrokerTestConstants.IDP_OIDC_ALIAS;
|
||||||
import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME;
|
import static org.keycloak.testsuite.broker.BrokerTestConstants.REALM_PROV_NAME;
|
||||||
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
|
import static org.keycloak.testsuite.broker.BrokerTestTools.waitForPage;
|
||||||
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim;
|
import static org.keycloak.testsuite.util.ProtocolMapperUtil.createHardcodedClaim;
|
||||||
|
@ -423,7 +425,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
@Test
|
@Test
|
||||||
public void testIdPNotFound() {
|
public void testIdPNotFound() {
|
||||||
final String notExistingIdP = "not-exists";
|
final String notExistingIdP = "not-exists";
|
||||||
final String realmName = Optional.ofNullable(realmsResouce().realm(bc.providerRealmName()).toRepresentation().getRealm()).orElse(null);
|
final String realmName = realmsResouce().realm(bc.providerRealmName()).toRepresentation().getRealm();
|
||||||
assertThat(realmName, notNullValue());
|
assertThat(realmName, notNullValue());
|
||||||
final String LINK = OAuthClient.AUTH_SERVER_ROOT + "/realms/" + realmName + "/broker/" + notExistingIdP + "/endpoint";
|
final String LINK = OAuthClient.AUTH_SERVER_ROOT + "/realms/" + realmName + "/broker/" + notExistingIdP + "/endpoint";
|
||||||
|
|
||||||
|
@ -457,7 +459,9 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
|
|
||||||
private void checkUpdatedUserAttributesIdP(boolean isForceSync) {
|
private void checkUpdatedUserAttributesIdP(boolean isForceSync) {
|
||||||
final String IDP_NAME = getBrokerConfiguration().getIDPAlias();
|
final String IDP_NAME = getBrokerConfiguration().getIDPAlias();
|
||||||
final String USERNAME = "demoUser";
|
final String USERNAME = "demo-user";
|
||||||
|
final String PASSWORD = "demo-pwd";
|
||||||
|
final String NEW_USERNAME = "demo-user-new";
|
||||||
|
|
||||||
final String FIRST_NAME = "John";
|
final String FIRST_NAME = "John";
|
||||||
final String LAST_NAME = "Doe";
|
final String LAST_NAME = "Doe";
|
||||||
|
@ -467,63 +471,101 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
final String NEW_LAST_NAME = "Doee";
|
final String NEW_LAST_NAME = "Doee";
|
||||||
final String NEW_EMAIL = "mail123@example.com";
|
final String NEW_EMAIL = "mail123@example.com";
|
||||||
|
|
||||||
UsersResource providerUserResource = Optional.ofNullable(realmsResouce().realm(bc.providerRealmName()).users()).orElse(null);
|
RealmResource providerRealmResource = realmsResouce().realm(bc.providerRealmName());
|
||||||
assertThat("Cannot get User Resource from Provider realm", providerUserResource, Matchers.notNullValue());
|
allowUserEdit(providerRealmResource);
|
||||||
|
|
||||||
String userID = createUser(bc.providerRealmName(), USERNAME, USERNAME, FIRST_NAME, LAST_NAME, EMAIL);
|
UsersResource providerUsersResource = providerRealmResource.users();
|
||||||
assertThat("Cannot create user : " + USERNAME, userID, Matchers.notNullValue());
|
|
||||||
|
String providerUserID = createUser(bc.providerRealmName(), USERNAME, PASSWORD, FIRST_NAME, LAST_NAME, EMAIL);
|
||||||
|
UserResource providerUserResource = providerUsersResource.get(providerUserID);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
UserRepresentation user = Optional.ofNullable(providerUserResource.get(userID).toRepresentation()).orElse(null);
|
IdentityProviderResource consumerIdentityResource = getIdentityProviderResource();
|
||||||
assertThat("Cannot get user from provider", user, Matchers.notNullValue());
|
IdentityProviderRepresentation idProvider = consumerIdentityResource.toRepresentation();
|
||||||
|
|
||||||
IdentityProviderResource consumerIdentityResource = Optional.ofNullable(getIdentityProviderResource()).orElse(null);
|
updateIdPSyncMode(idProvider, consumerIdentityResource,
|
||||||
assertThat("Cannot get Identity Provider resource", consumerIdentityResource, Matchers.notNullValue());
|
isForceSync ? IdentityProviderSyncMode.FORCE : IdentityProviderSyncMode.IMPORT);
|
||||||
|
|
||||||
IdentityProviderRepresentation idProvider = Optional.ofNullable(consumerIdentityResource.toRepresentation()).orElse(null);
|
|
||||||
assertThat("Cannot get Identity Provider", idProvider, Matchers.notNullValue());
|
|
||||||
|
|
||||||
updateIdPSyncMode(idProvider, consumerIdentityResource, isForceSync ? IdentityProviderSyncMode.FORCE : IdentityProviderSyncMode.IMPORT);
|
|
||||||
|
|
||||||
driver.navigate().to(getAccountUrl(getConsumerRoot(), bc.consumerRealmName()));
|
driver.navigate().to(getAccountUrl(getConsumerRoot(), bc.consumerRealmName()));
|
||||||
WaitUtils.waitForPageToLoad();
|
WaitUtils.waitForPageToLoad();
|
||||||
|
|
||||||
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.consumerRealmName()));
|
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.consumerRealmName()));
|
||||||
logInWithIdp(IDP_NAME, USERNAME, USERNAME);
|
logInWithIdp(IDP_NAME, USERNAME, PASSWORD);
|
||||||
accountUpdateProfilePage.assertCurrent();
|
accountUpdateProfilePage.assertCurrent();
|
||||||
|
|
||||||
|
assertThat(accountUpdateProfilePage.getUsername(), Matchers.equalTo(USERNAME));
|
||||||
|
assertThat(accountUpdateProfilePage.getEmail(), Matchers.equalTo(EMAIL));
|
||||||
|
assertThat(accountUpdateProfilePage.getFirstName(), Matchers.equalTo(FIRST_NAME));
|
||||||
|
assertThat(accountUpdateProfilePage.getLastName(), Matchers.equalTo(LAST_NAME));
|
||||||
|
|
||||||
|
accountUpdateProfilePage.submitWithoutChanges();
|
||||||
|
assertAccountConsoleIsCurrent();
|
||||||
|
|
||||||
|
RealmResource consumerRealmResource = realmsResouce().realm(bc.consumerRealmName());
|
||||||
|
List<UserRepresentation> foundUsers = consumerRealmResource.users().searchByUsername(USERNAME, true);
|
||||||
|
assertThat(foundUsers, Matchers.hasSize(1));
|
||||||
|
UserRepresentation consumerUser = foundUsers.get(0);
|
||||||
|
assertThat(consumerUser, Matchers.notNullValue());
|
||||||
|
String consumerUserID = consumerUser.getId();
|
||||||
|
UserResource consumerUserResource = consumerRealmResource.users().get(consumerUserID);
|
||||||
|
|
||||||
|
checkFederatedIdentityLink(consumerUserResource, providerUserID, USERNAME);
|
||||||
|
|
||||||
logoutFromRealm(getProviderRoot(), bc.providerRealmName());
|
logoutFromRealm(getProviderRoot(), bc.providerRealmName());
|
||||||
logoutFromRealm(getConsumerRoot(), bc.consumerRealmName());
|
logoutFromRealm(getConsumerRoot(), bc.consumerRealmName());
|
||||||
|
|
||||||
driver.navigate().to(getAccountUrl(getProviderRoot(), bc.providerRealmName()));
|
UserRepresentation providerUser = providerUserResource.toRepresentation();
|
||||||
WaitUtils.waitForPageToLoad();
|
providerUser.setUsername(NEW_USERNAME);
|
||||||
|
providerUser.setFirstName(NEW_FIRST_NAME);
|
||||||
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.providerRealmName()));
|
providerUser.setLastName(NEW_LAST_NAME);
|
||||||
|
providerUser.setEmail(NEW_EMAIL);
|
||||||
loginPage.login(USERNAME, USERNAME);
|
providerUserResource.update(providerUser);
|
||||||
WaitUtils.waitForPageToLoad();
|
|
||||||
|
|
||||||
accountUpdateProfilePage.assertCurrent();
|
|
||||||
accountUpdateProfilePage.updateProfile(NEW_FIRST_NAME, NEW_LAST_NAME, NEW_EMAIL);
|
|
||||||
logoutFromRealm(getProviderRoot(), bc.providerRealmName());
|
|
||||||
|
|
||||||
driver.navigate().to(getAccountUrl(getConsumerRoot(), bc.consumerRealmName()));
|
driver.navigate().to(getAccountUrl(getConsumerRoot(), bc.consumerRealmName()));
|
||||||
WaitUtils.waitForPageToLoad();
|
WaitUtils.waitForPageToLoad();
|
||||||
|
|
||||||
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.consumerRealmName()));
|
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.consumerRealmName()));
|
||||||
logInWithIdp(IDP_NAME, USERNAME, USERNAME);
|
logInWithIdp(IDP_NAME, NEW_USERNAME, PASSWORD);
|
||||||
|
|
||||||
accountUpdateProfilePage.assertCurrent();
|
accountUpdateProfilePage.assertCurrent();
|
||||||
|
|
||||||
|
// consumer username stays the same, even when sync mode is force
|
||||||
|
assertThat(accountUpdateProfilePage.getUsername(), Matchers.equalTo(USERNAME));
|
||||||
|
// other consumer attributes are updated, when sync mode is force
|
||||||
assertThat(accountUpdateProfilePage.getEmail(), Matchers.equalTo(isForceSync ? NEW_EMAIL : EMAIL));
|
assertThat(accountUpdateProfilePage.getEmail(), Matchers.equalTo(isForceSync ? NEW_EMAIL : EMAIL));
|
||||||
assertThat(accountUpdateProfilePage.getFirstName(), Matchers.equalTo(isForceSync ? NEW_FIRST_NAME : FIRST_NAME));
|
assertThat(accountUpdateProfilePage.getFirstName(),
|
||||||
assertThat(accountUpdateProfilePage.getLastName(), Matchers.equalTo(isForceSync ? NEW_LAST_NAME : LAST_NAME));
|
Matchers.equalTo(isForceSync ? NEW_FIRST_NAME : FIRST_NAME));
|
||||||
|
assertThat(accountUpdateProfilePage.getLastName(),
|
||||||
|
Matchers.equalTo(isForceSync ? NEW_LAST_NAME : LAST_NAME));
|
||||||
|
|
||||||
|
accountUpdateProfilePage.submitWithoutChanges();
|
||||||
|
assertAccountConsoleIsCurrent();
|
||||||
|
|
||||||
|
checkFederatedIdentityLink(consumerUserResource, providerUserID, isForceSync ? NEW_USERNAME : USERNAME);
|
||||||
} finally {
|
} finally {
|
||||||
providerUserResource.delete(userID);
|
providerUsersResource.delete(providerUserID);
|
||||||
assertThat("User wasn't deleted", providerUserResource.search(USERNAME).size(), Matchers.is(0));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void assertAccountConsoleIsCurrent() {
|
||||||
|
assertThat(driver.getTitle(), Matchers.containsString("Account Management"));
|
||||||
|
}
|
||||||
|
|
||||||
|
private void allowUserEdit(RealmResource realmResource) {
|
||||||
|
RealmRepresentation realm = realmResource.toRepresentation();
|
||||||
|
realm.setEditUsernameAllowed(true);
|
||||||
|
realmResource.update(realm);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void checkFederatedIdentityLink(UserResource userResource, String userID, String username) {
|
||||||
|
List<FederatedIdentityRepresentation> federatedIdentities = userResource.getFederatedIdentity();
|
||||||
|
assertThat(federatedIdentities, Matchers.hasSize(1));
|
||||||
|
FederatedIdentityRepresentation federatedIdentity = federatedIdentities.get(0);
|
||||||
|
assertThat(federatedIdentity.getIdentityProvider(), Matchers.equalTo(IDP_OIDC_ALIAS));
|
||||||
|
assertThat(federatedIdentity.getUserId(), Matchers.equalTo(userID));
|
||||||
|
assertThat(federatedIdentity.getUserName(), Matchers.equalTo(username));
|
||||||
|
}
|
||||||
|
|
||||||
private void updateIdPSyncMode(IdentityProviderRepresentation idProvider, IdentityProviderResource idProviderResource, IdentityProviderSyncMode syncMode) {
|
private void updateIdPSyncMode(IdentityProviderRepresentation idProvider, IdentityProviderResource idProviderResource, IdentityProviderSyncMode syncMode) {
|
||||||
assertThat(idProvider, Matchers.notNullValue());
|
assertThat(idProvider, Matchers.notNullValue());
|
||||||
assertThat(idProviderResource, Matchers.notNullValue());
|
assertThat(idProviderResource, Matchers.notNullValue());
|
||||||
|
@ -536,7 +578,7 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
idProvider.getConfig().put(IdentityProviderModel.SYNC_MODE, syncMode.name());
|
idProvider.getConfig().put(IdentityProviderModel.SYNC_MODE, syncMode.name());
|
||||||
idProviderResource.update(idProvider);
|
idProviderResource.update(idProvider);
|
||||||
|
|
||||||
idProvider = Optional.ofNullable(idProviderResource.toRepresentation()).orElse(null);
|
idProvider = idProviderResource.toRepresentation();
|
||||||
assertThat("Cannot get Identity Provider", idProvider, Matchers.notNullValue());
|
assertThat("Cannot get Identity Provider", idProvider, Matchers.notNullValue());
|
||||||
assertThat("Sync mode didn't change", idProvider.getConfig().get(IdentityProviderModel.SYNC_MODE), Matchers.equalTo(syncMode.name()));
|
assertThat("Sync mode didn't change", idProvider.getConfig().get(IdentityProviderModel.SYNC_MODE), Matchers.equalTo(syncMode.name()));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue