use of org.keycloak.userprofile.config.UPAttributeRequired in project keycloak by keycloak.
the class UserProfileTest method testNoValidationsIfAdminReadOnly.
private static void testNoValidationsIfAdminReadOnly(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(UPConfigUtils.ROLE_USER));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "user");
// Fails on USER context
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
try {
profile.validate();
fail("Should fail validation");
} catch (ValidationException ve) {
assertTrue(ve.isAttributeOnError(ATT_ADDRESS));
}
// NO fail on ADMIN context - User REST API
profile = provider.create(UserProfileContext.USER_API, attributes);
profile.validate();
}
use of org.keycloak.userprofile.config.UPAttributeRequired in project keycloak by keycloak.
the class UserProfileTest method testRequiredByClientScope.
private static void testRequiredByClientScope(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setScopes(Collections.singleton("client-a"));
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton("user"));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "user");
attributes.put(UserModel.EMAIL, "user@email.test");
// client with default scopes for which is attribute NOT configured as required
configureAuthenticationSession(session, "client-b", null);
// no fail on User API nor Account console as they do not have scopes
UserProfile profile = provider.create(UserProfileContext.USER_API, attributes);
profile.validate();
profile = provider.create(UserProfileContext.ACCOUNT, attributes);
profile.validate();
profile = provider.create(UserProfileContext.ACCOUNT_OLD, attributes);
profile.validate();
// no fail on auth flow scopes when scope is not required
profile = provider.create(UserProfileContext.REGISTRATION_PROFILE, attributes);
profile.validate();
profile = provider.create(UserProfileContext.REGISTRATION_USER_CREATION, attributes);
profile.validate();
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
profile.validate();
profile = provider.create(UserProfileContext.IDP_REVIEW, attributes);
profile.validate();
// client with default scope for which is attribute configured as required
configureAuthenticationSession(session, "client-a", null);
// no fail on User API nor Account console as they do not have scopes
profile = provider.create(UserProfileContext.USER_API, attributes);
profile.validate();
profile = provider.create(UserProfileContext.ACCOUNT, attributes);
profile.validate();
profile = provider.create(UserProfileContext.ACCOUNT_OLD, attributes);
profile.validate();
// fail on auth flow scopes when scope is required
try {
profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
profile.validate();
fail("Should fail validation");
} catch (ValidationException ve) {
assertTrue(ve.isAttributeOnError(ATT_ADDRESS));
}
try {
profile = provider.create(UserProfileContext.REGISTRATION_PROFILE, attributes);
profile.validate();
fail("Should fail validation");
} catch (ValidationException ve) {
assertTrue(ve.isAttributeOnError(ATT_ADDRESS));
}
try {
profile = provider.create(UserProfileContext.IDP_REVIEW, attributes);
profile.validate();
fail("Should fail validation");
} catch (ValidationException ve) {
assertTrue(ve.isAttributeOnError(ATT_ADDRESS));
}
}
use of org.keycloak.userprofile.config.UPAttributeRequired in project keycloak by keycloak.
the class UserProfileTest method testRequiredIfAdmin.
private static void testRequiredIfAdmin(KeycloakSession session) throws IOException {
DeclarativeUserProfileProvider provider = getDynamicUserProfileProvider(session);
ComponentModel component = provider.getComponentModel();
assertNotNull(component);
UPConfig config = new UPConfig();
UPAttribute attribute = new UPAttribute();
attribute.setName(ATT_ADDRESS);
UPAttributeRequired requirements = new UPAttributeRequired();
requirements.setRoles(Collections.singleton(ROLE_ADMIN));
attribute.setRequired(requirements);
UPAttributePermissions permissions = new UPAttributePermissions();
permissions.setEdit(Collections.singleton(UPConfigUtils.ROLE_ADMIN));
attribute.setPermissions(permissions);
config.addAttribute(attribute);
provider.setConfiguration(JsonSerialization.writeValueAsString(config));
Map<String, Object> attributes = new HashMap<>();
attributes.put(UserModel.USERNAME, "user");
// NO fail on common contexts
UserProfile profile = provider.create(UserProfileContext.UPDATE_PROFILE, attributes);
profile.validate();
profile = provider.create(UserProfileContext.ACCOUNT, attributes);
profile.validate();
profile = provider.create(UserProfileContext.REGISTRATION_PROFILE, attributes);
profile.validate();
// fail on User API
try {
profile = provider.create(UserProfileContext.USER_API, attributes);
profile.validate();
fail("Should fail validation");
} catch (ValidationException ve) {
assertTrue(ve.isAttributeOnError(ATT_ADDRESS));
}
}
use of org.keycloak.userprofile.config.UPAttributeRequired in project keycloak by keycloak.
the class UPConfigParserTest method validateConfiguration_attributeRequirementsErrors.
public static void validateConfiguration_attributeRequirementsErrors(KeycloakSession session) throws IOException {
UPConfig config = loadValidConfig();
// we run this test without KeycloakSession so validator configs are not validated here
UPAttribute attConfig = config.getAttributes().get(1);
// it is OK without requirements configures at all
attConfig.setRequired(null);
List<String> errors = validate(session, config);
Assert.assertEquals(0, errors.size());
// it is OK with empty config as it means ALWAYS required
UPAttributeRequired reqConfig = new UPAttributeRequired();
attConfig.setRequired(reqConfig);
errors = validate(session, config);
Assert.assertEquals(0, errors.size());
Assert.assertTrue(reqConfig.isAlways());
// invalid role used
reqConfig.setRoles(Collections.singleton("invalid"));
errors = validate(session, config);
Assert.assertEquals(1, errors.size());
Assert.assertFalse(reqConfig.isAlways());
}
use of org.keycloak.userprofile.config.UPAttributeRequired in project keycloak by keycloak.
the class DeclarativeUserProfileProvider method decorateUserProfileForCache.
/**
* Decorate basic metadata provided from {@link AbstractUserProfileProvider} based on 'per realm' configuration.
* 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.
*
* @param decoratedMetadata base to be decorated based on configuration loaded from component model
* @param model component model to get "per realm" configuration from
* @return decorated metadata
*/
protected UserProfileMetadata decorateUserProfileForCache(UserProfileMetadata decoratedMetadata, ComponentModel model) {
UserProfileContext context = decoratedMetadata.getContext();
UPConfig parsedConfig = getParsedConfig(model);
// 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) {
return decoratedMetadata;
}
Map<String, UPGroup> groupsByName = asHashMap(parsedConfig.getGroups());
int guiOrder = 0;
for (UPAttribute attrConfig : parsedConfig.getAttributes()) {
String attributeName = attrConfig.getName();
List<AttributeValidatorMetadata> validators = new ArrayList<>();
Map<String, Map<String, Object>> validationsConfig = attrConfig.getValidations();
if (validationsConfig != null) {
for (Map.Entry<String, Map<String, Object>> vc : validationsConfig.entrySet()) {
validators.add(createConfiguredValidator(vc.getKey(), vc.getValue()));
}
}
UPAttributeRequired rc = attrConfig.getRequired();
Predicate<AttributeContext> required = AttributeMetadata.ALWAYS_FALSE;
if (rc != null && !isUsernameOrEmailAttribute(attributeName)) {
// driven by business logic from parent!
if (rc.isAlways() || UPConfigUtils.isRoleForContext(context, rc.getRoles())) {
required = AttributeMetadata.ALWAYS_TRUE;
} else if (UPConfigUtils.canBeAuthFlowContext(context) && rc.getScopes() != null && !rc.getScopes().isEmpty()) {
// for contexts executed from auth flow and with configured scopes requirement
// we have to create required validation with scopes based selector
required = (c) -> requestedScopePredicate(c, rc.getScopes());
}
validators.add(new AttributeValidatorMetadata(AttributeRequiredByMetadataValidator.ID));
}
Predicate<AttributeContext> writeAllowed = AttributeMetadata.ALWAYS_FALSE;
Predicate<AttributeContext> readAllowed = AttributeMetadata.ALWAYS_FALSE;
UPAttributePermissions permissions = attrConfig.getPermissions();
if (permissions != null) {
Set<String> editRoles = permissions.getEdit();
if (!editRoles.isEmpty()) {
writeAllowed = ac -> UPConfigUtils.isRoleForContext(ac.getContext(), editRoles);
}
Set<String> viewRoles = permissions.getView();
if (viewRoles.isEmpty()) {
readAllowed = writeAllowed;
} else {
readAllowed = createViewAllowedPredicate(writeAllowed, viewRoles);
}
}
Predicate<AttributeContext> selector = AttributeMetadata.ALWAYS_TRUE;
UPAttributeSelector sc = attrConfig.getSelector();
if (sc != null && !isUsernameOrEmailAttribute(attributeName) && UPConfigUtils.canBeAuthFlowContext(context) && sc.getScopes() != null && !sc.getScopes().isEmpty()) {
// for contexts executed from auth flow and with configured scopes selector
// we have to create correct predicate
selector = (c) -> requestedScopePredicate(c, sc.getScopes());
}
Map<String, Object> annotations = attrConfig.getAnnotations();
String attributeGroup = attrConfig.getGroup();
AttributeGroupMetadata groupMetadata = toAttributeGroupMeta(groupsByName.get(attributeGroup));
if (isUsernameOrEmailAttribute(attributeName)) {
if (permissions == null) {
writeAllowed = AttributeMetadata.ALWAYS_TRUE;
}
List<AttributeMetadata> atts = decoratedMetadata.getAttribute(attributeName);
if (atts.isEmpty()) {
// attribute metadata doesn't exist so we have to add it. We keep it optional as Abstract base
// doesn't require it.
decoratedMetadata.addAttribute(attributeName, guiOrder++, writeAllowed, validators).addAnnotations(annotations).setAttributeDisplayName(attrConfig.getDisplayName()).setAttributeGroupMetadata(groupMetadata);
} else {
final int localGuiOrder = guiOrder++;
// only add configured validators and annotations if attribute metadata exist
atts.stream().forEach(c -> c.addValidator(validators).addAnnotations(annotations).setAttributeDisplayName(attrConfig.getDisplayName()).setGuiOrder(localGuiOrder).setAttributeGroupMetadata(groupMetadata));
}
} else {
// always add validation for immutable/read-only attributes
validators.add(new AttributeValidatorMetadata(ImmutableAttributeValidator.ID));
decoratedMetadata.addAttribute(attributeName, guiOrder++, validators, selector, writeAllowed, required, readAllowed).addAnnotations(annotations).setAttributeDisplayName(attrConfig.getDisplayName()).setAttributeGroupMetadata(groupMetadata);
}
}
return decoratedMetadata;
}
Aggregations