mirror of
https://github.com/keycloak/keycloak.git
synced 2025-12-21 14:30:05 -06:00
Do not show update email link if the email attribute is not writable
Closes #39669 Signed-off-by: Pedro Igor <pigor.craveiro@gmail.com>
This commit is contained in:
@@ -119,11 +119,15 @@ export const PersonalInfo = () => {
|
|||||||
((key: unknown, params) =>
|
((key: unknown, params) =>
|
||||||
t(key as TFuncKey, params as any)) as TFunction
|
t(key as TFuncKey, params as any)) as TFunction
|
||||||
}
|
}
|
||||||
renderer={(attribute) =>
|
renderer={(attribute) => {
|
||||||
attribute.name === "email" &&
|
const annotations = attribute.annotations
|
||||||
updateEmailFeatureEnabled &&
|
? attribute.annotations
|
||||||
updateEmailActionEnabled &&
|
: {};
|
||||||
(!isRegistrationEmailAsUsername || isEditUserNameAllowed) ? (
|
return attribute.name === "email" &&
|
||||||
|
updateEmailFeatureEnabled &&
|
||||||
|
updateEmailActionEnabled &&
|
||||||
|
annotations["kc.required.action.supported"] &&
|
||||||
|
(!isRegistrationEmailAsUsername || isEditUserNameAllowed) ? (
|
||||||
<Button
|
<Button
|
||||||
id="update-email-btn"
|
id="update-email-btn"
|
||||||
variant="link"
|
variant="link"
|
||||||
@@ -135,8 +139,8 @@ export const PersonalInfo = () => {
|
|||||||
>
|
>
|
||||||
{t("updateEmail")}
|
{t("updateEmail")}
|
||||||
</Button>
|
</Button>
|
||||||
) : undefined
|
) : undefined;
|
||||||
}
|
}}
|
||||||
/>
|
/>
|
||||||
{!allFieldsReadOnly() && (
|
{!allFieldsReadOnly() && (
|
||||||
<ActionGroup>
|
<ActionGroup>
|
||||||
|
|||||||
@@ -567,6 +567,19 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
|
|||||||
return unmanagedAttributes;
|
return unmanagedAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Map<String, Object> getAnnotations(String name) {
|
||||||
|
AttributeMetadata metadata = getMetadata(name);
|
||||||
|
|
||||||
|
if (metadata == null) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
AttributeContext context = createAttributeContext(metadata);
|
||||||
|
|
||||||
|
return metadata.getAnnotations(context);
|
||||||
|
}
|
||||||
|
|
||||||
protected AttributeMetadata createUnmanagedAttributeMetadata(String name) {
|
protected AttributeMetadata createUnmanagedAttributeMetadata(String name) {
|
||||||
return new AttributeMetadata(name, Integer.MAX_VALUE) {
|
return new AttributeMetadata(name, Integer.MAX_VALUE) {
|
||||||
final UnmanagedAttributePolicy unmanagedAttributePolicy = upConfig.getUnmanagedAttributePolicy();
|
final UnmanagedAttributePolicy unmanagedAttributePolicy = upConfig.getUnmanagedAttributePolicy();
|
||||||
|
|||||||
@@ -155,12 +155,14 @@ public class UserProfileUtil {
|
|||||||
group = am.getAttributeGroupMetadata().getName();
|
group = am.getAttributeGroupMetadata().getName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Attributes attributes = profile.getAttributes();
|
||||||
|
|
||||||
return new UserProfileAttributeMetadata(am.getName(),
|
return new UserProfileAttributeMetadata(am.getName(),
|
||||||
am.getAttributeDisplayName(),
|
am.getAttributeDisplayName(),
|
||||||
profile.getAttributes().isRequired(am.getName()),
|
attributes.isRequired(am.getName()),
|
||||||
profile.getAttributes().isReadOnly(am.getName()),
|
attributes.isReadOnly(am.getName()),
|
||||||
group,
|
group,
|
||||||
am.getAnnotations(),
|
attributes.getAnnotations(am.getName()),
|
||||||
toValidatorMetadata(am, session),
|
toValidatorMetadata(am, session),
|
||||||
am.isMultivalued());
|
am.isMultivalued());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -52,7 +53,7 @@ public class AttributeMetadata {
|
|||||||
private Map<String, Object> annotations;
|
private Map<String, Object> annotations;
|
||||||
private int guiOrder;
|
private int guiOrder;
|
||||||
private boolean multivalued;
|
private boolean multivalued;
|
||||||
|
private Function<AttributeContext, Map<String, Object>> annotationDecorator = (c) -> c.getMetadata().getAnnotations();
|
||||||
|
|
||||||
AttributeMetadata(String attributeName, int guiOrder) {
|
AttributeMetadata(String attributeName, int guiOrder) {
|
||||||
this(attributeName, guiOrder, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE);
|
this(attributeName, guiOrder, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE, ALWAYS_TRUE);
|
||||||
@@ -225,6 +226,7 @@ public class AttributeMetadata {
|
|||||||
cloned.setAttributeGroupMetadata(attributeGroupMetadata.clone());
|
cloned.setAttributeGroupMetadata(attributeGroupMetadata.clone());
|
||||||
}
|
}
|
||||||
cloned.setMultivalued(multivalued);
|
cloned.setMultivalued(multivalued);
|
||||||
|
cloned.setAnnotationDecorator(annotationDecorator);
|
||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -270,4 +272,13 @@ public class AttributeMetadata {
|
|||||||
this.validators = validators;
|
this.validators = validators;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Map<String, Object> getAnnotations(AttributeContext context) {
|
||||||
|
return annotationDecorator.apply(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
public AttributeMetadata setAnnotationDecorator(Function<AttributeContext, Map<String, Object>> annotationDecorator) {
|
||||||
|
this.annotationDecorator = annotationDecorator;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ import java.util.List;
|
|||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
import org.keycloak.validate.ValidationError;
|
import org.keycloak.validate.ValidationError;
|
||||||
|
|
||||||
@@ -168,4 +169,24 @@ public interface Attributes {
|
|||||||
* @return a map with any unmanaged attribute
|
* @return a map with any unmanaged attribute
|
||||||
*/
|
*/
|
||||||
Map<String, List<String>> getUnmanagedAttributes();
|
Map<String, List<String>> getUnmanagedAttributes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* <p>Returns the annotations for an attribute with the given {@code name}.
|
||||||
|
*
|
||||||
|
* <p>The annotations returned by this method might differ from those returned directly from
|
||||||
|
* the {@link AttributeMetadata#getAnnotations()} if the implementation supports annotations
|
||||||
|
* being resolved dynamically based on contextual data. See {@link AttributeMetadata#setAnnotationDecorator(Function)}.
|
||||||
|
*
|
||||||
|
* @param name the name of the attribute
|
||||||
|
* @return the annotations
|
||||||
|
*/
|
||||||
|
default Map<String, Object> getAnnotations(String name) {
|
||||||
|
AttributeMetadata metadata = getMetadata(name);
|
||||||
|
|
||||||
|
if (metadata == null) {
|
||||||
|
return Collections.emptyMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
return metadata.getAnnotations();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
@@ -42,13 +43,14 @@ import org.keycloak.component.ComponentValidationException;
|
|||||||
import org.keycloak.models.KeycloakContext;
|
import org.keycloak.models.KeycloakContext;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.OrganizationModel;
|
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.RequiredActionProviderModel;
|
import org.keycloak.models.RequiredActionProviderModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.organization.validator.OrganizationMemberValidator;
|
import org.keycloak.organization.validator.OrganizationMemberValidator;
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.provider.ProviderConfigurationBuilder;
|
import org.keycloak.provider.ProviderConfigurationBuilder;
|
||||||
|
import org.keycloak.representations.userprofile.config.UPAttribute;
|
||||||
|
import org.keycloak.representations.userprofile.config.UPAttributePermissions;
|
||||||
import org.keycloak.representations.userprofile.config.UPConfig;
|
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.userprofile.config.UPConfigUtils;
|
import org.keycloak.userprofile.config.UPConfigUtils;
|
||||||
@@ -57,7 +59,6 @@ import org.keycloak.userprofile.validator.BrokeringFederatedUsernameHasValueVali
|
|||||||
import org.keycloak.userprofile.validator.DuplicateEmailValidator;
|
import org.keycloak.userprofile.validator.DuplicateEmailValidator;
|
||||||
import org.keycloak.userprofile.validator.DuplicateUsernameValidator;
|
import org.keycloak.userprofile.validator.DuplicateUsernameValidator;
|
||||||
import org.keycloak.userprofile.validator.EmailExistsAsUsernameValidator;
|
import org.keycloak.userprofile.validator.EmailExistsAsUsernameValidator;
|
||||||
import org.keycloak.userprofile.validator.ImmutableAttributeValidator;
|
|
||||||
import org.keycloak.userprofile.validator.ReadOnlyAttributeUnchangedValidator;
|
import org.keycloak.userprofile.validator.ReadOnlyAttributeUnchangedValidator;
|
||||||
import org.keycloak.userprofile.validator.RegistrationEmailAsUsernameEmailValueValidator;
|
import org.keycloak.userprofile.validator.RegistrationEmailAsUsernameEmailValueValidator;
|
||||||
import org.keycloak.userprofile.validator.RegistrationEmailAsUsernameUsernameValueValidator;
|
import org.keycloak.userprofile.validator.RegistrationEmailAsUsernameUsernameValueValidator;
|
||||||
@@ -67,6 +68,7 @@ import org.keycloak.userprofile.validator.UsernameMutationValidator;
|
|||||||
import org.keycloak.validate.ValidatorConfig;
|
import org.keycloak.validate.ValidatorConfig;
|
||||||
import org.keycloak.validate.validators.EmailValidator;
|
import org.keycloak.validate.validators.EmailValidator;
|
||||||
|
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
import static org.keycloak.common.util.ObjectUtil.isBlank;
|
import static org.keycloak.common.util.ObjectUtil.isBlank;
|
||||||
import static org.keycloak.userprofile.DefaultAttributes.READ_ONLY_ATTRIBUTE_KEY;
|
import static org.keycloak.userprofile.DefaultAttributes.READ_ONLY_ATTRIBUTE_KEY;
|
||||||
import static org.keycloak.userprofile.UserProfileContext.ACCOUNT;
|
import static org.keycloak.userprofile.UserProfileContext.ACCOUNT;
|
||||||
@@ -412,7 +414,8 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
|
|||||||
new AttributeValidatorMetadata(DuplicateEmailValidator.ID),
|
new AttributeValidatorMetadata(DuplicateEmailValidator.ID),
|
||||||
new AttributeValidatorMetadata(EmailExistsAsUsernameValidator.ID),
|
new AttributeValidatorMetadata(EmailExistsAsUsernameValidator.ID),
|
||||||
new AttributeValidatorMetadata(EmailValidator.ID, ValidatorConfig.builder().config(EmailValidator.IGNORE_EMPTY_VALUE, true).build()))
|
new AttributeValidatorMetadata(EmailValidator.ID, ValidatorConfig.builder().config(EmailValidator.IGNORE_EMPTY_VALUE, true).build()))
|
||||||
.setAttributeDisplayName("${email}");
|
.setAttributeDisplayName("${email}")
|
||||||
|
.setAnnotationDecorator(DeclarativeUserProfileProviderFactory::getEmailAnnotationDecorator);
|
||||||
|
|
||||||
List<AttributeValidatorMetadata> readonlyValidators = new ArrayList<>();
|
List<AttributeValidatorMetadata> readonlyValidators = new ArrayList<>();
|
||||||
|
|
||||||
@@ -485,7 +488,7 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
|
|||||||
// The user-defined configuration is always parsed during init and should be avoided as much as possible
|
// The user-defined configuration is always parsed during init and should be avoided as much as possible
|
||||||
// If no user-defined configuration is set, the system default configuration must have been set
|
// If no user-defined configuration is set, the system default configuration must have been set
|
||||||
// In Quarkus, the system default configuration is set at build time for optimization purposes
|
// In Quarkus, the system default configuration is set at build time for optimization purposes
|
||||||
UPConfig defaultConfig = Optional.ofNullable(config.get("configFile"))
|
UPConfig defaultConfig = ofNullable(config.get("configFile"))
|
||||||
.map(Paths::get)
|
.map(Paths::get)
|
||||||
.map(UPConfigUtils::parseConfig)
|
.map(UPConfigUtils::parseConfig)
|
||||||
.orElse(PARSED_DEFAULT_RAW_CONFIG);
|
.orElse(PARSED_DEFAULT_RAW_CONFIG);
|
||||||
@@ -498,4 +501,36 @@ public class DeclarativeUserProfileProviderFactory implements UserProfileProvide
|
|||||||
PARSED_DEFAULT_RAW_CONFIG = null;
|
PARSED_DEFAULT_RAW_CONFIG = null;
|
||||||
setDefaultConfig(defaultConfig);
|
setDefaultConfig(defaultConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static Map<String, Object> getEmailAnnotationDecorator(AttributeContext c) {
|
||||||
|
AttributeMetadata m = c.getMetadata();
|
||||||
|
Map<String, Object> rawAnnotations = Optional.ofNullable(m.getAnnotations()).orElse(Map.of());
|
||||||
|
|
||||||
|
if (Profile.isFeatureEnabled(Feature.UPDATE_EMAIL)) {
|
||||||
|
UserProfileProvider provider = c.getSession().getProvider(UserProfileProvider.class);
|
||||||
|
UPConfig upConfig = provider.getConfiguration();
|
||||||
|
UPAttribute attribute = upConfig.getAttribute(UserModel.EMAIL);
|
||||||
|
UPAttributePermissions permissions = attribute.getPermissions();
|
||||||
|
|
||||||
|
if (permissions == null) {
|
||||||
|
return rawAnnotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
Set<String> writePermissions = permissions.getEdit();
|
||||||
|
boolean isWritable = writePermissions.contains(UPConfigUtils.ROLE_USER);
|
||||||
|
RealmModel realm = c.getSession().getContext().getRealm();
|
||||||
|
|
||||||
|
if ((realm.isRegistrationEmailAsUsername() && !realm.isEditUsernameAllowed()) || !isWritable) {
|
||||||
|
return rawAnnotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
Map<String, Object> annotations = new HashMap<>(rawAnnotations);
|
||||||
|
|
||||||
|
annotations.put("kc.required.action.supported", isWritable);
|
||||||
|
|
||||||
|
return annotations;
|
||||||
|
}
|
||||||
|
|
||||||
|
return rawAnnotations;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.keycloak.testsuite.account;
|
package org.keycloak.testsuite.account;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
|
import static org.hamcrest.Matchers.nullValue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -25,6 +28,8 @@ import static org.keycloak.testsuite.account.AccountRestServiceTest.getUserProfi
|
|||||||
import static org.keycloak.testsuite.util.userprofile.UserProfileUtil.PERMISSIONS_ALL;
|
import static org.keycloak.testsuite.util.userprofile.UserProfileUtil.PERMISSIONS_ALL;
|
||||||
import static org.keycloak.testsuite.util.userprofile.UserProfileUtil.PERMISSIONS_ADMIN_EDITABLE;
|
import static org.keycloak.testsuite.util.userprofile.UserProfileUtil.PERMISSIONS_ADMIN_EDITABLE;
|
||||||
import static org.keycloak.testsuite.util.userprofile.UserProfileUtil.PERMISSIONS_ADMIN_ONLY;
|
import static org.keycloak.testsuite.util.userprofile.UserProfileUtil.PERMISSIONS_ADMIN_ONLY;
|
||||||
|
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_ADMIN;
|
||||||
|
import static org.keycloak.userprofile.config.UPConfigUtils.ROLE_USER;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
@@ -32,10 +37,13 @@ import java.util.HashMap;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
import org.keycloak.admin.client.resource.RealmResource;
|
||||||
import org.keycloak.broker.provider.util.SimpleHttp;
|
import org.keycloak.broker.provider.util.SimpleHttp;
|
||||||
|
import org.keycloak.common.Profile;
|
||||||
import org.keycloak.events.Details;
|
import org.keycloak.events.Details;
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
@@ -43,6 +51,10 @@ import org.keycloak.representations.idm.UserProfileAttributeMetadata;
|
|||||||
import org.keycloak.representations.idm.UserProfileMetadata;
|
import org.keycloak.representations.idm.UserProfileMetadata;
|
||||||
import org.keycloak.representations.account.UserRepresentation;
|
import org.keycloak.representations.account.UserRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
import org.keycloak.representations.userprofile.config.UPAttribute;
|
||||||
|
import org.keycloak.representations.userprofile.config.UPAttributePermissions;
|
||||||
|
import org.keycloak.representations.userprofile.config.UPConfig;
|
||||||
|
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
||||||
import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
|
import org.keycloak.testsuite.broker.util.SimpleHttpDefault;
|
||||||
import org.keycloak.testsuite.util.userprofile.UserProfileUtil;
|
import org.keycloak.testsuite.util.userprofile.UserProfileUtil;
|
||||||
import org.keycloak.userprofile.UserProfileContext;
|
import org.keycloak.userprofile.UserProfileContext;
|
||||||
@@ -158,6 +170,33 @@ public class AccountRestServiceWithUserProfileTest extends AbstractRestServiceTe
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EnableFeature(value = Profile.Feature.UPDATE_EMAIL, skipRestart = true)
|
||||||
|
@Test
|
||||||
|
public void testUpdateEmailLink() throws Exception {
|
||||||
|
RealmResource realm = adminClient.realm("test");
|
||||||
|
RealmRepresentation realmRep = realm.toRepresentation();
|
||||||
|
|
||||||
|
try {
|
||||||
|
realmRep.setEditUsernameAllowed(false);
|
||||||
|
realm.update(realmRep);
|
||||||
|
|
||||||
|
UserRepresentation user = getUser();
|
||||||
|
assertNotNull(user.getUserProfileMetadata());
|
||||||
|
assertThat(user.getUserProfileMetadata().getAttributeMetadata(UserModel.EMAIL).getAnnotations().get("kc.required.action.supported"), is(true));
|
||||||
|
|
||||||
|
UPConfig upConfig = realm.users().userProfile().getConfiguration();
|
||||||
|
UPAttribute attribute = upConfig.getAttribute(UserModel.EMAIL);
|
||||||
|
attribute.setPermissions(new UPAttributePermissions(Set.of(ROLE_USER), Set.of(ROLE_ADMIN)));
|
||||||
|
realm.users().userProfile().update(upConfig);
|
||||||
|
user = getUser();
|
||||||
|
assertNotNull(user.getUserProfileMetadata());
|
||||||
|
assertThat(user.getUserProfileMetadata().getAttributeMetadata(UserModel.EMAIL).getAnnotations().get("kc.required.action.supported"), is(nullValue()));
|
||||||
|
} finally {
|
||||||
|
realmRep.setEditUsernameAllowed(true);
|
||||||
|
realm.update(realmRep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testGetUserProfileMetadata_RoAccessToNameFields() throws IOException {
|
public void testGetUserProfileMetadata_RoAccessToNameFields() throws IOException {
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,10 @@
|
|||||||
|
|
||||||
package org.keycloak.testsuite.user.profile;
|
package org.keycloak.testsuite.user.profile;
|
||||||
|
|
||||||
|
import static java.util.Optional.ofNullable;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
import static org.hamcrest.Matchers.containsInAnyOrder;
|
import static org.hamcrest.Matchers.containsInAnyOrder;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
import static org.junit.Assert.assertNotNull;
|
import static org.junit.Assert.assertNotNull;
|
||||||
@@ -2311,6 +2313,77 @@ public class UserProfileTest extends AbstractUserProfileTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@EnableFeature(Feature.UPDATE_EMAIL)
|
||||||
|
@Test
|
||||||
|
public void testEmailAnnotationsInAccountContext() {
|
||||||
|
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testEmailAnnotationsInAccountContext);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void testEmailAnnotationsInAccountContext(KeycloakSession session) {
|
||||||
|
UserProfileProvider provider = getUserProfileProvider(session);
|
||||||
|
String userName = org.keycloak.models.utils.KeycloakModelUtils.generateId();
|
||||||
|
Map<String, String> attributes = new HashMap<>();
|
||||||
|
|
||||||
|
attributes.put(UserModel.USERNAME, userName);
|
||||||
|
String originalEmail = userName + "@keycloak.org";
|
||||||
|
attributes.put(UserModel.EMAIL, originalEmail);
|
||||||
|
attributes.put(UserModel.FIRST_NAME, "Joe");
|
||||||
|
attributes.put(UserModel.LAST_NAME, "Doe");
|
||||||
|
attributes.put("address", "some address");
|
||||||
|
|
||||||
|
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
|
||||||
|
UserModel user = profile.create();
|
||||||
|
RealmModel realm = session.getContext().getRealm();
|
||||||
|
|
||||||
|
try {
|
||||||
|
realm.setEditUsernameAllowed(false);
|
||||||
|
realm.setRegistrationEmailAsUsername(true);
|
||||||
|
profile = provider.create(UserProfileContext.ACCOUNT, attributes, user);
|
||||||
|
assertFalse(ofNullable(profile.getAttributes().getAnnotations(UserModel.EMAIL)).orElse(Map.of()).containsKey("kc.required.action.supported"));
|
||||||
|
} finally {
|
||||||
|
realm.setEditUsernameAllowed(true);
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
realm.setEditUsernameAllowed(true);
|
||||||
|
realm.setRegistrationEmailAsUsername(true);
|
||||||
|
profile = provider.create(UserProfileContext.ACCOUNT, attributes, user);
|
||||||
|
assertThat(ofNullable(profile.getAttributes().getAnnotations(UserModel.EMAIL)).orElse(Map.of()).get("kc.required.action.supported"), is(true));
|
||||||
|
} finally {
|
||||||
|
realm.setEditUsernameAllowed(true);
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
realm.setEditUsernameAllowed(false);
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
UPConfig upConfig = provider.getConfiguration();
|
||||||
|
UPAttribute attribute = upConfig.getAttribute(UserModel.EMAIL);
|
||||||
|
attribute.setPermissions(new UPAttributePermissions(Set.of(ROLE_USER), Set.of(ROLE_ADMIN)));
|
||||||
|
provider.setConfiguration(upConfig);
|
||||||
|
profile = provider.create(UserProfileContext.ACCOUNT, attributes, user);
|
||||||
|
assertFalse(ofNullable(profile.getAttributes().getAnnotations(UserModel.EMAIL)).orElse(Map.of()).containsKey("kc.required.action.supported"));
|
||||||
|
} finally {
|
||||||
|
realm.setEditUsernameAllowed(true);
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
realm.setEditUsernameAllowed(false);
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
UPConfig upConfig = provider.getConfiguration();
|
||||||
|
UPAttribute attribute = upConfig.getAttribute(UserModel.EMAIL);
|
||||||
|
attribute.setPermissions(new UPAttributePermissions(Set.of(ROLE_USER), Set.of(ROLE_ADMIN, ROLE_USER)));
|
||||||
|
provider.setConfiguration(upConfig);
|
||||||
|
profile = provider.create(UserProfileContext.ACCOUNT, attributes, user);
|
||||||
|
assertThat(ofNullable(profile.getAttributes().getAnnotations(UserModel.EMAIL)).orElse(Map.of()).get("kc.required.action.supported"), is(true));
|
||||||
|
} finally {
|
||||||
|
realm.setEditUsernameAllowed(true);
|
||||||
|
realm.setRegistrationEmailAsUsername(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testMultivalued() {
|
public void testMultivalued() {
|
||||||
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testMultivalued);
|
getTestingClient().server(TEST_REALM_NAME).run((RunOnServer) UserProfileTest::testMultivalued);
|
||||||
|
|||||||
Reference in New Issue
Block a user