[keycloak-dev] creating JPA user storage provider difficult

Marek Posolda mposolda at redhat.com
Thu Aug 4 09:56:43 EDT 2016


On 04/08/16 15:10, Bill Burke wrote:
>
>
> On 8/4/16 4:00 AM, Marek Posolda wrote:
>> On 04/08/16 01:48, Bill Burke wrote:
>>> I wrote an JPA example for the new User Storage Provider SPI [1].  It
>>> was very difficult to figure out how to wire in JPA.  I'm going to take
>>> a guess that very very few users have actually tried to implement a
>>> JPA-based User Federation Provider.  They would have run into a ton of
>>> hurdles.
>>>
>>> * Putting just a jar within the "providers/" directory is unusable.  
>>> JPA
>>> classes and other dependencies will not be visible.
>>>
>>> * So, you have to craft a *CORRECT* module.xml file and know exactly
>>> which dependencies to bring in. [2]
>>>
>>> * javax.persistence.Persistence.createEntityManagerFactory() did not
>>> work, so I had to call Hibernate APIs directly.  Not only that, but
>>> non-simple Hibernate APIs. [3]
>>>
>>> * When configuring JPA I also had to know what classloader to use so
>>> that persistence.xml was visible.
>> In some recent release, we added JpaEntityProvider SPI. This allows 
>> to register your own JPA entities with Keycloak own EntityManager . 
>> So in your provider, you don't need to care about the complex stuff 
>> like proprietary Hibernate API, classloader or transaction enlisting.
>>
>
> The  JpaEntityProvider SPI extends the keycloak persistence unit. Not 
> very useful if you are integrating some other external RDBMs.
yep, true.
>
>> We have a docs [1] and example for that [2]
>>
>> [1] 
>> https://keycloak.gitbooks.io/server-developer-guide/content/v/2.1/topics/extensions.html
>> [2] 
>> https://github.com/patriot1burke/keycloak/tree/master/examples/providers/domain-extension 
>>
>>
>> That's much easier, isn't it? Just not sure if it helps with EJB...
>
> Easier if you don't need any other dependency defined.  What if they 
> want to JAX-RS client and a specific provider from Resteasy? As I 
> mentioned in a previous point, its just not as simple as including the 
> modules.  Persistence.createEMF() doesn't work as the classloaders all 
> seem confused.
Yep, so we can address this with some sort of "deployer" you proposed, 
which will have automatically access to JEE APIs, so people won't need 
to declare dependencies on them anywhere? Still people always need to 
deal with modules though, if they don't want just JEE, but also some 
other different 3rd party dependencies...
>>> * Had to use JpaKeycloakTransaction to enlist EntityManager with
>>> keycloak transactions.  This means using EJBs is out of the question.
>>>
>>> This is unacceptable.  Keycloak is supposed to be simple and this is
>>> extremely difficult.  When Keycloak was an exploded WAR you could use
>>> every Java EE component type as you could just plop your extensions
>>> within META-INF/lib.  Classloading was simple as it was all the same
>>> classloader.
>>>
>>> Going forward we need to write an actual deployer for Keycloak
>>> extensions that allow you to define Keycloak providers within EE jars,
>>> ears, etc.  Writing an extension to Keycloak should be as easy as
>>> writing a Java EE application.  Extension developers should be able to
>>> leverage the entire JBoss/Wildfly platform. Minimally, we also need to
>>> begin and commit/rollback a UserTransaction within a Keycloak request
>>> flow so that transaction EE and Spring component layers can function.
>> +1 for deployer. Maybe we can try to prototype an example, which uses 
>> stuff like EJB and then see what exactly we need to add?
>>
>> For UserTransaction, we can maybe have the KeycloakTransaction 
>> implementation, which will delegate to UserTransaction? Then people 
>> can optionally enlist it in their provider if they need it :
>>
>> session.getTransactionManager().enlistAfterCompletion(new 
>> UserTransactionWrapper());
>>
>> Then Keycloak will automatically take care of commit/rollback this 
>> transaction at end of request.
> Why wouldn't they just use UserTransaction?
In case that KeycloakTransaction is rolled back, then it calls rollback 
to all the enlisted delegates. So enlisted UserTransactionWrapper will 
then call UserTransaction.rollback as well.

Unless we're going to rewrite our transaction API to use JTA? That will 
automatically integrate with JPA and infinispan. If people needs to 
enlist their own transaction, they need to implement 
javax.transaction.xa.XAResource. This looks slightly more complicated 
then implement our KeycloakTransaction, but on the other hand, it's a 
standard.

Marek
>
> Bill



More information about the keycloak-dev mailing list