Skip to content

Realms Map JPA implementation#10901

Merged
hmlnarik merged 2 commits intokeycloak:mainfrom
sguilhen:9661-realm-jpa-store
Apr 20, 2022
Merged

Realms Map JPA implementation#10901
hmlnarik merged 2 commits intokeycloak:mainfrom
sguilhen:9661-realm-jpa-store

Conversation

@sguilhen
Copy link
Copy Markdown
Contributor

@sguilhen sguilhen commented Mar 23, 2022

Closes #9661
Closes #11070

@sguilhen sguilhen added area/storage Indicates an issue that touches storage (change in data layout or data manipulation) team/storage-sig labels Mar 23, 2022
@sguilhen
Copy link
Copy Markdown
Contributor Author

Opening as draft because I'm still testing locally

Copy link
Copy Markdown
Contributor

@vramik vramik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @sguilhen for the PR. Looks great! I have just one question, please see inline.

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch from 6f7358a to 1890c2f Compare March 25, 2022 13:12
Comment thread model/map-jpa/src/main/resources/META-INF/realms/jpa-realms-changelog-1.xml Outdated
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this search supported by any index?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, inverted index was added for the components

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this search supported by any index?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, inverted index was added for client initial accesses

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch 5 times, most recently from c188345 to a1841e0 Compare April 1, 2022 14:29
@sguilhen sguilhen marked this pull request as ready for review April 1, 2022 14:32
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UUID ids are being enforced only when the map storage is enabled as it was not a requirement for the legacy storage. We need to decide if we simply convert non-conforming ids automatically as the code above is doing, or if we want to throw a validation error.

Conversion is essential to be able to support importing legacy realms as those will come with the previously exported id, which can be a non-UUID string. We may, however, introduce a system property so that users can enforce UUIDs if they want to. Something like "keycloak.map_storage.reject_invalid_ids" which would be false by default, but can be turned on to make the above block throw an exception instead. Thoughts?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the configuration option would be nice. I agree with the proposed solution to have it by default set to false and throw an exception when set to true. On top of that I think we should add a warning which would alert a user that the id of realm is going to be changed.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Incorporated all these suggestions. For now I'm using a config property from the map storage, but it can be switched into something else, like a system property.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry that I'm late for this discussion: For the LDAP store, all IDs are determined by the LDAP server as GUIDs, so all ids passed in by Keycloak will be replaced in the returned entity with a GUID.

The automatic conversion is therefore correct IMHO. Thinking about configuration, there having an automatic conversion is what is expected from a map store as it is allowed to treat any passed in ID as a mere suggestion.

I would even go so far to make it non-configurable and also to not log a warning unless you have a scenario in mind where the conversion could break an existing behavior.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That makes sense, @ahus1, thanks for sharing your thoughts. I've changed the code so no warning is printed and no exception is thrown, JPA store simply converts non-compliant ids into UUIDs.

Comment thread services/src/main/java/org/keycloak/services/managers/RealmManager.java Outdated
@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch from a1841e0 to 8a9fe94 Compare April 1, 2022 17:52
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the configuration option would be nice. I agree with the proposed solution to have it by default set to false and throw an exception when set to true. On top of that I think we should add a warning which would alert a user that the id of realm is going to be changed.

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch 2 times, most recently from d820d2c to c9c338f Compare April 5, 2022 03:36
Comment thread model/map/src/main/java/org/keycloak/models/map/realm/MapRealmAdapter.java Outdated
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The JavaDoc states "Internal ID of the realm or null if one is to be created by the underlying store" for the id attribute. Please consider changing the JavaDoc to indicate that the storage might overwrite/change the ID at its own discretion.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated the javadoc.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 for the javadoc. Actually I don't agree with the throwing an exception, it should always create a new one.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Based on the other comments I'll remove the exception part.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done, javadoc updated.

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch 2 times, most recently from 516907b to b752c8e Compare April 5, 2022 18:40
Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just thinking a bit more about this validation/conversion of ids into UUIDs for the JPA storage.. using a config property from the mapStorage does feel a bit misplaced as other storage impls might not have this hard requirement of ids being UUIDs.

Perhaps we should have this rejectInvalidIds config in the jpa-map-storage instead and inject its value into the created transactions. The transaction's create method can then run the validateAndConvert method using the flag that signals if an exception should be thrown or if the invalid id should be simply converted into an UUID.

Thoughts?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the UUIDs are a requirement for the map storage in general, then maybe the approach of using a config in mapStorage directly is not displaced at all.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given the example of LDAP, the UUIDs are no requirement across all map storages. A store might decide to create IDs differently, and as long as they are a String they are fine to do so. Having a UUID might be default for Keycloak, and the only supported way for JPA, but this won't hold true for all map storages.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1 to what @ahus1 wrote.

Also: can rejectInvalidIds ever be false? Wouldn't passing in an invalid ID result in an exception from the store later upon saving the object?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ahus1 @hmlnarik Ok, so based on the discussion the conclusion is that the store has the freedom to convert ids at its own discretion, treating any supplied id as a suggestion. In that case, I should remove the id validation/conversion from the MapRealmProvider and MapRealmAdapter and move it to the JPA transaction create method. The reason being that converting at the logical layer is meaningless if other store, like LDAP, will have to convert it again.

In JPA, once the store is invoked to create an entity it can validate if the incoming id is a UUID and convert if needed. I'll also remove the exception and log message. Can I proceed this way?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Copy Markdown
Contributor Author

@sguilhen sguilhen Apr 6, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! All changes pushed based on the reviews. EDIT: still testing the best way to handle this, tx.create is not suitable for components as they are not created there but rather added to the realm-components relationship. Idea is to enforce the id conversion, if needed, in the JPA entities setId() method. Will update again once testing finishes.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This approach worked, got a clean testsuite run using this approach instead of adding things in the logical layer.

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch from b752c8e to 38bfa6c Compare April 6, 2022 15:48
@vramik vramik self-requested a review April 6, 2022 16:02
@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch 2 times, most recently from 6333548 to 91de430 Compare April 6, 2022 18:43
@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch from 91de430 to 6be4970 Compare April 6, 2022 19:36
Copy link
Copy Markdown
Contributor

@vramik vramik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you @sguilhen. It's huge amount of work! Great job, please see my comments inline.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: formatting

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It basically enforces that all realm map stores uses UUID format of ids, right? Do we want that? I thought individual implementations should decide what key format will be used.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, I had a few issues moving this into the JPA storage but I seem to have found a way to do it correctly. Once I finish testing I'll update.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the same here, do we want to enforce UUIDs at provider level?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same thing, currently testing a different approach to put this into the JPA storage.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to set the id to the representation?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't - prob the first test I've ran and I think I set it here to see if the failure would be fixed with a proper id set. Now that invalid ids are converted this is not needed, so I'll remove. Thanks for spotting this.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shoudn't we also handle case COMPONENTS to avoid unnecessary additional query?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think so, and the impl would very very similar to the attributes. I'll add it.

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch from 6be4970 to d662182 Compare April 7, 2022 11:37
@sguilhen sguilhen requested a review from vramik April 7, 2022 11:41
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wondering if it should also be implemented for other areas as well ... if so perhaps we could move it into JpaMapKeycloakTransaction.create method, wdyt?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

create wouldn't work for entities such as the ComponentEntity because its creation happens when it is added to the components relationship - i.e. components are not created via tx.create. I would indeed put this check in every entity's setId(String id) because this is always called, whether from the tx.create or when creating an entity by adding it to a relationship (such as components or auth sessions that are added to the root auth session).

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the validation on setId to all other entities that have non-generated ids. For generated ids this method should never be called.

@sguilhen sguilhen force-pushed the 9661-realm-jpa-store branch from d662182 to c5517f8 Compare April 15, 2022 14:16
@sguilhen sguilhen requested a review from vramik April 15, 2022 14:16
Copy link
Copy Markdown
Contributor

@vramik vramik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @sguilhen

Copy link
Copy Markdown
Contributor

@hmlnarik hmlnarik left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Approving per @vramik and @ahus1 approvals. Thanks for the PR!

@hmlnarik hmlnarik merged commit b29b27d into keycloak:main Apr 20, 2022
@sguilhen sguilhen deleted the 9661-realm-jpa-store branch April 22, 2022 17:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/storage Indicates an issue that touches storage (change in data layout or data manipulation)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Testsuite failures when JPA Map Storage is used for realms JPA map storage: Realm no-downtime store

4 participants