Update of the Server Development doc about how 'User Storage Providers' must adhere to Quarkus.

Closes #19156
This commit is contained in:
Andre Nascimento 2023-05-23 11:53:21 +02:00 committed by Bruno Oliveira da Silva
parent 90d2a01619
commit c8d418d50b

View file

@ -1,87 +1,16 @@
=== Leveraging Jakarta EE
The user storage providers can be packaged within any Jakarta EE component if you set up the `META-INF/services`
file correctly to point to your providers. For example, if your provider needs to use third-party libraries, you
can package up your provider within an EAR and store these third-party libraries in the `lib/` directory of the EAR.
Also note that provider JARs can make use of the `jboss-deployment-structure.xml` file that EJBs, WARS, and EARs
can use in a {appserver_name} environment. For more details on this file, see the {appserver_name} documentation. It
allows you to pull in external dependencies among other fine-grained actions.
Since version 20, Keycloak relies only on Quarkus. Unlike WildFly, Quarkus is not an Application Server. For more detail, see https://www.keycloak.org/migration/migrating-to-quarkus#_quarkus_is_not_an_application_server.
Provider implementations are required to be plain java objects. But we also currently support
implementing `UserStorageProvider` classes as Stateful EJBs. This is especially useful if you want to use JPA
to connect to a relational store. This is how you would do it:
Therefore, the User Storage Providers cannot be packaged within any Jakarta EE component or make it an EJB as was the case when Keycloak ran over WildFly in previous versions.
[source,java]
----
@Stateful
@Local(EjbExampleUserStorageProvider.class)
public class EjbExampleUserStorageProvider implements UserStorageProvider,
UserLookupProvider,
UserRegistrationProvider,
UserQueryProvider,
CredentialInputUpdater,
CredentialInputValidator,
OnUserCache
{
@PersistenceContext
protected EntityManager em;
Providers implementations are required to be plain java objects which implement the suitable User Storage SPI interfaces, as was explained in the previous sections. And they must be packaged and deployed as stated in this Migration Guide:
protected ComponentModel model;
protected KeycloakSession session;
- https://www.keycloak.org/migration/migrating-to-quarkus#_migrating_custom_providers
public void setModel(ComponentModel model) {
this.model = model;
}
You can still implement your custom `UserStorageProvider` class, which is able to integrate an external database by JPA Entity Manager, as shown in this example:
public void setSession(KeycloakSession session) {
this.session = session;
}
@Remove
@Override
public void close() {
}
...
}
----
You have to define the `@Local` annotation and specify your provider class there. If you do not do this, EJB will
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 `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]
----
public class EjbExampleUserStorageProviderFactory
implements UserStorageProviderFactory<EjbExampleUserStorageProvider> {
@Override
public EjbExampleUserStorageProvider create(KeycloakSession session, ComponentModel model) {
try {
InitialContext ctx = new InitialContext();
EjbExampleUserStorageProvider provider = (EjbExampleUserStorageProvider)ctx.lookup(
"java:global/user-storage-jpa-example/" + EjbExampleUserStorageProvider.class.getSimpleName());
provider.setModel(model);
provider.setSession(session);
return provider;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
----
This example also assumes that you have defined a JPA deployment in the same JAR as the provider. This means a `persistence.xml`
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.
- https://github.com/keycloak/keycloak-quickstarts/tree/latest/user-storage-jpa
CDI is not supported.