Check email with ignorecase when setting basic attributes in IdP
Closes #31848 Signed-off-by: rmartinc <rmartinc@redhat.com>
This commit is contained in:
parent
3930356c21
commit
a74e60f4d7
2 changed files with 104 additions and 5 deletions
|
@ -1060,14 +1060,14 @@ public class IdentityBrokerService implements IdentityProvider.AuthenticationCal
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setBasicUserAttributes(BrokeredIdentityContext context, UserModel federatedUser) {
|
private void setBasicUserAttributes(BrokeredIdentityContext context, UserModel federatedUser) {
|
||||||
setDiffAttrToConsumer(federatedUser.getEmail(), context.getEmail(), email -> setEmail(context, federatedUser, email));
|
setDiffAttrToConsumer(federatedUser.getEmail(), context.getEmail(), email -> setEmail(context, federatedUser, email), true);
|
||||||
setDiffAttrToConsumer(federatedUser.getFirstName(), context.getFirstName(), federatedUser::setFirstName);
|
setDiffAttrToConsumer(federatedUser.getFirstName(), context.getFirstName(), federatedUser::setFirstName, false);
|
||||||
setDiffAttrToConsumer(federatedUser.getLastName(), context.getLastName(), federatedUser::setLastName);
|
setDiffAttrToConsumer(federatedUser.getLastName(), context.getLastName(), federatedUser::setLastName, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setDiffAttrToConsumer(String actualValue, String newValue, Consumer<String> consumer) {
|
private void setDiffAttrToConsumer(String actualValue, String newValue, Consumer<String> consumer, boolean ignoreCase) {
|
||||||
String actualValueNotNull = Optional.ofNullable(actualValue).orElse("");
|
String actualValueNotNull = Optional.ofNullable(actualValue).orElse("");
|
||||||
if (newValue != null && !newValue.equals(actualValueNotNull)) {
|
if (newValue != null && !(ignoreCase? newValue.equalsIgnoreCase(actualValueNotNull) : newValue.equals(actualValueNotNull))) {
|
||||||
consumer.accept(newValue);
|
consumer.accept(newValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.ClientResource;
|
import org.keycloak.admin.client.resource.ClientResource;
|
||||||
import org.keycloak.admin.client.resource.ClientsResource;
|
import org.keycloak.admin.client.resource.ClientsResource;
|
||||||
|
import org.keycloak.admin.client.resource.ClientScopeResource;
|
||||||
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
import org.keycloak.admin.client.resource.IdentityProviderResource;
|
||||||
import org.keycloak.admin.client.resource.RealmResource;
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.admin.client.resource.UserResource;
|
import org.keycloak.admin.client.resource.UserResource;
|
||||||
|
@ -27,6 +28,7 @@ import org.keycloak.models.utils.TimeBasedOTP;
|
||||||
import org.keycloak.protocol.ProtocolMapperUtils;
|
import org.keycloak.protocol.ProtocolMapperUtils;
|
||||||
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
import org.keycloak.protocol.oidc.OIDCConfigAttributes;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
|
import org.keycloak.protocol.oidc.mappers.HardcodedClaim;
|
||||||
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
import org.keycloak.protocol.oidc.mappers.OIDCAttributeMapperHelper;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
@ -39,6 +41,7 @@ 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;
|
||||||
|
import org.keycloak.testsuite.admin.ApiUtil;
|
||||||
import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
|
import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
|
||||||
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
import org.keycloak.testsuite.updaters.RealmAttributeUpdater;
|
||||||
import org.keycloak.testsuite.util.AccountHelper;
|
import org.keycloak.testsuite.util.AccountHelper;
|
||||||
|
@ -707,6 +710,102 @@ public final class KcOidcBrokerTest extends AbstractAdvancedBrokerTest {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void checkUpdatedEmailAttributeIdPSameValueDifferentCase() throws Exception {
|
||||||
|
final String IDP_NAME = getBrokerConfiguration().getIDPAlias();
|
||||||
|
final String USERNAME = "demo-user";
|
||||||
|
final String PASSWORD = "demo-pwd";
|
||||||
|
|
||||||
|
final String FIRST_NAME = "John";
|
||||||
|
final String LAST_NAME = "Doe";
|
||||||
|
final String EMAIL = "mail@example.com";
|
||||||
|
|
||||||
|
RealmResource providerRealmResource = realmsResouce().realm(bc.providerRealmName());
|
||||||
|
allowUserEdit(providerRealmResource);
|
||||||
|
|
||||||
|
UsersResource providerUsersResource = providerRealmResource.users();
|
||||||
|
|
||||||
|
String providerUserID = createUser(bc.providerRealmName(), USERNAME, PASSWORD, FIRST_NAME, LAST_NAME, EMAIL,
|
||||||
|
user -> user.setEmailVerified(true));
|
||||||
|
|
||||||
|
try {
|
||||||
|
IdentityProviderResource consumerIdentityResource = getIdentityProviderResource();
|
||||||
|
IdentityProviderRepresentation idProvider = consumerIdentityResource.toRepresentation();
|
||||||
|
|
||||||
|
updateIdPSyncMode(idProvider, consumerIdentityResource, IdentityProviderSyncMode.FORCE, false);
|
||||||
|
|
||||||
|
// login to create the user in the consumer realm
|
||||||
|
oauth.clientId("broker-app");
|
||||||
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
|
||||||
|
WaitUtils.waitForPageToLoad();
|
||||||
|
|
||||||
|
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.consumerRealmName()));
|
||||||
|
logInWithIdp(IDP_NAME, USERNAME, PASSWORD);
|
||||||
|
|
||||||
|
UserRepresentation userRepresentation = AccountHelper.getUserRepresentation(adminClient.realm(bc.providerRealmName()), USERNAME);
|
||||||
|
|
||||||
|
assertThat(userRepresentation.getUsername(), Matchers.equalTo(USERNAME));
|
||||||
|
assertThat(userRepresentation.getEmail(), Matchers.equalTo(EMAIL));
|
||||||
|
assertThat(userRepresentation.getFirstName(), Matchers.equalTo(FIRST_NAME));
|
||||||
|
assertThat(userRepresentation.getLastName(), Matchers.equalTo(LAST_NAME));
|
||||||
|
|
||||||
|
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);
|
||||||
|
Assert.assertFalse(consumerUserResource.toRepresentation().isEmailVerified());
|
||||||
|
|
||||||
|
AccountHelper.logout(adminClient.realm(bc.consumerRealmName()), USERNAME);
|
||||||
|
AccountHelper.logout(adminClient.realm(bc.providerRealmName()), USERNAME);
|
||||||
|
|
||||||
|
// set email verified to true on the consumer resource
|
||||||
|
consumerUser = consumerUserResource.toRepresentation();
|
||||||
|
consumerUser.setEmailVerified(true);
|
||||||
|
consumerUserResource.update(consumerUser);
|
||||||
|
Assert.assertTrue(consumerUserResource.toRepresentation().isEmailVerified());
|
||||||
|
|
||||||
|
// Change the client scope for email to set the hardcoded email in capitals
|
||||||
|
ProtocolMapperRepresentation hardcodedEmail = new ProtocolMapperRepresentation();
|
||||||
|
hardcodedEmail.setName("email");
|
||||||
|
hardcodedEmail.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
|
||||||
|
hardcodedEmail.setProtocolMapper(HardcodedClaim.PROVIDER_ID);
|
||||||
|
hardcodedEmail.getConfig().put(OIDCAttributeMapperHelper.TOKEN_CLAIM_NAME, "email");
|
||||||
|
hardcodedEmail.getConfig().put(OIDCAttributeMapperHelper.JSON_TYPE, "String");
|
||||||
|
hardcodedEmail.getConfig().put(OIDCAttributeMapperHelper.INCLUDE_IN_ACCESS_TOKEN, "true");
|
||||||
|
hardcodedEmail.getConfig().put(OIDCAttributeMapperHelper.INCLUDE_IN_ID_TOKEN, "true");
|
||||||
|
hardcodedEmail.getConfig().put(OIDCAttributeMapperHelper.INCLUDE_IN_USERINFO, "true");
|
||||||
|
hardcodedEmail.getConfig().put(HardcodedClaim.CLAIM_VALUE, EMAIL.toUpperCase());
|
||||||
|
ClientScopeResource emailClientScope = ApiUtil.findClientScopeByName(providerRealmResource, "email");
|
||||||
|
ProtocolMapperRepresentation emailMapper = ApiUtil.findProtocolMapperByName(emailClientScope, "email");
|
||||||
|
emailClientScope.getProtocolMappers().delete(emailMapper.getId());
|
||||||
|
emailClientScope.getProtocolMappers().createMapper(hardcodedEmail);
|
||||||
|
|
||||||
|
// login again to force sync
|
||||||
|
oauth.clientId("broker-app");
|
||||||
|
loginPage.open(bc.consumerRealmName());
|
||||||
|
|
||||||
|
WaitUtils.waitForPageToLoad();
|
||||||
|
|
||||||
|
assertThat(driver.getTitle(), Matchers.containsString("Sign in to " + bc.consumerRealmName()));
|
||||||
|
logInWithIdp(IDP_NAME, USERNAME, PASSWORD);
|
||||||
|
assertThat(driver.getCurrentUrl(), Matchers.containsString("/app/auth?"));
|
||||||
|
|
||||||
|
consumerUserResource = consumerRealmResource.users().get(consumerUserID);
|
||||||
|
checkFederatedIdentityLink(consumerUserResource, providerUserID, USERNAME);
|
||||||
|
|
||||||
|
// the email should be verified as it's just a different case
|
||||||
|
Assert.assertTrue(consumerUserResource.toRepresentation().isEmailVerified());
|
||||||
|
} finally {
|
||||||
|
providerUsersResource.delete(providerUserID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void allowUserEdit(RealmResource realmResource) {
|
private void allowUserEdit(RealmResource realmResource) {
|
||||||
RealmRepresentation realm = realmResource.toRepresentation();
|
RealmRepresentation realm = realmResource.toRepresentation();
|
||||||
realm.setEditUsernameAllowed(true);
|
realm.setEditUsernameAllowed(true);
|
||||||
|
|
Loading…
Reference in a new issue