diff --git a/server_development/topics/user-storage.adoc b/server_development/topics/user-storage.adoc index cd9fdfe985..1f0d36ce11 100644 --- a/server_development/topics/user-storage.adoc +++ b/server_development/topics/user-storage.adoc @@ -1,7 +1,7 @@ [[_user-storage-spi]] == User Storage SPI -You can use the User Storage SPI to write extensions to {project_name} to connect to external user databases and credential stores. The built-in LDAP and ActiveDirectory support is an implementation of this SPI in action. Out of the box, {project_name} uses its local database to create, update, and look up users and validation credentials. Often though, organizations have existing external proprietary user databases that they cannot migrate to {project_name}'s data model. For those situations, application developers can write implementations of the User Storage SPI to bridge the external user store and the internal user object model that {project_name} uses to log in users and manage them. +You can use the User Storage SPI to write extensions to {project_name} to connect to external user databases and credential stores. The built-in LDAP and ActiveDirectory support is an implementation of this SPI in action. Out of the box, {project_name} uses its local database to create, update, and look up users and validate credentials. Often though, organizations have existing external proprietary user databases that they cannot migrate to {project_name}'s data model. For those situations, application developers can write implementations of the User Storage SPI to bridge the external user store and the internal user object model that {project_name} uses to log in users and manage them. When the {project_name} runtime needs to look up a user, such as when a user is logging in, it performs a number of steps to locate the user. It first looks to see if the user is in the user cache; if the user is found it uses that in-memory representation. Then it looks for the user within the {project_name} local database. If the user is not found, it then loops through User Storage SPI provider implementations to perform the user query until one of them returns the user the runtime is looking for. The provider queries the external user store for the user and maps the external data representation of the user to {project_name}'s user metamodel. diff --git a/server_development/topics/user-storage/augmenting.adoc b/server_development/topics/user-storage/augmenting.adoc index 77d0a11000..9338430b24 100644 --- a/server_development/topics/user-storage/augmenting.adoc +++ b/server_development/topics/user-storage/augmenting.adoc @@ -1,7 +1,7 @@ === Augmenting External Storage -The `PropertyProfileUserStorageProvider` example is really limited. While we will be able to login with users stored +The `PropertyFileUserStorageProvider` example is really limited. While we will be able to login with users stored in a property file, we won't be able to do much else. If users loaded by this provider need special role or group mappings to fully access particular applications there is no way for us to add additional role mappings to these users. You also can't modify or add additional important attributes like email, first and last name. diff --git a/server_development/topics/user-storage/cache.adoc b/server_development/topics/user-storage/cache.adoc index 6f247d2568..45f536f9e8 100644 --- a/server_development/topics/user-storage/cache.adoc +++ b/server_development/topics/user-storage/cache.adoc @@ -1,9 +1,9 @@ === User Caches -When a user is loaded by ID, username, or email queries it is cached. When a user is cached, it iterates through +When a user object is loaded by ID, username, or email queries it is cached. When a user object is bing cached, it iterates through the entire `UserModel` interface and pulls this information to a local in-memory-only cache. In a cluster, this cache -is still local, but it becomes an invalidation cache. When a user is modified, it is evicted. This eviction event +is still local, but it becomes an invalidation cache. When a user object is modified, it is evicted. This eviction event is propagated to the entire cluster so that the other nodes' user cache is also invalidated. ==== Managing the user cache diff --git a/server_development/topics/user-storage/configuration.adoc b/server_development/topics/user-storage/configuration.adoc index fcbad4f2a9..29d02f514b 100644 --- a/server_development/topics/user-storage/configuration.adoc +++ b/server_development/topics/user-storage/configuration.adoc @@ -1,7 +1,7 @@ === Configuration Techniques -Our `PropertyFileUserStorageProvider` example is bit contrived. It is hardcoded to a property file that is embedded in the jar of the provider. Not very useful at all. We might want to make the location of this file configurable per instance of the provider. In other words, we might want to reuse this provider mulitple times in multiple different realms and point to completely different user property files. We'll also want to perform this configuration within the administration console UI. +Our `PropertyFileUserStorageProvider` example is bit contrived. It is hardcoded to a property file that is embedded in the jar of the provider, which is not terribly useful. We might want to make the location of this file configurable per instance of the provider. In other words, we might want to reuse this provider mulitple times in multiple different realms and point to completely different user property files. We'll also want to perform this configuration within the administration console UI. The `UserStorageProviderFactory` has additional methods you can implement that handle provider configuration. You describe the variables you want to configure per provider and the administration console automatically renders a generic input page to gather this configuration. When implemented, callback methods also validate the configuration before it is saved, when a provider is created for the first time, and when it is updated. `UserStorageProviderFactory` inherits these methods from the `org.keycloak.component.ComponentFactory` interface. diff --git a/server_development/topics/user-storage/import.adoc b/server_development/topics/user-storage/import.adoc index f47adfa24d..1add6a4ec0 100644 --- a/server_development/topics/user-storage/import.adoc +++ b/server_development/topics/user-storage/import.adoc @@ -16,7 +16,7 @@ There are some obvious disadvantages though to using an import strategy: * Looking up a user for the first time will require multiple updates to {project_name} database. This can be a big performance loss under load and put a lot of strain on the {project_name} database. The user federated storage approach will only store extra data as needed and may never be used depending on the capabilities of your external store. -* With the import approach, you have to keep local keycloak storage and external storage in sync. The User Storage SPI +* With the import approach, you have to keep local {project_name} storage and external storage in sync. The User Storage SPI has capability interfaces that you can implement to support synchronization, but this can quickly become painful and messy. To implement the import strategy you simply check to see first if the user has been imported locally. If so return the @@ -51,7 +51,7 @@ begin first by modifying the `createAdapter()` method. In this method we call the `KeycloakSession.userLocalStorage()` method to obtain a reference to local {project_name} user storage. We see if the user is stored locally, if not, we add it locally. Do not set the `id` of the local user. -Let {project_name} set auto generate the `id`. Also note that we call +Let {project_name} automatically generate the `id`. Also note that we call `UserModel.setFederationLink()` and pass in the ID of the `ComponentModel` of our provider. This sets a link between the provider and the imported user. diff --git a/server_development/topics/user-storage/javaee.adoc b/server_development/topics/user-storage/javaee.adoc index cea2b78401..deee30279e 100644 --- a/server_development/topics/user-storage/javaee.adoc +++ b/server_development/topics/user-storage/javaee.adoc @@ -53,7 +53,7 @@ not proxy the user correctly and your provider won't work. You must put the `@Remove` annotation on the `close()` method of your provider. If you do not, the stateful bean will never be cleaned up and you might eventually see error messages. -Implementations of `UserStorageProviderFactory` are required to be plain java objects. Your factory class would +Implementations of `UserStorageProvider` are required to be plain Java objects. Your factory class would perform a JNDI lookup of the Stateful EJB in its create() method. [source,java] @@ -81,9 +81,7 @@ file as well as any JPA `@Entity` classes. WARNING: When using JPA any additional datasource must be an XA datasource. The {project_name} datasource is not an XA datasource. If you interact with two or more non-XA datasources in the same transaction, the server returns - an error message. Only one non-XA resource is permitted in a single transaction. - -See the {appserver_name} manual for more details on deploying an XA datasource. + an error message. Only one non-XA resource is permitted in a single transaction. See the {appserver_name} manual for more details on deploying an XA datasource. CDI is not supported. diff --git a/server_development/topics/user-storage/migration.adoc b/server_development/topics/user-storage/migration.adoc index be2dda0509..db280c74d4 100644 --- a/server_development/topics/user-storage/migration.adoc +++ b/server_development/topics/user-storage/migration.adoc @@ -4,7 +4,7 @@ NOTE: This chapter is only applicable if you have implemented a provider using the earlier (and now removed) User Federation SPI. -In Keycloak version 2.4.0 and earlier there was a User Federation SPI. Red Hat Single Sign-On version 7.0, although unsupported, also had +In Keycloak version 2.4.0 and earlier there was a User Federation SPI. Red Hat Single Sign-On version 7.0, although unsupported, had this earlier SPI available as well. This earlier User Federation SPI has been removed from Keycloak version 2.5.0 and Red Hat Single Sign-On version 7.1. However, if you have written a provider with this earlier SPI, this chapter discusses some strategies you can use to port it. @@ -28,7 +28,7 @@ There are some obvious disadvantages though to using an import strategy: * Looking up a user for the first time will require multiple updates to {project_name} database. This can be a big performance loss under load and put a lot of strain on the {project_name} database. The user federated storage approach will only store extra data as needed and might never be used depending on the capabilities of your external store. -* With the import approach, you have to keep local keycloak storage and external storage in sync. The User Storage SPI +* With the import approach, you have to keep local {project_name} storage and external storage in sync. The User Storage SPI has capability interfaces that you can implement to support synchronization, but this can quickly become painful and messy. ==== UserFederationProvider vs. UserStorageProvider @@ -44,7 +44,7 @@ Also note that in the earlier SPI, this method was called every time the user wa In the later SPI, this method is only called when the local user is loaded from local storage. If the local user is cached, then the `ImportedUserValidation.validate()` method is not called at all. -The `UserFederationProvider.isValid()` method no longer exists in the later model. +The `UserFederationProvider.isValid()` method no longer exists in the later SPI. The `UserFederationProvider` methods `synchronizeRegistrations()`, `registerUser()`, and `removeUser()` have been moved to the `UserRegistrationProvider` capability interface. This new interface is optional to implement so if your @@ -80,8 +80,8 @@ with the same provider ID (i.e., "ldap", "kerberos") as the earlier User Federat So, knowing this there are different approaches you can take. -. You can remove the earlier provider in your earlier {project_name} deployment. This will remove all local linked copies - of imported users. Then, when you upgrade {project_name}, just deploy and configure your new provider for your realm. +. You can remove the earlier provider in your earlier {project_name} deployment. This will remove thedd local linked copies + of all users you imported. Then, when you upgrade {project_name}, just deploy and configure your new provider for your realm. . The second option is to write your new provider making sure it has the same provider ID: `UserStorageProviderFactory.getId()`. Make sure this provider is in the `deploy/` directory of the new {project_name} installation. Boot the server, and have the built-in migration script convert from the earlier data model to the later data model. In this case all your earlier linked imported diff --git a/server_development/topics/user-storage/provider-interfaces.adoc b/server_development/topics/user-storage/provider-interfaces.adoc index 0f0070e3ca..62c0680a4f 100644 --- a/server_development/topics/user-storage/provider-interfaces.adoc +++ b/server_development/topics/user-storage/provider-interfaces.adoc @@ -66,7 +66,7 @@ package org.keycloak.storage; public interface UserStorageProviderFactory extends ComponentFactory { /** - * This is the name of the provider and will be showed in the admin console as an option. + * This is the name of the provider and will be shown in the admin console as an option. * * @return */ @@ -102,10 +102,10 @@ public class FileProviderFactory implements UserStorageProviderFactory