[KEYCLOAK-18427] - Allowing switching to declarative provider
This commit is contained in:
parent
512bcd14f7
commit
948f453e2d
27 changed files with 247 additions and 252 deletions
|
@ -61,8 +61,7 @@ public class Profile {
|
||||||
WEB_AUTHN(Type.DEFAULT, Type.PREVIEW),
|
WEB_AUTHN(Type.DEFAULT, Type.PREVIEW),
|
||||||
CLIENT_POLICIES(Type.DEFAULT),
|
CLIENT_POLICIES(Type.DEFAULT),
|
||||||
CIBA(Type.PREVIEW),
|
CIBA(Type.PREVIEW),
|
||||||
MAP_STORAGE(Type.EXPERIMENTAL),
|
MAP_STORAGE(Type.EXPERIMENTAL);
|
||||||
DECLARATIVE_USER_PROFILE(Type.PREVIEW);
|
|
||||||
|
|
||||||
private final Type typeProject;
|
private final Type typeProject;
|
||||||
private final Type typeProduct;
|
private final Type typeProduct;
|
||||||
|
|
|
@ -21,8 +21,8 @@ public class ProfileTest {
|
||||||
@Test
|
@Test
|
||||||
public void checkDefaultsKeycloak() {
|
public void checkDefaultsKeycloak() {
|
||||||
Assert.assertEquals("community", Profile.getName());
|
Assert.assertEquals("community", Profile.getName());
|
||||||
assertEquals(Profile.getDisabledFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.DOCKER, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.UPLOAD_SCRIPTS, Profile.Feature.CIBA, Profile.Feature.MAP_STORAGE, Profile.Feature.DECLARATIVE_USER_PROFILE);
|
assertEquals(Profile.getDisabledFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.DOCKER, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.UPLOAD_SCRIPTS, Profile.Feature.CIBA, Profile.Feature.MAP_STORAGE);
|
||||||
assertEquals(Profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.CIBA, Profile.Feature.DECLARATIVE_USER_PROFILE);
|
assertEquals(Profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.CIBA);
|
||||||
assertEquals(Profile.getDeprecatedFeatures(), Profile.Feature.UPLOAD_SCRIPTS);
|
assertEquals(Profile.getDeprecatedFeatures(), Profile.Feature.UPLOAD_SCRIPTS);
|
||||||
|
|
||||||
Assert.assertTrue(Profile.Feature.WEB_AUTHN.hasDifferentProductType());
|
Assert.assertTrue(Profile.Feature.WEB_AUTHN.hasDifferentProductType());
|
||||||
|
@ -37,8 +37,8 @@ public class ProfileTest {
|
||||||
Profile.init();
|
Profile.init();
|
||||||
|
|
||||||
Assert.assertEquals("product", Profile.getName());
|
Assert.assertEquals("product", Profile.getName());
|
||||||
assertEquals(Profile.getDisabledFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.DOCKER, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.UPLOAD_SCRIPTS, Profile.Feature.WEB_AUTHN, Profile.Feature.CIBA, Profile.Feature.MAP_STORAGE, Profile.Feature.DECLARATIVE_USER_PROFILE);
|
assertEquals(Profile.getDisabledFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.DOCKER, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.UPLOAD_SCRIPTS, Profile.Feature.WEB_AUTHN, Profile.Feature.CIBA, Profile.Feature.MAP_STORAGE);
|
||||||
assertEquals(Profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.WEB_AUTHN, Profile.Feature.CIBA, Profile.Feature.DECLARATIVE_USER_PROFILE);
|
assertEquals(Profile.getPreviewFeatures(), Profile.Feature.ADMIN_FINE_GRAINED_AUTHZ, Profile.Feature.SCRIPTS, Profile.Feature.TOKEN_EXCHANGE, Profile.Feature.OPENSHIFT_INTEGRATION, Profile.Feature.WEB_AUTHN, Profile.Feature.CIBA);
|
||||||
assertEquals(Profile.getDeprecatedFeatures(), Profile.Feature.UPLOAD_SCRIPTS);
|
assertEquals(Profile.getDeprecatedFeatures(), Profile.Feature.UPLOAD_SCRIPTS);
|
||||||
|
|
||||||
Assert.assertTrue(Profile.Feature.WEB_AUTHN.hasDifferentProductType());
|
Assert.assertTrue(Profile.Feature.WEB_AUTHN.hasDifferentProductType());
|
||||||
|
|
|
@ -138,6 +138,7 @@ import org.keycloak.representations.idm.authorization.ScopeRepresentation;
|
||||||
import org.keycloak.storage.UserStorageProvider;
|
import org.keycloak.storage.UserStorageProvider;
|
||||||
import org.keycloak.storage.UserStorageProviderModel;
|
import org.keycloak.storage.UserStorageProviderModel;
|
||||||
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
import org.keycloak.storage.federated.UserFederatedStorageProvider;
|
||||||
|
import org.keycloak.userprofile.UserProfileProvider;
|
||||||
import org.keycloak.util.JsonSerialization;
|
import org.keycloak.util.JsonSerialization;
|
||||||
import org.keycloak.validation.ValidationUtil;
|
import org.keycloak.validation.ValidationUtil;
|
||||||
|
|
||||||
|
@ -1077,6 +1078,11 @@ public class RepresentationToModel {
|
||||||
renameRealm(realm, rep.getRealm());
|
renameRealm(realm, rep.getRealm());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Boolean.parseBoolean(rep.getAttributesOrEmpty().get("userProfileEnabled"))) {
|
||||||
|
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
|
||||||
|
provider.setConfiguration(null);
|
||||||
|
}
|
||||||
|
|
||||||
// Import attributes first, so the stuff saved directly on representation (displayName, bruteForce etc) has bigger priority
|
// Import attributes first, so the stuff saved directly on representation (displayName, bruteForce etc) has bigger priority
|
||||||
if (rep.getAttributes() != null) {
|
if (rep.getAttributes() != null) {
|
||||||
Set<String> attrsToRemove = new HashSet<>(realm.getAttributes().keySet());
|
Set<String> attrsToRemove = new HashSet<>(realm.getAttributes().keySet());
|
||||||
|
|
|
@ -275,11 +275,8 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
|
||||||
List<String> values = EMPTY_VALUE;
|
List<String> values = EMPTY_VALUE;
|
||||||
AttributeMetadata metadata = metadataByAttribute.get(attributeName);
|
AttributeMetadata metadata = metadataByAttribute.get(attributeName);
|
||||||
|
|
||||||
// if the attribute is not provided and does not have view permission, use the current values
|
if (user != null && isIncludeAttributeIfNotProvided(metadata)) {
|
||||||
// this check makes possible to decide whether or not validation should happen for read-only attributes
|
values = user.getAttributes().getOrDefault(attributeName, EMPTY_VALUE);
|
||||||
// when the context does not have access to such attributes
|
|
||||||
if (user != null && !metadata.canView(createAttributeContext(metadata))) {
|
|
||||||
values = user.getAttributes().get(attributeName);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
newAttributes.put(attributeName, values);
|
newAttributes.put(attributeName, values);
|
||||||
|
@ -302,6 +299,11 @@ public class DefaultAttributes extends HashMap<String, List<String>> implements
|
||||||
return newAttributes;
|
return newAttributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected boolean isIncludeAttributeIfNotProvided(AttributeMetadata metadata) {
|
||||||
|
// user api expects that attributes are not updated if not provided when in legacy mode
|
||||||
|
return UserProfileContext.USER_API.equals(context);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>Checks whether an attribute is support by the profile configuration and the current context.
|
* <p>Checks whether an attribute is support by the profile configuration and the current context.
|
||||||
*
|
*
|
||||||
|
|
|
@ -286,10 +286,14 @@ public class UserResource {
|
||||||
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
|
UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
|
||||||
UserProfile profile = provider.create(USER_API, user);
|
UserProfile profile = provider.create(USER_API, user);
|
||||||
|
|
||||||
Map<String, List<String>> attributes = profile.getAttributes().getReadable(false);
|
if (rep.getAttributes() != null) {
|
||||||
|
Map<String, List<String>> allowedAttributes = profile.getAttributes().getReadable(false);
|
||||||
|
|
||||||
if (!attributes.isEmpty()) {
|
for (String attributeName : rep.getAttributes().keySet()) {
|
||||||
rep.setAttributes(attributes);
|
if (!allowedAttributes.containsKey(attributeName)) {
|
||||||
|
rep.getAttributes().remove(attributeName);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return rep;
|
return rep;
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.userprofile.legacy;
|
package org.keycloak.userprofile;
|
||||||
|
|
||||||
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;
|
||||||
|
@ -44,16 +44,6 @@ import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.userprofile.AttributeContext;
|
|
||||||
import org.keycloak.userprofile.AttributeValidatorMetadata;
|
|
||||||
import org.keycloak.userprofile.Attributes;
|
|
||||||
import org.keycloak.userprofile.DefaultAttributes;
|
|
||||||
import org.keycloak.userprofile.DefaultUserProfile;
|
|
||||||
import org.keycloak.userprofile.UserProfile;
|
|
||||||
import org.keycloak.userprofile.UserProfileContext;
|
|
||||||
import org.keycloak.userprofile.UserProfileMetadata;
|
|
||||||
import org.keycloak.userprofile.UserProfileProvider;
|
|
||||||
import org.keycloak.userprofile.UserProfileProviderFactory;
|
|
||||||
import org.keycloak.userprofile.validator.BlankAttributeValidator;
|
import org.keycloak.userprofile.validator.BlankAttributeValidator;
|
||||||
import org.keycloak.userprofile.validator.BrokeringFederatedUsernameHasValueValidator;
|
import org.keycloak.userprofile.validator.BrokeringFederatedUsernameHasValueValidator;
|
||||||
import org.keycloak.userprofile.validator.DuplicateEmailValidator;
|
import org.keycloak.userprofile.validator.DuplicateEmailValidator;
|
||||||
|
@ -79,7 +69,20 @@ public abstract class AbstractUserProfileProvider<U extends UserProfileProvider>
|
||||||
KeycloakSession session = c.getSession();
|
KeycloakSession session = c.getSession();
|
||||||
KeycloakContext context = session.getContext();
|
KeycloakContext context = session.getContext();
|
||||||
RealmModel realm = context.getRealm();
|
RealmModel realm = context.getRealm();
|
||||||
return ((c.getContext() == REGISTRATION_PROFILE || c.getContext() == IDP_REVIEW) && !realm.isRegistrationEmailAsUsername()) || realm.isEditUsernameAllowed();
|
|
||||||
|
switch (c.getContext()) {
|
||||||
|
case REGISTRATION_PROFILE:
|
||||||
|
case IDP_REVIEW:
|
||||||
|
return !realm.isRegistrationEmailAsUsername();
|
||||||
|
case ACCOUNT_OLD:
|
||||||
|
case ACCOUNT:
|
||||||
|
case UPDATE_PROFILE:
|
||||||
|
return realm.isEditUsernameAllowed();
|
||||||
|
case USER_API:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Pattern getRegexPatternString(String[] builtinReadOnlyAttributes) {
|
public static Pattern getRegexPatternString(String[] builtinReadOnlyAttributes) {
|
|
@ -1,4 +1,4 @@
|
||||||
package org.keycloak.userprofile.config;
|
package org.keycloak.userprofile;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -7,6 +7,7 @@ import java.util.Map;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.userprofile.AttributeMetadata;
|
import org.keycloak.userprofile.AttributeMetadata;
|
||||||
|
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
||||||
import org.keycloak.userprofile.DefaultAttributes;
|
import org.keycloak.userprofile.DefaultAttributes;
|
||||||
import org.keycloak.userprofile.UserProfileContext;
|
import org.keycloak.userprofile.UserProfileContext;
|
||||||
import org.keycloak.userprofile.UserProfileMetadata;
|
import org.keycloak.userprofile.UserProfileMetadata;
|
||||||
|
@ -39,4 +40,9 @@ public class DeclarativeAttributes extends DefaultAttributes {
|
||||||
|
|
||||||
return attributes;
|
return attributes;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean isIncludeAttributeIfNotProvided(AttributeMetadata metadata) {
|
||||||
|
return !metadata.canView(createAttributeContext(metadata));
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -17,7 +17,7 @@
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package org.keycloak.userprofile.config;
|
package org.keycloak.userprofile;
|
||||||
|
|
||||||
import static org.keycloak.common.util.ObjectUtil.isBlank;
|
import static org.keycloak.common.util.ObjectUtil.isBlank;
|
||||||
import static org.keycloak.protocol.oidc.TokenManager.getRequestedClientScopes;
|
import static org.keycloak.protocol.oidc.TokenManager.getRequestedClientScopes;
|
||||||
|
@ -25,8 +25,6 @@ import static org.keycloak.userprofile.config.UPConfigUtils.readConfig;
|
||||||
|
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
|
||||||
import java.nio.charset.Charset;
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
@ -35,33 +33,28 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
|
||||||
import org.keycloak.common.Profile;
|
|
||||||
import org.keycloak.common.util.MultivaluedHashMap;
|
import org.keycloak.common.util.MultivaluedHashMap;
|
||||||
import org.keycloak.common.util.StreamUtil;
|
|
||||||
import org.keycloak.component.AmphibianProviderFactory;
|
import org.keycloak.component.AmphibianProviderFactory;
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.component.ComponentValidationException;
|
import org.keycloak.component.ComponentValidationException;
|
||||||
import org.keycloak.models.ClientModel;
|
import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.ClientScopeModel;
|
|
||||||
import org.keycloak.models.ClientScopeModel.ClientScopeRemovedEvent;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.KeycloakSessionFactory;
|
import org.keycloak.models.KeycloakSessionFactory;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
|
||||||
import org.keycloak.provider.EnvironmentDependentProviderFactory;
|
|
||||||
import org.keycloak.provider.ProviderConfigProperty;
|
import org.keycloak.provider.ProviderConfigProperty;
|
||||||
import org.keycloak.provider.ProviderEvent;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
import org.keycloak.userprofile.AttributeContext;
|
import org.keycloak.userprofile.config.DeclarativeUserProfileModel;
|
||||||
import org.keycloak.userprofile.AttributeMetadata;
|
import org.keycloak.userprofile.config.UPAttribute;
|
||||||
import org.keycloak.userprofile.AttributeValidatorMetadata;
|
import org.keycloak.userprofile.config.UPAttributePermissions;
|
||||||
import org.keycloak.userprofile.Attributes;
|
import org.keycloak.userprofile.config.UPAttributeRequired;
|
||||||
import org.keycloak.userprofile.UserProfileContext;
|
import org.keycloak.userprofile.config.UPAttributeSelector;
|
||||||
import org.keycloak.userprofile.UserProfileMetadata;
|
import org.keycloak.userprofile.config.UPConfig;
|
||||||
import org.keycloak.userprofile.UserProfileProvider;
|
import org.keycloak.userprofile.config.UPConfigUtils;
|
||||||
import org.keycloak.userprofile.legacy.AbstractUserProfileProvider;
|
|
||||||
import org.keycloak.userprofile.validator.AttributeRequiredByMetadataValidator;
|
import org.keycloak.userprofile.validator.AttributeRequiredByMetadataValidator;
|
||||||
|
import org.keycloak.userprofile.validator.BlankAttributeValidator;
|
||||||
import org.keycloak.userprofile.validator.ImmutableAttributeValidator;
|
import org.keycloak.userprofile.validator.ImmutableAttributeValidator;
|
||||||
import org.keycloak.validate.AbstractSimpleValidator;
|
import org.keycloak.validate.AbstractSimpleValidator;
|
||||||
import org.keycloak.validate.ValidatorConfig;
|
import org.keycloak.validate.ValidatorConfig;
|
||||||
|
@ -73,12 +66,12 @@ import org.keycloak.validate.ValidatorConfig;
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
* @author Vlastimil Elias <velias@redhat.com>
|
* @author Vlastimil Elias <velias@redhat.com>
|
||||||
*/
|
*/
|
||||||
public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<DeclarativeUserProfileProvider>
|
public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<UserProfileProvider>
|
||||||
implements AmphibianProviderFactory<DeclarativeUserProfileProvider>, EnvironmentDependentProviderFactory {
|
implements AmphibianProviderFactory<UserProfileProvider> {
|
||||||
|
|
||||||
public static final String SYSTEM_DEFAULT_CONFIG_RESOURCE = "keycloak-default-user-profile.json";
|
|
||||||
public static final String ID = "declarative-user-profile";
|
public static final String ID = "declarative-user-profile";
|
||||||
public static final String UP_PIECES_COUNT_COMPONENT_CONFIG_KEY = "config-pieces-count";
|
public static final String UP_PIECES_COUNT_COMPONENT_CONFIG_KEY = "config-pieces-count";
|
||||||
|
public static final String REALM_USER_PROFILE_ENABLED = "userProfileEnabled";
|
||||||
private static final String PARSED_CONFIG_COMPONENT_KEY = "kc.user.profile.metadata";
|
private static final String PARSED_CONFIG_COMPONENT_KEY = "kc.user.profile.metadata";
|
||||||
private static final String UP_PIECE_COMPONENT_CONFIG_KEY_BASE = "config-piece-";
|
private static final String UP_PIECE_COMPONENT_CONFIG_KEY_BASE = "config-piece-";
|
||||||
|
|
||||||
|
@ -106,7 +99,7 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
private String defaultRawConfig;
|
private String defaultRawConfig;
|
||||||
|
|
||||||
public DeclarativeUserProfileProvider() {
|
public DeclarativeUserProfileProvider() {
|
||||||
// for reflection
|
defaultRawConfig = UPConfigUtils.readDefaultConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeclarativeUserProfileProvider(KeycloakSession session, Map<UserProfileContext, UserProfileMetadata> metadataRegistry, String defaultRawConfig) {
|
public DeclarativeUserProfileProvider(KeycloakSession session, Map<UserProfileContext, UserProfileMetadata> metadataRegistry, String defaultRawConfig) {
|
||||||
|
@ -120,18 +113,33 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected DeclarativeUserProfileProvider create(KeycloakSession session, Map<UserProfileContext, UserProfileMetadata> metadataRegistry) {
|
protected UserProfileProvider create(KeycloakSession session, Map<UserProfileContext, UserProfileMetadata> metadataRegistry) {
|
||||||
return new DeclarativeUserProfileProvider(session, metadataRegistry, defaultRawConfig);
|
return new DeclarativeUserProfileProvider(session, metadataRegistry, defaultRawConfig);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Attributes createAttributes(UserProfileContext context, Map<String, ?> attributes,
|
protected Attributes createAttributes(UserProfileContext context, Map<String, ?> attributes,
|
||||||
UserModel user, UserProfileMetadata metadata) {
|
UserModel user, UserProfileMetadata metadata) {
|
||||||
|
if (!isEnabled(session)) {
|
||||||
|
return new DefaultAttributes(context, attributes, user, metadata, session);
|
||||||
|
}
|
||||||
return new DeclarativeAttributes(context, attributes, user, metadata, session);
|
return new DeclarativeAttributes(context, attributes, user, metadata, session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected UserProfileMetadata configureUserProfile(UserProfileMetadata metadata, KeycloakSession session) {
|
protected UserProfileMetadata configureUserProfile(UserProfileMetadata metadata, KeycloakSession session) {
|
||||||
|
UserProfileContext context = metadata.getContext();
|
||||||
|
UserProfileMetadata decoratedMetadata = metadata.clone();
|
||||||
|
|
||||||
|
if (!isEnabled(session)) {
|
||||||
|
if(!context.equals(UserProfileContext.USER_API) && !context.equals(UserProfileContext.REGISTRATION_USER_CREATION)) {
|
||||||
|
decoratedMetadata.addAttribute(UserModel.FIRST_NAME, new AttributeValidatorMetadata(BlankAttributeValidator.ID, BlankAttributeValidator.createConfig(
|
||||||
|
Messages.MISSING_FIRST_NAME))).setAttributeDisplayName("${firstName}");
|
||||||
|
decoratedMetadata.addAttribute(UserModel.LAST_NAME, new AttributeValidatorMetadata(BlankAttributeValidator.ID, BlankAttributeValidator.createConfig(Messages.MISSING_LAST_NAME))).setAttributeDisplayName("${lastName}");
|
||||||
|
return decoratedMetadata;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ComponentModel model = getComponentModelOrCreate(session);
|
ComponentModel model = getComponentModelOrCreate(session);
|
||||||
Map<UserProfileContext, UserProfileMetadata> metadataMap = model.getNote(PARSED_CONFIG_COMPONENT_KEY);
|
Map<UserProfileContext, UserProfileMetadata> metadataMap = model.getNote(PARSED_CONFIG_COMPONENT_KEY);
|
||||||
|
|
||||||
|
@ -141,7 +149,7 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
model.setNote(PARSED_CONFIG_COMPONENT_KEY, metadataMap);
|
model.setNote(PARSED_CONFIG_COMPONENT_KEY, metadataMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
return metadataMap.computeIfAbsent(metadata.getContext(), (context) -> decorateUserProfileForCache(metadata, model));
|
return metadataMap.computeIfAbsent(context, (c) -> decorateUserProfileForCache(decoratedMetadata, model));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -175,6 +183,10 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getConfiguration() {
|
public String getConfiguration() {
|
||||||
|
if (!isEnabled(session)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
String cfg = getConfigJsonFromComponentModel(getComponentModel());
|
String cfg = getConfigJsonFromComponentModel(getComponentModel());
|
||||||
|
|
||||||
if (isBlank(cfg)) {
|
if (isBlank(cfg)) {
|
||||||
|
@ -190,6 +202,8 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
|
|
||||||
removeConfigJsonFromComponentModel(component);
|
removeConfigJsonFromComponentModel(component);
|
||||||
|
|
||||||
|
RealmModel realm = session.getContext().getRealm();
|
||||||
|
|
||||||
if (!isBlank(configuration)) {
|
if (!isBlank(configuration)) {
|
||||||
// store new parts
|
// store new parts
|
||||||
List<String> parts = UPConfigUtils.getChunks(configuration, 3800);
|
List<String> parts = UPConfigUtils.getChunks(configuration, 3800);
|
||||||
|
@ -202,19 +216,15 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
for (String part : parts) {
|
for (String part : parts) {
|
||||||
config.putSingle(UP_PIECE_COMPONENT_CONFIG_KEY_BASE + (i++), part);
|
config.putSingle(UP_PIECE_COMPONENT_CONFIG_KEY_BASE + (i++), part);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
session.getContext().getRealm().updateComponent(component);
|
realm.updateComponent(component);
|
||||||
|
} else {
|
||||||
|
realm.removeComponent(component);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void postInit(KeycloakSessionFactory factory) {
|
public void postInit(KeycloakSessionFactory factory) {
|
||||||
// TODO: We should avoid blocking operations during startup. Need to review this.
|
|
||||||
try (InputStream is = getClass().getResourceAsStream(SYSTEM_DEFAULT_CONFIG_RESOURCE)) {
|
|
||||||
defaultRawConfig = StreamUtil.readString(is, Charset.defaultCharset());
|
|
||||||
} catch (IOException cause) {
|
|
||||||
throw new RuntimeException("Failed to load default user profile config file", cause);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -231,23 +241,19 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
* This method is called for each {@link UserProfileContext} in each realm, and metadata are cached then and this
|
* This method is called for each {@link UserProfileContext} in each realm, and metadata are cached then and this
|
||||||
* method is called again only if configuration changes.
|
* method is called again only if configuration changes.
|
||||||
*
|
*
|
||||||
* @param metadata base to be decorated based on configuration loaded from component model
|
* @param decoratedMetadata base to be decorated based on configuration loaded from component model
|
||||||
* @param model component model to get "per realm" configuration from
|
* @param model component model to get "per realm" configuration from
|
||||||
* @return decorated metadata
|
* @return decorated metadata
|
||||||
*/
|
*/
|
||||||
protected UserProfileMetadata decorateUserProfileForCache(UserProfileMetadata metadata, ComponentModel model) {
|
protected UserProfileMetadata decorateUserProfileForCache(UserProfileMetadata decoratedMetadata, ComponentModel model) {
|
||||||
UserProfileContext context = metadata.getContext();
|
UserProfileContext context = decoratedMetadata.getContext();
|
||||||
UPConfig parsedConfig = getParsedConfig(model);
|
UPConfig parsedConfig = getParsedConfig(model);
|
||||||
|
|
||||||
// do not change config for REGISTRATION_USER_CREATION context, everything important is covered thanks to REGISTRATION_PROFILE
|
// do not change config for REGISTRATION_USER_CREATION context, everything important is covered thanks to REGISTRATION_PROFILE
|
||||||
if (parsedConfig == null || context == UserProfileContext.REGISTRATION_USER_CREATION) {
|
if (parsedConfig == null || context == UserProfileContext.REGISTRATION_USER_CREATION) {
|
||||||
return metadata;
|
return decoratedMetadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
// need to clone otherwise changes to profile config are going to be reflected
|
|
||||||
// in the default config
|
|
||||||
UserProfileMetadata decoratedMetadata = metadata.clone();
|
|
||||||
|
|
||||||
for (UPAttribute attrConfig : parsedConfig.getAttributes()) {
|
for (UPAttribute attrConfig : parsedConfig.getAttributes()) {
|
||||||
String attributeName = attrConfig.getName();
|
String attributeName = attrConfig.getName();
|
||||||
List<AttributeValidatorMetadata> validators = new ArrayList<>();
|
List<AttributeValidatorMetadata> validators = new ArrayList<>();
|
||||||
|
@ -425,8 +431,14 @@ public class DeclarativeUserProfileProvider extends AbstractUserProfileProvider<
|
||||||
model.getConfig().remove(UP_PIECES_COUNT_COMPONENT_CONFIG_KEY);
|
model.getConfig().remove(UP_PIECES_COUNT_COMPONENT_CONFIG_KEY);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
/**
|
||||||
public boolean isSupported() {
|
* Returns whether the declarative provider is enabled to a realm
|
||||||
return Profile.isFeatureEnabled(Profile.Feature.DECLARATIVE_USER_PROFILE);
|
*
|
||||||
|
* @deprecated should be removed once {@link DeclarativeUserProfileProvider} becomes the default.
|
||||||
|
* @param session the session
|
||||||
|
* @return {@code true} if the declarative provider is enabled. Otherwise, {@code false}.
|
||||||
|
*/
|
||||||
|
private Boolean isEnabled(KeycloakSession session) {
|
||||||
|
return session.getContext().getRealm().getAttribute(REALM_USER_PROFILE_ENABLED, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
package org.keycloak.userprofile.config;
|
package org.keycloak.userprofile.config;
|
||||||
|
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
|
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
||||||
import org.keycloak.userprofile.UserProfileProvider;
|
import org.keycloak.userprofile.UserProfileProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -20,6 +20,7 @@ import static org.keycloak.common.util.ObjectUtil.isBlank;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -28,6 +29,7 @@ import java.util.Set;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
import org.keycloak.common.util.StreamUtil;
|
||||||
import org.keycloak.models.ClientScopeModel;
|
import org.keycloak.models.ClientScopeModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
|
@ -45,6 +47,7 @@ import org.keycloak.validate.Validators;
|
||||||
*/
|
*/
|
||||||
public class UPConfigUtils {
|
public class UPConfigUtils {
|
||||||
|
|
||||||
|
private static final String SYSTEM_DEFAULT_CONFIG_RESOURCE = "keycloak-default-user-profile.json";
|
||||||
public static final String ROLE_USER = "user";
|
public static final String ROLE_USER = "user";
|
||||||
public static final String ROLE_ADMIN = "admin";
|
public static final String ROLE_ADMIN = "admin";
|
||||||
|
|
||||||
|
@ -260,4 +263,11 @@ public class UPConfigUtils {
|
||||||
return str.substring(0, 1).toUpperCase() + str.substring(1);
|
return str.substring(0, 1).toUpperCase() + str.substring(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static String readDefaultConfig() {
|
||||||
|
try (InputStream is = UPConfigUtils.class.getResourceAsStream(SYSTEM_DEFAULT_CONFIG_RESOURCE)) {
|
||||||
|
return StreamUtil.readString(is, Charset.defaultCharset());
|
||||||
|
} catch (IOException cause) {
|
||||||
|
throw new RuntimeException("Failed to load default user profile config file", cause);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,70 +0,0 @@
|
||||||
/*
|
|
||||||
*
|
|
||||||
* * Copyright 2021 Red Hat, Inc. and/or its affiliates
|
|
||||||
* * and other contributors as indicated by the @author tags.
|
|
||||||
* *
|
|
||||||
* * Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* * you may not use this file except in compliance with the License.
|
|
||||||
* * You may obtain a copy of the License at
|
|
||||||
* *
|
|
||||||
* * http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
* *
|
|
||||||
* * Unless required by applicable law or agreed to in writing, software
|
|
||||||
* * distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* * See the License for the specific language governing permissions and
|
|
||||||
* * limitations under the License.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.keycloak.userprofile.legacy;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
|
||||||
import org.keycloak.models.UserModel;
|
|
||||||
import org.keycloak.services.messages.Messages;
|
|
||||||
import org.keycloak.userprofile.AttributeValidatorMetadata;
|
|
||||||
import org.keycloak.userprofile.UserProfileContext;
|
|
||||||
import org.keycloak.userprofile.UserProfileMetadata;
|
|
||||||
import org.keycloak.userprofile.validator.BlankAttributeValidator;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author <a href="mailto:markus.till@bosch.io">Markus Till</a>
|
|
||||||
*/
|
|
||||||
public class DefaultUserProfileProvider extends AbstractUserProfileProvider<DefaultUserProfileProvider> {
|
|
||||||
|
|
||||||
private static final String PROVIDER_ID = "legacy-user-profile";
|
|
||||||
|
|
||||||
public DefaultUserProfileProvider() {
|
|
||||||
// for reflection
|
|
||||||
}
|
|
||||||
|
|
||||||
public DefaultUserProfileProvider(KeycloakSession session, Map<UserProfileContext, UserProfileMetadata> validators) {
|
|
||||||
super(session, validators);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected DefaultUserProfileProvider create(KeycloakSession session, Map<UserProfileContext, UserProfileMetadata> metadataRegistry) {
|
|
||||||
return new DefaultUserProfileProvider(session, metadataRegistry);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getId() {
|
|
||||||
return PROVIDER_ID;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int order() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected UserProfileMetadata configureUserProfile(UserProfileMetadata metadata) {
|
|
||||||
UserProfileContext ctx = metadata.getContext();
|
|
||||||
if(ctx != UserProfileContext.USER_API && ctx != UserProfileContext.REGISTRATION_USER_CREATION) {
|
|
||||||
metadata.addAttribute(UserModel.FIRST_NAME, new AttributeValidatorMetadata(BlankAttributeValidator.ID, BlankAttributeValidator.createConfig(Messages.MISSING_FIRST_NAME))).setAttributeDisplayName("${firstName}");
|
|
||||||
metadata.addAttribute(UserModel.LAST_NAME, new AttributeValidatorMetadata(BlankAttributeValidator.ID, BlankAttributeValidator.createConfig(Messages.MISSING_LAST_NAME))).setAttributeDisplayName("${lastName}");
|
|
||||||
}
|
|
||||||
return metadata;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -16,5 +16,4 @@
|
||||||
# * limitations under the License.
|
# * limitations under the License.
|
||||||
# */
|
# */
|
||||||
#
|
#
|
||||||
org.keycloak.userprofile.legacy.DefaultUserProfileProvider
|
org.keycloak.userprofile.DeclarativeUserProfileProvider
|
||||||
org.keycloak.userprofile.config.DeclarativeUserProfileProvider
|
|
|
@ -19,9 +19,6 @@ echo ** Adding max-detail-length to eventsStore spi **
|
||||||
|
|
||||||
echo ** Adding spi=userProfile with legacy-user-profile configuration of read-only attributes **
|
echo ** Adding spi=userProfile with legacy-user-profile configuration of read-only attributes **
|
||||||
/subsystem=keycloak-server/spi=userProfile/:add
|
/subsystem=keycloak-server/spi=userProfile/:add
|
||||||
/subsystem=keycloak-server/spi=userProfile/provider=legacy-user-profile/:add(properties={},enabled=true)
|
|
||||||
/subsystem=keycloak-server/spi=userProfile/provider=legacy-user-profile/:map-put(name=properties,key=read-only-attributes,value=[deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing])
|
|
||||||
/subsystem=keycloak-server/spi=userProfile/provider=legacy-user-profile/:map-put(name=properties,key=admin-read-only-attributes,value=[deniedSomeAdmin])
|
|
||||||
/subsystem=keycloak-server/spi=userProfile/provider=declarative-user-profile/:add(properties={},enabled=true)
|
/subsystem=keycloak-server/spi=userProfile/provider=declarative-user-profile/:add(properties={},enabled=true)
|
||||||
/subsystem=keycloak-server/spi=userProfile/provider=declarative-user-profile/:map-put(name=properties,key=read-only-attributes,value=[deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing])
|
/subsystem=keycloak-server/spi=userProfile/provider=declarative-user-profile/:map-put(name=properties,key=read-only-attributes,value=[deniedFoo,deniedBar*,deniedSome/thing,deniedsome*thing])
|
||||||
/subsystem=keycloak-server/spi=userProfile/provider=declarative-user-profile/:map-put(name=properties,key=admin-read-only-attributes,value=[deniedSomeAdmin])
|
/subsystem=keycloak-server/spi=userProfile/provider=declarative-user-profile/:map-put(name=properties,key=admin-read-only-attributes,value=[deniedSomeAdmin])
|
||||||
|
|
|
@ -24,7 +24,4 @@ spi.truststore.file.file=${kc.home.dir}/conf/keycloak.truststore
|
||||||
spi.truststore.file.password=secret
|
spi.truststore.file.password=secret
|
||||||
|
|
||||||
# http client connection reuse settings
|
# http client connection reuse settings
|
||||||
spi.connections-http-client.default.reuse-connections=false
|
spi.connections-http-client.default.reuse-connections=false
|
||||||
|
|
||||||
# user profile provider settings
|
|
||||||
spi.user-profile.provider=${keycloak.userProfile.provider:legacy-user-profile}
|
|
|
@ -20,50 +20,40 @@
|
||||||
package org.keycloak.testsuite.admin.userprofile;
|
package org.keycloak.testsuite.admin.userprofile;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||||
|
import static org.keycloak.userprofile.config.UPConfigUtils.readDefaultConfig;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.nio.charset.Charset;
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.admin.client.resource.UserProfileResource;
|
import org.keycloak.admin.client.resource.UserProfileResource;
|
||||||
import org.keycloak.common.Profile;
|
|
||||||
import org.keycloak.common.util.StreamUtil;
|
import org.keycloak.common.util.StreamUtil;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.testsuite.admin.AbstractAdminTest;
|
import org.keycloak.testsuite.admin.AbstractAdminTest;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.SetDefaultProvider;
|
import org.keycloak.userprofile.config.UPConfigUtils;
|
||||||
import org.keycloak.userprofile.UserProfileSpi;
|
|
||||||
import org.keycloak.userprofile.config.DeclarativeUserProfileProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
*/
|
*/
|
||||||
@EnableFeature(value = Profile.Feature.DECLARATIVE_USER_PROFILE, skipRestart = false)
|
|
||||||
@SetDefaultProvider(spi = UserProfileSpi.ID, providerId = DeclarativeUserProfileProvider.ID,
|
|
||||||
beforeEnableFeature = false,
|
|
||||||
onlyUpdateDefault = true
|
|
||||||
)
|
|
||||||
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
||||||
public class UserProfileAdminTest extends AbstractAdminTest {
|
public class UserProfileAdminTest extends AbstractAdminTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||||
|
if (testRealm.getAttributes() == null) {
|
||||||
|
testRealm.setAttributes(new HashMap<>());
|
||||||
|
}
|
||||||
|
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDefaultConfigIfNoneSet() {
|
public void testDefaultConfigIfNoneSet() {
|
||||||
String defaultRawConfig;
|
assertEquals(readDefaultConfig(), testRealm().users().userProfile().getConfiguration());
|
||||||
|
|
||||||
try (InputStream is = DeclarativeUserProfileProvider.class.getResourceAsStream(DeclarativeUserProfileProvider.SYSTEM_DEFAULT_CONFIG_RESOURCE)) {
|
|
||||||
defaultRawConfig = StreamUtil.readString(is, Charset.defaultCharset());
|
|
||||||
} catch (IOException cause) {
|
|
||||||
throw new RuntimeException("Failed to load default user profile config file", cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
assertEquals(defaultRawConfig, testRealm().users().userProfile().getConfiguration());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
|
@ -39,6 +39,10 @@ import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||||
import org.keycloak.testsuite.util.*;
|
import org.keycloak.testsuite.util.*;
|
||||||
import javax.mail.internet.MimeMessage;
|
import javax.mail.internet.MimeMessage;
|
||||||
|
|
||||||
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
import static org.hamcrest.Matchers.anyOf;
|
||||||
|
import static org.hamcrest.Matchers.containsString;
|
||||||
|
import static org.hamcrest.Matchers.is;
|
||||||
import static org.jgroups.util.Util.assertTrue;
|
import static org.jgroups.util.Util.assertTrue;
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude.AuthServer;
|
||||||
|
@ -261,10 +265,20 @@ public class RegisterTest extends AbstractTestRealmKeycloakTest {
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
assertEquals("Please specify username.", registerPage.getInputAccountErrors().getUsernameError());
|
assertEquals("Please specify username.", registerPage.getInputAccountErrors().getUsernameError());
|
||||||
assertEquals("Please specify first name.", registerPage.getInputAccountErrors().getFirstNameError());
|
assertThat(registerPage.getInputAccountErrors().getFirstNameError(), anyOf(
|
||||||
assertEquals("Please specify last name.", registerPage.getInputAccountErrors().getLastNameError());
|
containsString("Please specify first name"),
|
||||||
assertEquals("Please specify email.", registerPage.getInputAccountErrors().getEmailError());
|
containsString("Please specify this field")
|
||||||
assertEquals("Please specify password.", registerPage.getInputPasswordErrors().getPasswordError());
|
));
|
||||||
|
assertThat(registerPage.getInputAccountErrors().getLastNameError(), anyOf(
|
||||||
|
containsString("Please specify last name"),
|
||||||
|
containsString("Please specify this field")
|
||||||
|
));
|
||||||
|
assertThat(registerPage.getInputAccountErrors().getEmailError(), anyOf(
|
||||||
|
containsString("Please specify email"),
|
||||||
|
containsString("Please specify this field")
|
||||||
|
));
|
||||||
|
|
||||||
|
assertThat(registerPage.getInputPasswordErrors().getPasswordError(), is("Please specify password."));
|
||||||
|
|
||||||
events.expectRegister(null, "registerUserMissingUsername@email")
|
events.expectRegister(null, "registerUserMissingUsername@email")
|
||||||
.removeDetail(Details.USERNAME)
|
.removeDetail(Details.USERNAME)
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
package org.keycloak.testsuite.forms;
|
package org.keycloak.testsuite.forms;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import javax.ws.rs.core.Response;
|
import javax.ws.rs.core.Response;
|
||||||
|
@ -29,15 +31,12 @@ import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.common.Profile;
|
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.representations.idm.UserRepresentation;
|
import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
|
||||||
import org.keycloak.testsuite.arquillian.annotation.SetDefaultProvider;
|
|
||||||
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
import org.keycloak.testsuite.pages.AccountUpdateProfilePage;
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||||
|
@ -47,19 +46,12 @@ import org.keycloak.testsuite.pages.VerifyEmailPage;
|
||||||
import org.keycloak.testsuite.util.ClientScopeBuilder;
|
import org.keycloak.testsuite.util.ClientScopeBuilder;
|
||||||
import org.keycloak.testsuite.util.GreenMailRule;
|
import org.keycloak.testsuite.util.GreenMailRule;
|
||||||
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||||
import org.keycloak.userprofile.UserProfileSpi;
|
|
||||||
import org.keycloak.userprofile.config.DeclarativeUserProfileProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
* @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
|
||||||
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
|
* @author Stan Silvert ssilvert@redhat.com (C) 2016 Red Hat Inc.
|
||||||
* @author Vlastimil Elias <velias@redhat.com>
|
* @author Vlastimil Elias <velias@redhat.com>
|
||||||
*/
|
*/
|
||||||
@EnableFeature(value = Profile.Feature.DECLARATIVE_USER_PROFILE, skipRestart = false)
|
|
||||||
@SetDefaultProvider(spi = UserProfileSpi.ID, providerId = DeclarativeUserProfileProvider.ID,
|
|
||||||
beforeEnableFeature = false,
|
|
||||||
onlyUpdateDefault = true
|
|
||||||
)
|
|
||||||
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
||||||
public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
|
|
||||||
|
@ -103,18 +95,21 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
List<String> scopes = new ArrayList<>();
|
List<String> scopes = new ArrayList<>();
|
||||||
scopes.add(SCOPE_LAST_NAME);
|
scopes.add(SCOPE_LAST_NAME);
|
||||||
scopes.add(VerifyProfileTest.SCOPE_DEPARTMENT);
|
scopes.add(VerifyProfileTest.SCOPE_DEPARTMENT);
|
||||||
|
|
||||||
client_scope_default = KeycloakModelUtils.createClient(testRealm, "client-a");
|
client_scope_default = KeycloakModelUtils.createClient(testRealm, "client-a");
|
||||||
client_scope_default.setDefaultClientScopes(scopes);
|
client_scope_default.setDefaultClientScopes(scopes);
|
||||||
client_scope_default.setRedirectUris(Collections.singletonList("*"));
|
client_scope_default.setRedirectUris(Collections.singletonList("*"));
|
||||||
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
||||||
client_scope_optional.setOptionalClientScopes(scopes);
|
client_scope_optional.setOptionalClientScopes(scopes);
|
||||||
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
||||||
|
if (testRealm.getAttributes() == null) {
|
||||||
|
testRealm.setAttributes(new HashMap<>());
|
||||||
|
}
|
||||||
|
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRregisterUserSuccess_lastNameOptional() {
|
public void testRegisterUserSuccess_lastNameOptional() {
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ UP_CONFIG_BASIC_ATTRIBUTES
|
+ UP_CONFIG_BASIC_ATTRIBUTES
|
||||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
|
@ -248,14 +243,14 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
events.expectRegister("registeruserinvalidlastnamelength", "registerUserInvalidLastNameLength@email")
|
events.expectRegister("registeruserinvalidlastnamelength", "registerUserInvalidLastNameLength@email")
|
||||||
.error("invalid_registration").assertEvent();
|
.error("invalid_registration").assertEvent();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAttributeDisplayName() {
|
public void testAttributeDisplayName() {
|
||||||
|
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}}"
|
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}}"
|
||||||
+ "]}");
|
+ "]}");
|
||||||
|
|
||||||
loginPage.open();
|
loginPage.open();
|
||||||
|
@ -271,50 +266,50 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
// direct value in display name
|
// direct value in display name
|
||||||
Assert.assertEquals("Department",registerPage.getLabelForField("department"));
|
Assert.assertEquals("Department",registerPage.getLabelForField("department"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterUserSuccess_requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration() {
|
public void testRegisterUserSuccess_requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration() {
|
||||||
|
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\",\"displayName\":\"${firstName}\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||||
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + VerifyProfileTest.PERMISSIONS_ADMIN_EDITABLE + ", \"required\":{}}"
|
+ "{\"name\": \"department\", \"displayName\" : \"Department\", " + VerifyProfileTest.PERMISSIONS_ADMIN_EDITABLE + ", \"required\":{}}"
|
||||||
+ "]}");
|
+ "]}");
|
||||||
|
|
||||||
loginPage.open();
|
loginPage.open();
|
||||||
loginPage.clickRegister();
|
loginPage.clickRegister();
|
||||||
|
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
Assert.assertFalse(registerPage.isDepartmentPresent());
|
Assert.assertFalse(registerPage.isDepartmentPresent());
|
||||||
|
|
||||||
|
|
||||||
registerPage.register("FirstName", "LastName", "requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration@email", "requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration", "password", "password");
|
registerPage.register("FirstName", "LastName", "requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration@email", "requiredReadOnlyAttributeNotRenderedAndNotBlockingRegistration", "password", "password");
|
||||||
|
|
||||||
appPage.assertCurrent();
|
appPage.assertCurrent();
|
||||||
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterUserSuccess_attributeRequiredAndSelectedByScopeMustBeSet() {
|
public void testRegisterUserSuccess_attributeRequiredAndSelectedByScopeMustBeSet() {
|
||||||
|
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + "},"
|
||||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||||
+ "]}");
|
+ "]}");
|
||||||
|
|
||||||
oauth.scope(VerifyProfileTest.SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
oauth.scope(VerifyProfileTest.SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||||
loginPage.clickRegister();
|
loginPage.clickRegister();
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
//check required validation works
|
//check required validation works
|
||||||
registerPage.register("FirstAA", "LastAA", "attributeRequiredAndSelectedByScopeMustBeSet@email", "attributeRequiredAndSelectedByScopeMustBeSet", "password", "password", "");
|
registerPage.register("FirstAA", "LastAA", "attributeRequiredAndSelectedByScopeMustBeSet@email", "attributeRequiredAndSelectedByScopeMustBeSet", "password", "password", "");
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
registerPage.register("FirstAA", "LastAA", "attributeRequiredAndSelectedByScopeMustBeSet@email", "attributeRequiredAndSelectedByScopeMustBeSet", "password", "password", "DepartmentAA");
|
registerPage.register("FirstAA", "LastAA", "attributeRequiredAndSelectedByScopeMustBeSet@email", "attributeRequiredAndSelectedByScopeMustBeSet", "password", "password", "DepartmentAA");
|
||||||
|
|
||||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
|
||||||
|
@ -327,23 +322,23 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterUserSuccess_attributeNotRequiredAndSelectedByScopeCanBeIgnored() {
|
public void testRegisterUserSuccess_attributeNotRequiredAndSelectedByScopeCanBeIgnored() {
|
||||||
|
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||||
+ "]}");
|
+ "]}");
|
||||||
|
|
||||||
oauth.scope(VerifyProfileTest.SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
oauth.scope(VerifyProfileTest.SCOPE_DEPARTMENT).clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||||
loginPage.clickRegister();
|
loginPage.clickRegister();
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
Assert.assertTrue(registerPage.isDepartmentPresent());
|
Assert.assertTrue(registerPage.isDepartmentPresent());
|
||||||
registerPage.register("FirstAA", "LastAA", "attributeNotRequiredAndSelectedByScopeCanBeIgnored@email", "attributeNotRequiredAndSelectedByScopeCanBeIgnored", "password", "password", null);
|
registerPage.register("FirstAA", "LastAA", "attributeNotRequiredAndSelectedByScopeCanBeIgnored@email", "attributeNotRequiredAndSelectedByScopeCanBeIgnored", "password", "password", null);
|
||||||
|
|
||||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
|
||||||
String userId = events.expectRegister("attributeNotRequiredAndSelectedByScopeCanBeIgnored", "attributeNotRequiredAndSelectedByScopeCanBeIgnored@email",client_scope_optional.getClientId()).assertEvent().getUserId();
|
String userId = events.expectRegister("attributeNotRequiredAndSelectedByScopeCanBeIgnored", "attributeNotRequiredAndSelectedByScopeCanBeIgnored@email",client_scope_optional.getClientId()).assertEvent().getUserId();
|
||||||
UserRepresentation user = getUser(userId);
|
UserRepresentation user = getUser(userId);
|
||||||
assertEquals("FirstAA", user.getFirstName());
|
assertEquals("FirstAA", user.getFirstName());
|
||||||
assertEquals("LastAA", user.getLastName());
|
assertEquals("LastAA", user.getLastName());
|
||||||
|
@ -353,23 +348,23 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterUserSuccess_attributeNotRequiredAndSelectedByScopeCanBeSet() {
|
public void testRegisterUserSuccess_attributeNotRequiredAndSelectedByScopeCanBeSet() {
|
||||||
|
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||||
+ "]}");
|
+ "]}");
|
||||||
|
|
||||||
oauth.clientId(client_scope_default.getClientId()).openLoginForm();
|
oauth.clientId(client_scope_default.getClientId()).openLoginForm();
|
||||||
loginPage.clickRegister();
|
loginPage.clickRegister();
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
Assert.assertTrue(registerPage.isDepartmentPresent());
|
Assert.assertTrue(registerPage.isDepartmentPresent());
|
||||||
registerPage.register("FirstAA", "LastAA", "attributeNotRequiredAndSelectedByScopeCanBeSet@email", "attributeNotRequiredAndSelectedByScopeCanBeSet", "password", "password", "Department AA");
|
registerPage.register("FirstAA", "LastAA", "attributeNotRequiredAndSelectedByScopeCanBeSet@email", "attributeNotRequiredAndSelectedByScopeCanBeSet", "password", "password", "Department AA");
|
||||||
|
|
||||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
|
||||||
String userId = events.expectRegister("attributeNotRequiredAndSelectedByScopeCanBeSet", "attributeNotRequiredAndSelectedByScopeCanBeSet@email",client_scope_default.getClientId()).assertEvent().getUserId();
|
String userId = events.expectRegister("attributeNotRequiredAndSelectedByScopeCanBeSet", "attributeNotRequiredAndSelectedByScopeCanBeSet@email",client_scope_default.getClientId()).assertEvent().getUserId();
|
||||||
UserRepresentation user = getUser(userId);
|
UserRepresentation user = getUser(userId);
|
||||||
assertEquals("FirstAA", user.getFirstName());
|
assertEquals("FirstAA", user.getFirstName());
|
||||||
assertEquals("LastAA", user.getLastName());
|
assertEquals("LastAA", user.getLastName());
|
||||||
|
@ -379,19 +374,19 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
@Test
|
@Test
|
||||||
public void testRegisterUserSuccess_attributeRequiredButNotSelectedByScopeIsNotRenderedAndNotBlockingRegistration() {
|
public void testRegisterUserSuccess_attributeRequiredButNotSelectedByScopeIsNotRenderedAndNotBlockingRegistration() {
|
||||||
|
|
||||||
setUserProfileConfiguration("{\"attributes\": ["
|
setUserProfileConfiguration("{\"attributes\": ["
|
||||||
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"firstName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
+ "{\"name\": \"lastName\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\": {}},"
|
||||||
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
+ "{\"name\": \"department\"," + VerifyProfileTest.PERMISSIONS_ALL + ", \"required\":{}, \"selector\":{\"scopes\":[\""+VerifyProfileTest.SCOPE_DEPARTMENT+"\"]}}"
|
||||||
+ "]}");
|
+ "]}");
|
||||||
|
|
||||||
oauth.clientId(client_scope_optional.getClientId()).openLoginForm();
|
oauth.clientId(client_scope_optional.getClientId()).openLoginForm();
|
||||||
loginPage.clickRegister();
|
loginPage.clickRegister();
|
||||||
registerPage.assertCurrent();
|
registerPage.assertCurrent();
|
||||||
|
|
||||||
Assert.assertFalse(registerPage.isDepartmentPresent());
|
Assert.assertFalse(registerPage.isDepartmentPresent());
|
||||||
registerPage.register("FirstAA", "LastAA", "attributeRequiredButNotSelectedByScopeIsNotRendered@email", "attributeRequiredButNotSelectedByScopeIsNotRendered", "password", "password");
|
registerPage.register("FirstAA", "LastAA", "attributeRequiredButNotSelectedByScopeIsNotRendered@email", "attributeRequiredButNotSelectedByScopeIsNotRendered", "password", "password");
|
||||||
|
|
||||||
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
Assert.assertEquals(RequestType.AUTH_RESPONSE, appPage.getRequestType());
|
||||||
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
Assert.assertNotNull(oauth.getCurrentQuery().get(OAuth2Constants.CODE));
|
||||||
|
|
||||||
|
@ -402,7 +397,7 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
assertEquals(null, user.firstAttribute(VerifyProfileTest.ATTRIBUTE_DEPARTMENT));
|
assertEquals(null, user.firstAttribute(VerifyProfileTest.ATTRIBUTE_DEPARTMENT));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void assertUserRegistered(String userId, String username, String email, String firstName, String lastName) {
|
private void assertUserRegistered(String userId, String username, String email, String firstName, String lastName) {
|
||||||
events.expectLogin().detail("username", username.toLowerCase()).user(userId).assertEvent();
|
events.expectLogin().detail("username", username.toLowerCase()).user(userId).assertEvent();
|
||||||
|
|
||||||
|
@ -421,7 +416,7 @@ public class RegisterWithUserProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
protected UserRepresentation getUser(String userId) {
|
protected UserRepresentation getUser(String userId) {
|
||||||
return testRealm().users().get(userId).toRepresentation();
|
return testRealm().users().get(userId).toRepresentation();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected UserRepresentation getUserByUsername(String username) {
|
protected UserRepresentation getUserByUsername(String username) {
|
||||||
List<UserRepresentation> users = testRealm().users().search(username);
|
List<UserRepresentation> users = testRealm().users().search(username);
|
||||||
if(users!=null && !users.isEmpty())
|
if(users!=null && !users.isEmpty())
|
||||||
|
|
|
@ -0,0 +1,24 @@
|
||||||
|
package org.keycloak.testsuite.forms;
|
||||||
|
|
||||||
|
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
|
*/
|
||||||
|
public class UserProfileRegisterTest extends RegisterTest {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||||
|
super.configureTestRealm(testRealm);
|
||||||
|
|
||||||
|
if (testRealm.getAttributes() == null) {
|
||||||
|
testRealm.setAttributes(new HashMap<>());
|
||||||
|
}
|
||||||
|
|
||||||
|
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||||
|
}
|
||||||
|
}
|
|
@ -19,9 +19,11 @@ package org.keycloak.testsuite.forms;
|
||||||
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.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
@ -33,7 +35,6 @@ import org.junit.Assert;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.OAuth2Constants;
|
import org.keycloak.OAuth2Constants;
|
||||||
import org.keycloak.common.Profile;
|
|
||||||
import org.keycloak.events.EventType;
|
import org.keycloak.events.EventType;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
import org.keycloak.representations.idm.ClientRepresentation;
|
import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
|
@ -43,8 +44,6 @@ import org.keycloak.representations.idm.UserRepresentation;
|
||||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
import org.keycloak.testsuite.AssertEvents;
|
import org.keycloak.testsuite.AssertEvents;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
|
||||||
import org.keycloak.testsuite.arquillian.annotation.SetDefaultProvider;
|
|
||||||
import org.keycloak.testsuite.pages.AppPage;
|
import org.keycloak.testsuite.pages.AppPage;
|
||||||
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
import org.keycloak.testsuite.pages.AppPage.RequestType;
|
||||||
import org.keycloak.testsuite.pages.LoginPage;
|
import org.keycloak.testsuite.pages.LoginPage;
|
||||||
|
@ -54,16 +53,10 @@ import org.keycloak.testsuite.util.KeycloakModelUtils;
|
||||||
import org.keycloak.testsuite.util.OAuthClient;
|
import org.keycloak.testsuite.util.OAuthClient;
|
||||||
import org.keycloak.testsuite.util.RealmBuilder;
|
import org.keycloak.testsuite.util.RealmBuilder;
|
||||||
import org.keycloak.testsuite.util.UserBuilder;
|
import org.keycloak.testsuite.util.UserBuilder;
|
||||||
import org.keycloak.userprofile.UserProfileSpi;
|
|
||||||
import org.keycloak.userprofile.config.DeclarativeUserProfileProvider;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author Vlastimil Elias <velias@redhat.com>
|
* @author Vlastimil Elias <velias@redhat.com>
|
||||||
*/
|
*/
|
||||||
@EnableFeature(value = Profile.Feature.DECLARATIVE_USER_PROFILE, skipRestart = false)
|
|
||||||
@SetDefaultProvider(spi = UserProfileSpi.ID, providerId = DeclarativeUserProfileProvider.ID,
|
|
||||||
beforeEnableFeature = false,
|
|
||||||
onlyUpdateDefault = true)
|
|
||||||
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
||||||
public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
|
|
||||||
|
@ -135,6 +128,10 @@ public class VerifyProfileTest extends AbstractTestRealmKeycloakTest {
|
||||||
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
client_scope_optional = KeycloakModelUtils.createClient(testRealm, "client-b");
|
||||||
client_scope_optional.setOptionalClientScopes(Collections.singletonList(SCOPE_DEPARTMENT));
|
client_scope_optional.setOptionalClientScopes(Collections.singletonList(SCOPE_DEPARTMENT));
|
||||||
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
client_scope_optional.setRedirectUris(Collections.singletonList("*"));
|
||||||
|
if (testRealm.getAttributes() == null) {
|
||||||
|
testRealm.setAttributes(new HashMap<>());
|
||||||
|
}
|
||||||
|
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
|
|
|
@ -19,6 +19,9 @@
|
||||||
|
|
||||||
package org.keycloak.testsuite.user.profile;
|
package org.keycloak.testsuite.user.profile;
|
||||||
|
|
||||||
|
import static org.keycloak.userprofile.DeclarativeUserProfileProvider.REALM_USER_PROFILE_ENABLED;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
@ -27,10 +30,11 @@ import org.keycloak.models.ClientModel;
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.sessions.AuthenticationSessionModel;
|
import org.keycloak.sessions.AuthenticationSessionModel;
|
||||||
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
import org.keycloak.sessions.RootAuthenticationSessionModel;
|
||||||
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
import org.keycloak.testsuite.AbstractTestRealmKeycloakTest;
|
||||||
import org.keycloak.userprofile.config.DeclarativeUserProfileProvider;
|
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
||||||
import org.keycloak.userprofile.UserProfileProvider;
|
import org.keycloak.userprofile.UserProfileProvider;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -233,4 +237,12 @@ public abstract class AbstractUserProfileTest extends AbstractTestRealmKeycloakT
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||||
|
if (testRealm.getAttributes() == null) {
|
||||||
|
testRealm.setAttributes(new HashMap<>());
|
||||||
|
}
|
||||||
|
testRealm.getAttributes().put(REALM_USER_PROFILE_ENABLED, Boolean.TRUE.toString());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,8 @@ import java.util.function.Consumer;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.keycloak.common.Profile;
|
|
||||||
import org.keycloak.component.ComponentModel;
|
import org.keycloak.component.ComponentModel;
|
||||||
import org.keycloak.component.ComponentValidationException;
|
import org.keycloak.component.ComponentValidationException;
|
||||||
import org.keycloak.models.ClientScopeModel;
|
|
||||||
import org.keycloak.models.KeycloakSession;
|
import org.keycloak.models.KeycloakSession;
|
||||||
import org.keycloak.models.RealmModel;
|
import org.keycloak.models.RealmModel;
|
||||||
import org.keycloak.models.UserModel;
|
import org.keycloak.models.UserModel;
|
||||||
|
@ -54,11 +52,8 @@ import org.keycloak.representations.idm.ClientRepresentation;
|
||||||
import org.keycloak.representations.idm.RealmRepresentation;
|
import org.keycloak.representations.idm.RealmRepresentation;
|
||||||
import org.keycloak.services.messages.Messages;
|
import org.keycloak.services.messages.Messages;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
import org.keycloak.testsuite.arquillian.annotation.AuthServerContainerExclude;
|
||||||
import org.keycloak.testsuite.arquillian.annotation.EnableFeature;
|
|
||||||
import org.keycloak.testsuite.arquillian.annotation.SetDefaultProvider;
|
|
||||||
import org.keycloak.testsuite.runonserver.RunOnServer;
|
import org.keycloak.testsuite.runonserver.RunOnServer;
|
||||||
import org.keycloak.userprofile.UserProfileSpi;
|
import org.keycloak.userprofile.DeclarativeUserProfileProvider;
|
||||||
import org.keycloak.userprofile.config.DeclarativeUserProfileProvider;
|
|
||||||
import org.keycloak.userprofile.config.UPAttribute;
|
import org.keycloak.userprofile.config.UPAttribute;
|
||||||
import org.keycloak.userprofile.config.UPAttributePermissions;
|
import org.keycloak.userprofile.config.UPAttributePermissions;
|
||||||
import org.keycloak.userprofile.config.UPAttributeRequired;
|
import org.keycloak.userprofile.config.UPAttributeRequired;
|
||||||
|
@ -80,15 +75,12 @@ import org.keycloak.validate.validators.LengthValidator;
|
||||||
/**
|
/**
|
||||||
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
* @author <a href="mailto:psilva@redhat.com">Pedro Igor</a>
|
||||||
*/
|
*/
|
||||||
@EnableFeature(Profile.Feature.DECLARATIVE_USER_PROFILE)
|
|
||||||
@SetDefaultProvider(spi = UserProfileSpi.ID, providerId = DeclarativeUserProfileProvider.ID,
|
|
||||||
beforeEnableFeature = false,
|
|
||||||
onlyUpdateDefault = true)
|
|
||||||
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
@AuthServerContainerExclude(AuthServerContainerExclude.AuthServer.REMOTE)
|
||||||
public class UserProfileTest extends AbstractUserProfileTest {
|
public class UserProfileTest extends AbstractUserProfileTest {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configureTestRealm(RealmRepresentation testRealm) {
|
public void configureTestRealm(RealmRepresentation testRealm) {
|
||||||
|
super.configureTestRealm(testRealm);
|
||||||
testRealm.setClientScopes(new ArrayList<>());
|
testRealm.setClientScopes(new ArrayList<>());
|
||||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name("customer").protocol("openid-connect").build());
|
testRealm.getClientScopes().add(ClientScopeBuilder.create().name("customer").protocol("openid-connect").build());
|
||||||
testRealm.getClientScopes().add(ClientScopeBuilder.create().name("client-a").protocol("openid-connect").build());
|
testRealm.getClientScopes().add(ClientScopeBuilder.create().name("client-a").protocol("openid-connect").build());
|
||||||
|
|
|
@ -220,10 +220,6 @@
|
||||||
|
|
||||||
"userProfile": {
|
"userProfile": {
|
||||||
"provider": "${keycloak.userProfile.provider:}",
|
"provider": "${keycloak.userProfile.provider:}",
|
||||||
"legacy-user-profile": {
|
|
||||||
"read-only-attributes": [ "deniedFoo", "deniedBar*", "deniedSome/thing", "deniedsome*thing" ],
|
|
||||||
"admin-read-only-attributes": [ "deniedSomeAdmin" ]
|
|
||||||
},
|
|
||||||
"declarative-user-profile": {
|
"declarative-user-profile": {
|
||||||
"read-only-attributes": [ "deniedFoo", "deniedBar*", "deniedSome/thing", "deniedsome*thing" ],
|
"read-only-attributes": [ "deniedFoo", "deniedBar*", "deniedSome/thing", "deniedsome*thing" ],
|
||||||
"admin-read-only-attributes": [ "deniedSomeAdmin" ]
|
"admin-read-only-attributes": [ "deniedSomeAdmin" ]
|
||||||
|
|
|
@ -140,10 +140,6 @@
|
||||||
|
|
||||||
"userProfile": {
|
"userProfile": {
|
||||||
"provider": "${keycloak.userProfile.provider:}",
|
"provider": "${keycloak.userProfile.provider:}",
|
||||||
"legacy-user-profile": {
|
|
||||||
"read-only-attributes": [ "deniedFoo", "deniedBar*", "deniedSome/thing", "deniedsome*thing" ],
|
|
||||||
"admin-read-only-attributes": [ "deniedSomeAdmin" ]
|
|
||||||
},
|
|
||||||
"declarative-user-profile": {
|
"declarative-user-profile": {
|
||||||
"read-only-attributes": [ "deniedFoo", "deniedBar*", "deniedSome/thing", "deniedsome*thing" ],
|
"read-only-attributes": [ "deniedFoo", "deniedBar*", "deniedSome/thing", "deniedsome*thing" ],
|
||||||
"admin-read-only-attributes": [ "deniedSomeAdmin" ]
|
"admin-read-only-attributes": [ "deniedSomeAdmin" ]
|
||||||
|
|
|
@ -32,6 +32,8 @@ realm-detail.protocol-endpoints.tooltip=Shows the configuration of the protocol
|
||||||
realm-detail.protocol-endpoints.oidc=OpenID Endpoint Configuration
|
realm-detail.protocol-endpoints.oidc=OpenID Endpoint Configuration
|
||||||
realm-detail.protocol-endpoints.saml=SAML 2.0 Identity Provider Metadata
|
realm-detail.protocol-endpoints.saml=SAML 2.0 Identity Provider Metadata
|
||||||
realm-detail.userManagedAccess.tooltip=If enabled, users are allowed to manage their resources and permissions using the Account Management Console.
|
realm-detail.userManagedAccess.tooltip=If enabled, users are allowed to manage their resources and permissions using the Account Management Console.
|
||||||
|
userProfileEnabled=User Profile Enabled
|
||||||
|
userProfileEnabled.tooltip=If enabled, allows managing user profiles.
|
||||||
userManagedAccess=User-Managed Access
|
userManagedAccess=User-Managed Access
|
||||||
registrationAllowed=User registration
|
registrationAllowed=User registration
|
||||||
registrationAllowed.tooltip=Enable/disable the registration page. A link for registration will show on login page too.
|
registrationAllowed.tooltip=Enable/disable the registration page. A link for registration will show on login page too.
|
||||||
|
|
|
@ -280,8 +280,10 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, ser
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
$scope.realm = angular.copy(realm);
|
$scope.realm = angular.copy(realm);
|
||||||
|
$scope.realm.attributes['userProfileEnabled'] = $scope.realm.attributes['userProfileEnabled'] == 'true';
|
||||||
|
|
||||||
var oldCopy = angular.copy($scope.realm);
|
var oldCopy = angular.copy($scope.realm);
|
||||||
|
$scope.realmCopy = oldCopy;
|
||||||
|
|
||||||
$scope.changed = $scope.create;
|
$scope.changed = $scope.create;
|
||||||
|
|
||||||
|
@ -309,6 +311,7 @@ module.controller('RealmDetailCtrl', function($scope, Current, Realm, realm, ser
|
||||||
if (Current.realms[i].realm == realmCopy.realm) {
|
if (Current.realms[i].realm == realmCopy.realm) {
|
||||||
Current.realm = Current.realms[i];
|
Current.realm = Current.realms[i];
|
||||||
oldCopy = angular.copy($scope.realm);
|
oldCopy = angular.copy($scope.realm);
|
||||||
|
$scope.realmCopy = oldCopy;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -55,6 +55,14 @@
|
||||||
<kc-tooltip>{{:: 'realm-detail.userManagedAccess.tooltip' | translate}}</kc-tooltip>
|
<kc-tooltip>{{:: 'realm-detail.userManagedAccess.tooltip' | translate}}</kc-tooltip>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label class="col-md-2 control-label" for="userProfileEnabled">{{:: 'userProfileEnabled' | translate}}</label>
|
||||||
|
<div class="col-md-6">
|
||||||
|
<input ng-model="realm.attributes['userProfileEnabled']" name="userProfileEnabled" id="userProfileEnabled" onoffswitch on-text="{{:: 'onText' | translate}}" off-text="{{:: 'offText' | translate}}" />
|
||||||
|
</div>
|
||||||
|
<kc-tooltip>{{:: 'userProfileEnabled.tooltip' | translate}}</kc-tooltip>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label class="col-md-2 control-label">{{:: 'endpoints' | translate}}</label>
|
<label class="col-md-2 control-label">{{:: 'endpoints' | translate}}</label>
|
||||||
<div class="col-md-6">
|
<div class="col-md-6">
|
||||||
|
|
|
@ -19,6 +19,6 @@
|
||||||
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'realm-tab-client-policies' | translate}}</a>
|
<a href="#/realms/{{realm.realm}}/client-policies/profiles">{{:: 'realm-tab-client-policies' | translate}}</a>
|
||||||
</li>
|
</li>
|
||||||
<li ng-class="{active: path[2] == 'defense'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/defense/headers">{{:: 'realm-tab-security-defenses' | translate}}</a></li>
|
<li ng-class="{active: path[2] == 'defense'}" data-ng-show="access.viewRealm"><a href="#/realms/{{realm.realm}}/defense/headers">{{:: 'realm-tab-security-defenses' | translate}}</a></li>
|
||||||
<li ng-class="{active: path[2] == 'user-profile'}" data-ng-show="access.viewRealm && serverInfo.featureEnabled('DECLARATIVE_USER_PROFILE')"><a href="#/realms/{{realm.realm}}/user-profile">{{:: 'realm-tab-user-profile' | translate}}</a></li>
|
<li ng-class="{active: path[2] == 'user-profile'}" data-ng-show="access.viewRealm && (realm.attributes['userProfileEnabled'] == true || realm.attributes['userProfileEnabled'] == 'true')"><a href="#/realms/{{realm.realm}}/user-profile">{{:: 'realm-tab-user-profile' | translate}}</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
Loading…
Reference in a new issue