Update of the Server Development doc about how 'User Storage Providers' must adhere to Quarkus.
Closes #19156
This commit is contained in:
parent
90d2a01619
commit
c8d418d50b
1 changed files with 6 additions and 77 deletions
|
@ -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.
|
||||
|
||||
|
|
Loading…
Reference in a new issue