[KEYCLOAK-18816] - Updates to User Profile

This commit is contained in:
Pedro Igor 2021-07-29 12:01:28 -03:00 committed by Stian Thorgersen
parent 34fcfb80a8
commit a1ac618f47
9 changed files with 221 additions and 38 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 64 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 39 KiB

View file

@ -2,7 +2,7 @@
=== User Profile
In {project_name} a user is associated with a set of attributes. These attributes are used to better describe and identify users within {project_name} as well as to pass over additional information to applications about them.
In {project_name} a user is associated with a set of attributes. These attributes are used to better describe and identify users within {project_name} as well as to pass over additional information about them to applications.
A user profile defines a well-defined schema for representing user attributes and how they are managed within a realm. By providing a consistent view over user information, it allows administrators to control the different aspects on how attributes are managed as well as to make a lot easier to extend {project_name} to support additional attributes.
@ -13,49 +13,65 @@ Among other capabilities, user profile enables administrators to:
* Define specific permissions for viewing and editing user attributes, making possible to adhere to strong privacy requirements where some attributes can not be seen or be changed by third-parties (including administrators)
* Dynamically enforce user profile compliance so that user information is always updated and in compliance with the metadata and rules associated with attributes
* Define validation rules on a per-attribute basis by leveraging the built-in validators or writing custom ones
* Dynamically render forms that users interact with like registration, update profile, brokering, and personal information in the account console, according to the attribute definitions and without any need to manually change themes.
The User Profile capabilities are backed by the User Profile SPI. By default, there are two providers you can choose from:
The User Profile capabilities are backed by the User Profile SPI. By default, these capabilities are disabled and realms are configured to use a default configuration that keeps backward compatibility with the legacy behavior.
* Legacy User Profile Provider (`legacy-user-profile`)
* Declarative User Profile Provider (`declarative-user-profile`)
[Note]
====
The legacy behavior is about keeping the default constraints used by {project_name} when managing users root attributes such as username, email, first and last name, without any restriction on how custom attributes are managed. Regarding user flows such as registration, profile update, brokering, and managing accounts through the account console, users are restricted to use the attributes aforementioned with the possibility to change theme templates to support additional attributes.
The legacy provider is enabled by default, and it provides a basic user profile configuration based on the user root attributes such as e-mail, first and last names.
If you are already using {project_name}, the legacy behavior is what you have been using so far.
====
On the other hand, the declarative provider gives you a lot more flexibility to define the user profile configuration to a realm through the administration console and a well-defined JSON schema.
Differently than the legacy behavior, the declarative provider gives you a lot more flexibility to define the user profile configuration to a realm through the administration console and a well-defined JSON schema.
In the next sections, we'll be looking at how to use the declarative provider to define your own user profile configuration.
[NOTE]
====
In the future, the `declarative-user-profile` provider is going to replace the legacy provider and become the default.
In the future, the legacy behavior will no longer be supported on {project_name}. Ideally, you should start looking at the new capabilities provided by the User Profile and migrate your realms accordingly.
====
==== Enabling the Declarative User Profile
==== Enabling the User Profile
:tech_feature_name: Declarative User Profile
:tech_feature_setting: -Dkeycloak.profile.feature.declarative_user_profile=enabled
include::../templates/techpreview.adoc[]
In addition to enabling the `declarative_user_profile` feature, you should use the link:{installguide_link}#_start_cli[CLI] to set the `declarative-user-profile` provider as the default provider as follows:
In addition to enabling the `declarative_user_profile` feature, you should enable User Profile to a realm. For that, click on the `Realm Settings` link on
the left side menu and then turn on the `User Profile Enabled` switch.
[source]
----
$ /subsystem=keycloak-server/spi=userProfile:add(default-provider=declarative-user-profile)
----
image:{project_images}/user-profile-enabling.png[]
After setting the default provider, make sure to restart the server.
Once you enable it and click on the `Save` button, you should be able to access the `User Profile` tab from where you can manage the configuration for user attributes.
By enabling the user profile to a realm, {project_name} is going to impose additional constraints on how attributes are managed based on the user profile configuration. In summary, here is the list of what you should expect when the feature is enabled:
* From an administration point of view, the `Attributes` tab at the user details page will only show the attributes defined in the user profile configuration. The conditions defined on a per-attribute basis will also be taken into account when managing attributes.
* User facing forms like registration, update profile, brokering, and personal info in the account console, are going to be rendered dynamically based on the user profile configuration. For that, {project_name} is going to rely on different templates to render these forms dynamically.
In the next topics, we'll be exploring how to manage the user profile configuration and how does it affect your realm.
==== Managing the User Profile
The user profile configuration is managed on a per-realm basis. For that, click on the
`Realm Settings` link on the left side menu and then click on the `User Profile` tab.
.User Profile Attributes
image:{project_images}/user-profile-attributes.png[]
.User Profile Tab
image:{project_images}/user-profile-tab.png[]
In the `Attributes` sub-tab you have a list of the attributes currently associated with the user profile. By default, {project_name} uses a configuration based on the user root attributes and very similar to the configuration used by the legacy provider.
In the `Attributes` sub-tab you have a list of the attributes currently associated with the user profile. By default, the configuration is created based on the user root attributes and each attribute is configured with some defaults in terms of validation and permissioning.
In the `JSON Editor` sub-tab you can view and edit the configuration using a well-defined JSON schema.
In the `Attribute Groups` sub-tab you can manage attribute groups. An attribute group allows you to correlate attributes so that they are displayed together when rendering user facing forms.
[NOTE]
====
For now, attribute groups are only used for rendering purposes but in the future they should also enable defining top-level configurations to the attributes they are linked to.
====
In the `JSON Editor` sub-tab you can view and edit the configuration using a well-defined JSON schema. Any change you make when at any other tab should be reflected in the JSON configuration shown at this tab.
In the next section, you are going to learn how to manage the configuration from the `Attributes` sub-tab.
@ -71,21 +87,31 @@ image:{project_images}/user-profile-create-attribute.png[]
When configuring the attribute you should be able to define the following settings:
Name::
The name of the attribute. This setting is required.
The name of the attribute.
Display name::
A user-friendly name for the attribute, mainly used when rendering user-facing forms. It supports internationalization so that values can be loaded from message bundles.
Attribute Group::
The attribute group to which the attribute belongs to, if any.
Enabled when scope::
Allows you to define a list of scopes to dynamically enable an attribute. If not set, the attribute is always enabled and its constraints are always enforced when managing user profiles as well as when rendering user-facing forms. Otherwise, the same constraints only apply when any of the scopes in the list is requested by clients.
Required::
Set the attribute as required. If enabled, the attribute must be set by users and administrators. Otherwise, the attribute is optional.
Set the attribute as required. If not enabled, the attribute is optional. Otherwise, the attribute must be provided by users and administrators with the possibility to also make the attribute required only for users or administrators as well as based on the scopes requested by clients.
Permission::
In this section, you can define read and write permissions for users and administrators.
Validation::
In this section, you can define custom validations when updating the attribute.
In this section, you can define the validations that should be performed when managing the attribute value. {project_name} provides a set of built-in validators you can choose from with the possibility to add your own.
Annotation::
In this section, you can associate annotations to the attribute.
In this section, you can associate annotations to the attribute. Annotations are mainly useful to pass over additional metadata to frontends for rendering purposes.
==== Managing Permissions
===== Managing Permissions
In the `Permission` section, you can define the level of access users and administrators have to read and write to an attribute.
@ -106,7 +132,22 @@ If enabled, administrators can view the attribute. Otherwise, administrators don
Can admin edit?::
If enabled, administrators can view and edit the attribute. Otherwise, administrators don't have access to write to the attribute.
==== Managing Validations
[NOTE]
====
When you create an attribute, no permission is set to the attribute. Effectively, the attribute won't be accessible by either users or administrators. Once you create the attribute, make sure to set the permissions accordingly to that the attribute is only visible by the target audience.
====
Permissioning has a direct impact on how and who can manage the attribute, as well as on how the attribute is rendered in user-facing forms.
For instance, by marking an attribute as only viewable by users, the administrators won't have access to the attribute when managing users through the administration console (neither from the User API). Also, users won't be able to change the attribute when updating their profiles. An interesting configuration if user attributes are fetched from an existing identity store (federation) and you just want to make attributes visible to users without any possibility to update the attribute other than through the source identity store.
Similarly, you can also mark an attribute as writable only for administrators with read-only access for users. In this case, only administrators are going to be allowed to manage the attribute.
Depending on your privacy requirements, you might also want attributes inaccessible to administrators but with read-write permissions for users.
Make sure to set the correct permissions whenever you add a new attribute to the user profile configuration.
===== Managing Validations
In the `Validation` section, you can choose from different forms of validation to make sure the attribute value conforms to specific rules.
@ -115,40 +156,73 @@ image:{project_images}/user-profile-validation.png[]
{project_name} provides different validators out of the box:
[cols="2*", options="header"]
[cols="3*", options="header"]
|===
|Name
|Description
|not-empty
|Check that input value is not empty. It means it is not null for all data types.
|not-blank
|Check that a string value is not empty. It means it is not null nor empty.
|Configuration
|length
|Check the length of a string value based on a minimum and maximum length.
|
*min*: an integer to define the minimum allowed length.
*max*: an integer to define the maximum allowed length.
*trim-disabled*: a boolean to define whether the value should be trimmed prior to validation.
|integer
|Check if the value is an integer.
|Check if the value is an integer and within a lower and/or upper range. If no range is defined, the validator only checks whether the value is a valid number.
|
*min*: an integer to define the lower range.
*max*: an integer to define the upper range.
|double
|Check if the value is a number.
|Check if the value is a double and within a lower and/or upper range. If no range is defined, the validator only checks whether the value is a valid number.
|
*min*: an integer to define the lower range.
*max*: an integer to define the upper range.
|uri
|Check if the value is a valid URI.
| None
|pattern
|Check if the value matches a specific RegEx pattern.
|
*pattern*: the RegEx pattern to use when validating values.
*error-message*: the key of the error message in i18n bundle. If not set a generic message is used.
|email
|Check if the value has a valid e-mail format.
| None
|local-date
|Check if the value has a valid format based on the realm and/or user locale.
| None
|person-name-prohibited-characters
| Check if the value is a valid person name as an additional barrier for attacks such as script injection. The validation is based on a default RegEx pattern that blocks characters not common in person names.
|
*error-message*: the key of the error message in i18n bundle. If not set a generic message is used.
|username-prohibited-characters
| Check if the value is a valid username as an additional barrier for attacks such as script injection. The validation is based on a default RegEx pattern that blocks characters not common in usernames.
|
*error-message*: the key of the error message in i18n bundle. If not set a generic message is used.
|===
==== Managing Annotations
===== Managing Annotations
In order to pass additional information to frontends, attributes can be decorated with
annotations to dictate how attributes should be rendered. This capability is mainly useful when extending {project_name} themes to render pages dynamically based on the annotations associated with attributes.
@ -156,6 +230,37 @@ annotations to dictate how attributes should be rendered. This capability is mai
.Attribute Annotation
image:{project_images}/user-profile-annotation.png[]
==== Managing Attribute Groups
At the `Attribute Grousp` sub-tab you should be able to create, edit, and delete attribute groups. An attribute group allows you to define a container for correlated attributes so that they are rendered together when at the user-facing forms.
.Attribute Group List
image:{project_images}/user-profile-attribute-group-list.png[]
[NOTE]
====
You can't delete attribute groups that are bound to attributes. For that, you should first update the attributes to remove the binding.
====
To create a new group, click on the `Create` button in the top-right corner of the attribute groups listing.
.Attribute Group Configuration
image:{project_images}/user-profile-create-attribute-group.png[]
When configuring the group you should be able to define the following settings:
Name::
The name of the group.
Display name::
A user-friendly name for the group, mainly used when rendering user-facing forms. It supports internationalization so that values can be loaded from message bundles.
Display description::
A user-friendly text that should be displayed as a tooltip when rendering user-facing forms.
Annotation::
In this section, you can associate annotations to the attribute. Annotations are mainly useful to pass over additional metadata to frontends for rendering purposes.
==== Using the JSON Configuration
The user profile configuration is stored using a well-defined JSON schema. You can choose from editing the user profile configuration directly by clicking on the `JSON Editor` sub-tab.
@ -179,10 +284,22 @@ The JSON schema is defined as follows:
"view": [ "admin", "user" ],
"edit": [ "admin", "user" ]
},
"validations": {
"email": {},
"length": {
"max": 255
}
},
"annotations": {
"myannotation": "myannotation-value"
}
}
],
"groups": [
{
"name": "personalInfo",
"displayHeader": "Personal Information"
}
]
}
----
@ -284,20 +401,86 @@ The attribute-level `annotation` property can be used to associate additional me
}
----
==== Verifying User Profile
==== Using Dynamic Forms
One of the main capabilities of User Profile is the possibility to dynamically render user-facing forms based on attributes metadata. When you have the feature enabled to your realm, forms like registration and update profile are rendered using specific theme templates to dynamically render pages based on the user profile configuration.
That said, you shouldn't need to customize templates at all if the default rendering mechanisms serves to your needs. In case you still need customizations to themes, here are the templates you should be looking at:
[cols="2*", options="header"]
|===
|Template
|Description
| base/login/update-user-profile.ftl
| The template that renders the update profile page.
| base/login/register-user-profile.ftl
| The template that renders the registration page.
| base/login/idp-review-user-profile.ftl
| The template that renders the page to review/update the user profile when federating users through brokering.
|===
The default rendering mechanism provides the following capabilities:
* Dynamically display fields based on the permissions set to attributes.
* Dynamically render markers for required fields based on the constraints set to the attributes.
* Dynamically render read-only fields depending on the permissions set to an attribute.
* Dynamically order fields depending on the order set to the attributes.
* Dynamically group fields that belong to a same attribute group.
===== Ordering Attributes
The attributes order is set by clicking on the up and down arrows when at the attribute listing page.
.Ordering Attributes
image:{project_images}/user-profile-attribute-list-order.png[]
The order you set in this page should be respected when fields are rendered in dynamic forms.
===== Grouping Attributes
When dynamic forms are rendered, they will try to group together attributes that belong to a same attribute group.
.Dynamic Update Profile Form
image:{project_images}/user-profile-update-profile.png[]
[NOTE]
====
When attributes are linked to an attribute group, the attribute order is also important to make sure attributes within the same group are close together, within a same group header. Otherwise, if attributes within a group do not have a sequential order you might have the same group header rendered multiple times in the dynamic form.
====
==== Forcing User Profile Compliance
In order to make sure user profiles are in compliance with the configuration, administrators may use the `VerifyProfile` required action to eventually force users to update their profiles when authenticating to {project_name}.
[NOTE]
====
The `VerifyProfile` action is similar to the `UpdateProfile` action. However, it leverages all the capabilities provided by the user profile to automatically enforce compliance with the user profile configuration.
====
When enabled, the `VerifyProfile` action is going to perform the following steps when the user is authenticating:
* Check whether the user profile is fully compliant with the user profile configuration set to the realm.
* If not, perform an additional step during the authentication so that the user can update his/her profile.
* If not, perform an additional step during the authentication so that the user can update any missing or invalid attribute.
* If the user profile is compliant with the configuration, no additional step is performed, and the user continues with the authentication process.
The `VerifyProfile` action is similar to the `UpdateProfile`. However, it leverages all the capabilities provided by the user profile configuration to dynamically render the attributes defined in the user profile configuration.
By default, the `VerifyProfile` action is disabled. To enabled it, click on the
`Authentication` link on the left side menu and then click on the `Required Actions` tab. At this tab, click on the `Register` button and select the `VerifyProfile` action.
.Registring the VerifyProfile Required Action
image:{project_images}/user-profile-register-verify-profile-action.png[]
==== Migrating to User Profile
Before enabling the User Profile capabilities to a realm, there are some important considerations you should be aware of. By providing a single place to manage attribute metadata, the feature is very strict about the attributes that can be set to users and how they are managed.
In terms of user management, administrators should be able to manage only the attributes defined in the user profile configuration. Any other attribute set to the user and not yet defined in the user profile configuration won't be accessible. It is recommended to update your user profile configuration with all the user attributes you want to expose either to users or administrators.
The same recommendation applies for those accessing the User REST API to query user information.
In regards to {project_name} internal user attributes such as `LDAP_ID`, `LDAP_ENTRY_DN`, or `KERBEROS_PRINCIPAL`, if you want to be able to access those attributes you should have them as attributes in your user profile configuration. The recommendation is to mark these attributes as viewable only to administrators so that you can look at them when managing the user attributes through the administration console or querying users via User API.
In regards to theming, if you already have customizations to the legacy templates (those hardcoded with user root attributes) your custom templates won't be used when rendering user-facing forms but the new templates that render these forms dynamically. Ideally, you should avoid having any customizations to templates and try to stick with the behavior provided by these new templates to dynamically render forms for you. If they are still not enough to address your requirements, you can either customize them or provide us with any feedback so that we discuss whether it makes sense to enhance the new templates.