8000 KEYCLOAK-14536 UserModel preparation for UserProfile by Martin-Idel-SI · Pull Request #7080 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content

KEYCLOAK-14536 UserModel preparation for UserProfile - #7080

Merged
mposolda merged 1 commit into
keycloak:masterfrom
bosch-io:feature/UserProfile-UserModel-preparation
Jun 25, 2020
Merged

mposolda merged 1 commit into
keycloak:masterfrom
bosch-io:feature/UserProfile-UserModel-preparation

Conversation

@Martin-Idel-SI
@Martin-Idel-SI Martin-Idel-SI commented May 19, 2020 •
Copy link
Copy Markdown
Contributor

This PR is a preparation for adding the user model soon.

As discussed in several threads (e.g. here: keycloak/keycloak-community#104), it would be nice to no longer store attributes such as "firstName" or "lastName" as fields in the user model so that they are not mandatory in a future user profile. I believe this is also in line with how you are planning to evolve the Keacloak model

In addition, it was suggested to also change the name from firstName/lastName to the OIDC naming convention (i.e. given_name/family_name).

This PR outlines how we would approach this change:

  • Initially, we would leave the various representations in the GUI as they are (this would be changed later on when introducing the user profile)
  • We would also leave the database as is and provide the mapping in the corresponding database adapter. How and if to do a database migration can then be decided later on (and we don't break users having indices on those fields in their db)
  • In this PR, I initially only migrate firstName and lastName. According to the discussion, we'd also think about migration email. I think username is too special to merit migration.

There are a few things I noticed when preparing this migration:

  • This will break those policy evaluations in fine grained permissions using lastName/firstName and/or the amount of attributes (see the test change in
    builder.append("if (attributes.size() == 2 && attributes.containsKey('a1') && attributes.containsKey('a2') && attributes.get('a1').size() == 2 && attributes.get('a2').get(0).equals('3') && resource.getAttribute('a1').size() == 2 && resource.getSingleAttribute('a2').equals('3')) { $evaluation.grant(); }");
    ) - checking against the amount of attributes would also break somewhat silently because the evaluation would be semantically correct
  • We probably have to do a migration for the realm model: Mappers from user federation or OIDC flow mappers (SAML too probably?) need to be updated to reflect the change from a field called "lastName" in the UserModel to an attribute called "family_name", etc. Does anybody have a hint on how best to achieve this?
  • We probably also break JSON imports for the same reason
  • There are some conversions back and forth between attributes and a few (necessary copies). While I don't believe it should impact performance a lot, it might so we probably need to be careful

What do you thing about those?

Regarding the breaking change with built in mappers, as far as I can see this should be avoidable if we do not rename the attribute from lastName to family_name but keep the old name and just migrate it from a field to an attribute.

Finally, it's difficult to assess how well the tests cover that no real functionality change happened here. I went through all code changes and to me there are the following areas of interest:

  • User Federation: This is handled by mappers from the server to Keycloak and by writing to LDAP if possible - this should be covered, but I'm not particularly familiar with the user federation code, yet
  • Identity Brokering: This is basically the contexts and then just filling the user model from the context (should be covered)
  • (OIDC) client: There are protocol mappers mapping from Keycloak to the oidc claims (adapted). On the SAML side I'm unsure whether I need to do anything except for potential user mapper changes (see above)
  • Keycloak <-> Frontend (e.g. Profile update): There are the two UserRepresentation classes and the ProfileBeans - should be covered

Finally, what I believe remains to be done before merging this once there is an agreement on whether this is a viable strategy:

  • run (and potentially fix compilation and tests) for other test suites than base
  • decide and implement migration strategy if necessary
  • create JIRA ticket for this subtask
  • squash to one commit

@stianst
stianst commented May 20, 2020
Copy link
Copy Markdown
Contributor

We'll need to consider a slightly less intrusive way to achieve this. Through deprecation/migration.

The fields on the UserModel should remain as is, but marked as @deprecated. These can then delegate to attributes instead of fields. Perhaps this can even be done in an non-intrusive way of returning given_name attribute if it's set, with a fallback to firstName. Alternatively, we could consider migrating, but that could be very expensive for those that have millions of entries. We could even go as far as allowing reading firstName field with getAttribute(given_name).

@mposolda @hmlnarik @pedroigor we really need some input on this one. It would be nice to get to the point where we don't have basic fields on the user-model and it's all just attributes, but how to get there is another thing.

@pedroigor pedroigor left a comment
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Lea 8000 rn more.

As an initial and base implementation for the user profile stuff, I would also do it differently as @stianst suggested.

Before continuing reviewing other parts I would just revert the changes that remove first/last references from the model, deprecate them, and use a fallback approach to read them as attributes.

I think obtaining/set the first/name is a so common operation that maybe it even makes sense to not deprecate them but have them there as a more convenient way to obtain both given and family names.

In regards to migration, I also think that we can't do much without impact deployments with a huge number of entries. However, this can be done either by migrating on demand (when a user updates these attributes) and when a realm us actually using the upcoming user profile SPI (not the legacy).

@mposolda mposolda left a comment
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 agree with @pedroigor regarding keeping firstName,lastName getters/setters on UserModel. And they are quite used methods, so even deprecating them is not needed IMO.

  • I would just add the methods like this to UserModel interface directly:
default void setFirstName(String firstName) {
    setSingleAttribute("firstName");
}

etc for other getters/setters

  • My vote is even to keep the name of attributes as firstName/lastName. I personally like firstName/lastName better than "given_name"/"family_name" . Moreover I don't see much benefit with aligning to OIDC protocol naming? It rather seems that changing "firstName" to "given_name" etc will mean some more migration work (configuration of all mappers etc) and potential for more bugs reported.

  • On the other hand, we can change JPA model to use attributes for writing instead of properties? The properties can be used just as fallback for reading from previous version. I can imagine something like this on the JPA UserAdapter:

public String getFirstName() {
    // This reads from the "firstName" attribute as implemented on the UserModel interface
    String firstName = super.getFirstName();
    
    // Fallback to read from FIRST_NAME property on USER_ENTITY table
    if (firstName == null) {
        firstName = userEntity.getFirstName();
    }
}

The setters on UserEntity can be removed entirely. Also the UserAdapter.setFirstName setter can be removed. This means that all new writes will go to attributes and reads will allow fallback to read from FIRST_NAME , LAST_NAME properties.

This approach can allow better flexibility for removing getters/properties entirely in the future. And at the same time, there won't be a need for the expensive bulk users DB migration

  • We can use same approach for UserRepresentation - write to attributes and read from attributes with the fallback to read from getters.

In other words, only needed thing for this PR might be the change on UserModel and then slight change on the JPA model and UserRepresentation JSON reading/writing.

@mposolda
Copy link
Copy Markdown
Contributor

Regarding the other properties, I can imagine that "email" can be a bit tricky regarding DB model. It is due the fact that we have unique constraint in the DB model for the "email" and I assume we still want to keep this constraint?

So for the JPA model etc, I think we will still write "email" as the column EMAIL instead of the attribute just to enforce the constraint is addressed.

@Martin-Idel-SI
Copy link
Copy Markdown
Contributor Author

@stianst , @mposolda , @pedroigor Thanks for your feedback! Here is my summary of the discussion so far and what I would do:

firstName/lastName naming:

There is at least one voice to have the attributes named "lastName" and "firstName" as before, not "family_name" and "given_name". This was suggested in the design document (https://github.com/keycloak/keycloak-community/blob/master/design/user-profile.md):

Standard attribute names will be based on claims from OpenID Connect Core, but we may not cover all attributes listed there at least initially. Especially attributes such as picture are problematic as the ideal experience is one where users are able to upload a picture through admin and account consoles rather than simply listing an externally managed URL.

The reasoning was to make it easy for people knowing openid to work with the user (profile) directly. Of course it's fine to make a different decision here in order to avoid ramifications for migrating mappers. What should be the final decision here as I don't see a clear consensus?

Database

I like the suggestion by @mposolda to migrate slowly by moving to attributes when touching the user.

However, the suggestion as is will break the user search: the search for a user with some firstName will then not necessarily work if the firstName was updated (concrete method I think would break:

public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {
).

To fix this, we'd have to implement searching for attributes, too. I'd therefore think that we should not implement the slow migration in this PR but postpone this to future PRs to keep changes small:

  • implement search for attributes in JPA provider
  • Then start slow migration of firstName/lastName column to user attributes using the search for attributes to implement a fallback search for firstName/lastName

Does that sound good to you or would you prefer to do it here?

Accessor methods on the UserModel:

Clearly we have to either deprecate or leave the methods. I gather that most of you prefer keeping the methods as convenience methods so that's what I'm going to do.

Email and Username

I gather the consensus here is to also have both fields as attributes in the UserModel, however we still want to keep the corresponding columns in the database here for now, so that's what I'm going to do.

@mposolda
Copy link
Copy Markdown
Contributor

firstName/lastName naming:

I am the one, who postponed to keep the attribute names to "firstName" / "lastname" instead of changing to "given_name" / "family_name" . If you guys have different opinion, then feel free to rename.

Just repeating, that I don't see so much advantages of rename (Keycloak doesn't necessarily need to be tightly-coupled to OIDC as OIDC is just one of the protocols supported by Keycloak) comparing to the possible bugs during migration (EG. all mappers may need to be renamed for the migration and maybe some more various issues...)

Database

I like the suggestion by @mposolda to migrate slowly by moving to attributes when touching the user.

However, the suggestion as is will break the user search: the search for a user with some firstName will then not necessarily work if the firstName was updated (concrete method I think would break:

public List<UserModel> searchForUser(Map<String, String> attributes, RealmModel realm, int firstResult, int maxResults) {

).

To fix this, we'd have to implement searching for attributes, too. I'd therefore think that we should not implement the slow migration in this PR but postpone this to future PRs to keep c 8000 hanges small:

* implement search for attributes in JPA provider

* Then start slow migration of `firstName`/`lastName` column to user attributes using the search for attributes to implement a fallback search for `firstName`/`lastName`

Does that sound good to you or would you prefer to do it here?

+1 . Doing things in more PRs is always good. So JPA model can be done later.

Accessor methods on the UserModel:

Clearly we have to either deprecate or leave the methods. I gather that most of you prefer keeping the methods as convenience methods so that's what I'm going to do.

+1 from me.

Email and Username

I gather the consensus here is to also have both fields as attributes in the UserModel, however we still want to keep the corresponding columns in the database here for now, so that's what I'm going to do.

+1 .

It seems the main reason to keep the username and email columns in DB are the DB unique constraints, which we probably still want to preserve.

Will be nice if "username" is also subject to the UserProfile as I mentioned in the keycloak-dev. This is related to the support for username to be writable on registration form and when creating by admin, but readable in further edits. It will also allow us to remove the realm switch "Edit username" , but that can be done in some further PRs in my opinion.

@Martin-Idel-SI
Martin-Idel-SI force-pushed the feature/UserProfile-UserModel-preparation branch from a447825 to c4cebdc Compare June 2, 2020 14:06
@Martin-Idel-SI
Martin-Idel-SI commented Jun 2, 2020 •
Copy link
Copy Markdown
Contributor Author

@mposolda I updated the PR with the changes discussed above, i.e. firstName, lastName, email and username are now attributes. I fully agree that it would be nice to have username subject to the profile.

There are a few points to discuss though:

  • It turns out that FTL doesn't recognize default methods on classes as the JavaBeans specification doesn't (didn't?). There is a workaround since version 2.3.26 (we use 2.3.29) but we'd have to sacrifice compatibility with templates for earlier versions. So either we can't have default methods in UserModel or (preferred imho) we go with default methods as suggested and we introduce this flag, potentially breaking some old FTL templates:
    Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);
  • I noticed that we still have one bit of possible migration to discuss: What if a user has a custom attribute called "email", "username", "firstName" or "lastName" in the database? What if that field doesn't match the real email, etc? We have to have some sort of migration strategy. I stumbled across this since there is one test realm which actually has a user with email as attribute which makes one test fail: I renamed it in the test, but I think we have to discuss what to do here.
  • Regarding the last problem, we probably should forbid creating custom attributes of that type, but I don't know how best to support this in the GUI, or should we just list email, firstName, lastName and username as custom attributes, too?
  • I was wondering: Apart from the base test suite, is there another testsuite which runs some tests against federated storage? Changes around the UserModel seemed to result in less test failures for federated storage than I would have thought so I wonder how good test coverage in that area is and whether we need to do some manual testing to see that everything still works - in any case I'll have to look into potential test failures on your CI.

@Martin-Idel-SI
Copy link
Copy Markdown
Contributor Author

There are still the Cross DC tests failing, everything else seems to work fine. I'm trying to debug those but that'll take some time.

@mposolda
mposolda commented Jun 4, 2020
Copy link
Copy Markdown
Contributor

@Martin-Idel-SI Feel free to ignore cross-dc tests. They are broken right now and separate JIRA for fixing them exists.

However if you volunteer to fix them, it will be great! :) Just a warning that it may be non-trivial effort and will be probably good to send separate PR to keycloak master as fixing cross-dc tests is not directly related to this User Profile work. Just checking for the case that you are interested in cross-dc. See https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/HOW-TO-RUN.md#cross-dc-tests for how to run cross-dc tests.

@mposolda
mposolda commented Jun 4, 2020
Copy link
Copy Markdown
Contributor

@Martin-Idel-SI I will take a more look at your changes and proposal for this PR next week. Sorry for the delay - had some other priority task this week...

@Martin-Idel-SI
Copy link
Copy Markdown
8000
Contributor Author

@mposolda No worries, next week is fine!

Good to know about the Cross DC tests. Yes, I saw the "How to run" but as of yet, something isn't working correctly from IntelliJ. If I get my setup working and see an easy fix I'll let you know asap of course, but I'm not going to put too much effort into that if they also fail on master ;-) .

@Martin-Idel-SI
Martin-Idel-SI force-pushed the feature/UserProfile-UserModel-preparation branch from c4cebdc to 88b5551 Compare June 8, 2020 10:35
@mposolda mposolda left a comment
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.

@Martin-Idel-SI Thanks for your changes and I am sorry for later review... Please see my comment below

@stianst Do you have a chance to also take a look in this PR please and at some comments above?

I am adding my opinion on the questions you had in the comment above.

It turns out that FTL doesn't recognize default methods on classes as the JavaBeans
specification doesn't (didn't?). There is a workaround since version 2.3.26 (we use 2.3.29) but we'd
have to sacrifice compatibility with templates for earlier versions. So either we can't have default
methods in UserModel or (preferred imho) we go with default methods as suggested and we
introduce this flag, potentially breaking some old FTL templates:

Configuration cfg = new Configuration(Configuration.VERSION_2_3_26);

I think this change is OK, but I am not 100% sure. @stianst WDYT?

I noticed that we still have one bit of possible migration to discuss: What if a user has a custom attribute called "email", "username", "firstName" or "lastName" in the database? What if that field doesn't match the real email, etc? We have to have some sort of migration strategy. I stumbled across this since there is one test realm which actually has a user with email as attribute which makes one test fail:

keycloak/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json

Line 132 in c4cebdc
"old-email": "bburke@redhat.com"
I renamed it in the test, but I think we have to discuss what to do here.
Regarding the last problem, we probably should forbid creating custom attributes of that type, but I don't know how best to support this in the GUI, or should we just list email, firstName, lastName and username as custom attributes, too?

I think this is corner case and I would ignore this issue. If someone has an attribute "email" in addition to the property "email", then they already have some issues in the mappers etc. Your change in the test is OK in my opinion.

I was wondering: Apart from the base test suite, is there another testsuite which runs some tests against federated storage? Changes around the UserModel seemed to result in less test failures for federated storage than I would have thought so I wonder how good test coverage in that area is and whether we need to do some manual testing to see that everything still works - in any case I'll have to look into potential test failures on your CI.

I think it will be good to run the cluster tests and cross-dc tests. Namely the UserInvalidationClusterTest and InvalidationCrossDCTest. This will be good as I am not 100% confident that your changes in model/infinispan don't have any impact on user invalidations. Here are some hints for run those tests:
https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/HOW-TO-RUN.md#cluster-tests
https://github.com/keycloak/keycloak/blob/master/testsuite/integration-arquillian/HOW-TO-RUN.md#cross-dc-tests

Besides that, it will be good to run admin console tests and account console tests to doublecheck there is no impact of your freemarker change. I will take care of it and will run the tests in our environment. But will be good to first address my other comments.

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 it it not very good to remove those methods from UserModelDelegate? IMO you always want to call delegate rather than rely on default implementations from UserModel. In some cases, the methods on the delegate can do something different that call "setAttribute/getAttribute" . I hope it is possible to revert changes in UserModelDelegate class entirely.

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.

The problem is that this introduces potential inconsistencies:

I have two ways to access and/or change those attributes. If one way behaves differently than the other, this will lead to subtle and hard to debug bugs. That's why I would've deprecated and deleted those methods altogether but I can see that the effort involved is much larger as of now (for instance ftl templates rely on those methods), so we keep those methods.

This is in general true for all subclasses of UserModel. For the AbstractUserAdapterFederatedStorage this is discussed in the other comment and there is a solution to ensure consistent behaviour as long as the implementation does not override the methods to get or set attributes.

I didn't see any other implementation of that interface I thought was modeled for inheritance, but if it is possible to provide UserModel implementations via SPI then we definitely should think about this again.

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.

Replied to your other comment. Hopefully once "getUsername" and "setUsername" are not implemented on UserModel, the changes in Use 10000 rModelDelegate will be possible to revert, so that it always calls the delegate instead of rely on the default implementations.

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.

It's possible (see the two last commits). However, please note the duplicate code I had to introduce to keep consistency!

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.

@stianst Is this change ok or do you see any issues with that? More details in this comment : #7080 (comment)

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.

Not sure to be honest as I don't know what the implications really are here. It seems this requires FreeMarker to do additional reflection of the classes, which could be expensive? Also, what would break in existing templates with this?

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 in the sense that it requires FreeMarker to also see default methods, but I'd think this should be done in the same pass where Freemarker retrieves the other getter/setter methods, so this shouldn't have a large overhead (if any).

However, some things may break: Here is an overview: https://freemarker.apache.org/docs/api/freemarker/template/Configuration.html#Configuration-freemarker.template.Version- - since I have no idea what features are used, it's hard for me to judge if this is a problem. I ran some console tests and all seemed fine, so I was confident enough to propose this change.

As I said, the alternative would be to not use default methods but duplicate the methods to all implementing classes.

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.

10BC8

Just an idea, but will it help to use the "wrapper" object, which has the methods getX/setX overriden? I can imagine some change like this:

-  freemarkerContextAttributes.put("user", userModel);
+ UserModelDelegate wrapper = new UserModelDelegate(userModel);
+ freemarkerContextAttributes.put("user", wrapper);

Can it help?

If not, is it the possibility to have some other Wrapper class similar to for example org.keycloak.forms.login.freemarker.model.ProfileBean ?

If nothing of those helps (or it becomes unecessary complex and ugly code), if you have an opportunity to add the details what exactly the error is and where it happens, it will be helpful. Hopefully we can figure something.

The set of version in the Configuration may work as the last possibility, but will be nice to avoid since we are not 100% sure of all the possible side-effects.

@Martin-Idel-SI Martin-Idel-SI Jun 16, 2020 •
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'm sure we'll figure something out!

The problem is actually very simple: I found it first in the resource-detail.ftl. The corresponding AuthorizationBean contains permissions which contain a RequesterBean which contains a UserModel (the requester). Now, without this change, the ftl-template cannot be rendered correctly, because permission.requester.username is null in this line:

<form action="${url.getResourceGrant(authorization.resource.id)}" name="revokeForm-${authorization.resource.id}-${permission.requester.username}" method="post">

And the reason it's null is because this refers to the method getUsername on the UserModel- but it doesn't exist for FTL as default methods don't exist for without this change (this is due to the JavaBean specification which doesn't understand default methods).

Now, clearly that's just one instance of where this fails as the UserModel is also present in other beans. Also, since get/setUsername are not default implemented anymore this particular issue will not arise anymore, but the same problem will be whenever we need get/setEmail or firstName, lastName.

So for me, there would be several solutions to this:

  • directly grab the attribute of the user in the FTL templates via something like permission.requester.attributes["username"][0] or similar. This is not very nice and very error prone as I don't see a good way to find all instances where this could be a problem. Also, this breaks custom templates.
  • Add the configuration option as above: least intrusive from a code perspective which is why I proposed this change first, but may have unwanted side-effects. I've never really worked with FTL, so I can't say much about it
  • Remove the default methods and just implement them on all subclasses. Since we do essentially the same for getUsername it seems those subclasses aren't too many due to the hierarchy of subclasses.
  • Add a wrapper object to all places where UserModel is used in the beans. Sounds weird and error prone and results in quite a few changes
  • Add an abstract subclass of UserModel and derive all classes that don't override the default methods from this subclass: I don't particularly like to add yet another level to the hierarchy, it's already quite deep
  • Make UserModel an abstract class instead of an interface (I haven't tested it though): This should also work, but may not be nice from an architectural standpoint.

I'm probably going to try out the third option. This leads to some code duplication, but the code changes are easiest to get right, so maybe that's the best way to go?

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.

As I pointed, if there is some easy way to address this like for example using this in the AuthorizationBean constructor: this.user = new UserModelDelegate(user);, it will be fine to me.

The solution with adding to subclasses however works for me as well.

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 ended up adding subclasses - please have a look. I feel that this approach is the safest, as everything looks as before for FTL templates.

All tests already ran beforehand since the only test failure I saw was actually related to the username field and I had already removed the default methods before. I tried using wrapper objects but was left unsatisfied whether I actually solved all problems and if somebody uses custom FTL files, those could easily break if I overlook something.

I could add a comment to the wrapper class (and the one set of duplicate methods in the infinispan/UserAdapter) to move to default methods once this is no longer a problem in FTL (maybe you will make a switch to a newer version for different reasons).

@Martin-Idel-SI
Martin-Idel-SI force-pushed the feature/UserProfile-UserModel-preparation branch from 88b5551 to 26074c8 Compare June 15, 2020 10:36
@Martin-Idel-SI
Martin-Idel-SI commented Jun 15, 2020 •
Copy link
Copy Markdown
Contributor Author

@mposolda Thanks for your input, I updated the PR again implementing the changes and rebased it to make it mergable in principle (for now, I'll only add commits to make it easier for you to review the changes I put on top, so this time I added two commits).

I ran the crossdc and cluster test locally and they ran fine with the exception of the AuthenticationSessionFailoverClusterTest.failoverDuringAuthentication test where it seems the first response in the test setup is not a "reset password" page but an "update profile" page instead (both pages should be shown eventually if I see this correctly). I'll look into that failure of course, but I'm unsure whether it has anything to do with my changes, yet.

EDIT: Sadly, there are CI failures. As I can't reproduce those locally, this will take some time to debug and if I look at the code caching can be the only culprit I can think of...

@mposolda
Copy link
Copy Markdown
Contributor

@Martin-Idel-SI The test failure in AuthenticationSessionFailoverClusterTest.failoverDuringAuthentication does not have anything to do with your changes. No need to look at it. JIRA exists for this and fix is in progress as far as I know.

The same applies to cross-dc server and adapter tests. However the errors in LDAPProvidersIntegrationNoImportTest are most likely caused by the changes. I will take a look at your changes now...

@mposolda
Copy link
Copy Markdown
Contributor

@Martin-Idel-SI The changes are ok to me. Just 2 things:

  • Will be good to figure the failing LDAPProvidersNoImport test
  • Will be good to avoid the explicit version set in Freemarker if possible - details in the inline comment.

Thanks for all your work on this. The User SPI refactoring is unfortunately the part, which is a bit of pain the UserStorage SPI, backwards compatibility, lots of the tests affected etc... Hopefully the follow-up work on the UserProfile will not be that painful... :-)

@Martin-Idel-SI
Martin-Idel-SI commented Jun 16, 2020 •
Copy link
Copy Markdown
Contributor Author

@mposolda We knew that changing how data is stored and accessed in the UserModel would likely be very painful, although I was pleasantly surprised by how few changes we actually need. The architecture seems to be quite well done! I'm confident introducing the SPIs will be less painful since it was rather straightforward to get something like the Legacy Profile in place (see the PR by bs-matil).

Yes, the two tests failing outside of the crossdc tests are definitely related to my changes. EDIT: I can now reproduce them, so should hopefully be able to fix them soon or provide another problem to analyze :D

@Martin-Idel-SI
Martin-Idel-SI force-pushed the feature/UserProfile-UserModel-preparation branch 2 times, most recently from f8f2701 to caaa04c Compare June 18, 2020 15:55
@Martin-Idel-SI
Copy link
Copy Markdown
Contributor Author

@mposolda
I fixed the LDAPProvidersNoImport test - it was inconsistent usage of the firstName/lastName getters and setters.

TravisCI is still not happy about the CrossDC tests but they do run locally and I see a test failure in your Keycloak.X test suite - does that have anything to do with my changes?

@mposolda mposolda added area/server area/core Core server — startup, configuration, providers/SPIs, cross-cutting concerns labels Jun 19, 2020
@mposolda mposolda added kind/feature Categorizes a PR related to a new feature missing/docs labels Jun 19, 2020
@mposolda mposolda left a comment •
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.

@Martin-Idel-SI Thanks for the update! The PR looks good to me. I've added one (hopefully) last minor comment inline.

Besides that, it will be good to add some small note to the documentation (Upgrading guide) about the changes in the user model. See the file https://github.com/keycloak/keycloak-documentation/blob/master/upgrading/topics/keycloak/changes.adoc for more details.

@stianst @hmlnarik @pedroigor Do you have any more feedback to this PR?

@Martin-Idel-SI
Martin-Idel-SI commented Jun 19, 2020 •
Copy link
Copy Markdown
Contributor Author

@mposolda No worries, since this is a rather intrusive change it's definitely good to be careful.

Yes, I was thinking about where to put some documentation, thanks for pointing this out! Here is the corresponding PR: keycloak/keycloak-documentation#962

Regarding ticketing: Would you like me to create some task ticket describing the changes or rather a subtask to the UserProfile epic?
Once it seems your feedback is complete I'll squash the commits.

I'll then continue with the database changes we discussed above but that'll probably take a while since I'll be unavailable in July.

@mposolda
Copy link
Copy Markdown
Contributor

@Martin-Idel-SI Thanks for the update!

I've approved your PR for the documentation. I've added Andrew (our documentation guru) as a reviewer to this PR as well to check if it is fine from the perspective of english grammar and other things like that.

Yes, it will be good to have JIRA under UserProfile epic for this. We try to have 1 commit per 1 PR and 1 JIRA. Once you do the JIRA, you can squash the commits in this PR and add the JIRA number to the commit message (See other Keycloak commit messages for the details).

- In order to make lastName/firstName/email/username field
  configurable in profile
  we need to store it as an attribute
- Keep database as is for now (no impact on performance, schema)
- Keep field names and getters and setters (no impact on FTL files)

Fix tests with logic changes

- PolicyEvaluationTest: We need to take new user attributes into account
- UserTest: We need to take into account new user attributes

Potential impact on users:

- When subclassing UserModel, consistency issues may occur since one can
  now set e.g. username via setSingleAttribute also
- When using PolicyEvaluations, the number of attributes has changed
@Martin-Idel-SI
Martin-Idel-SI force-pushed the feature/UserProfile-UserModel-preparation branch from 2a098e6 to ed6e791 Compare June 22, 2020 09:54
@Martin-Idel-SI Martin-Idel-SI changed the title UserModel preparation for UserProfile KEYCLOAK-14536 UserModel preparation for UserProfile Jun 22, 2020
@Martin-Idel-SI
Martin-Idel-SI commented Jun 22, 2020 •
Copy link
Copy Markdown
Contributor Author

@mposolda Thank you for your approving the documentation PR: However, I added one more line to the documentation because when going over the changes one last time I remembered that this change may impact users of the policy evaluation feature (see the test change that was necessary).

I opened a subtask as requested and squashed to one commit as anticipated. I just like to keep several commits until most discussion is over because that makes it easier to revert changes and review new changes, but since hopefully most major changes are done now, I'm fine with squashing!

@mposolda mposolda left a comment
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.

@Martin-Idel-SI Thanks for your work on this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Core server — startup, configuration, providers/SPIs, cross-cutting concerns kind/feature Categorizes a PR related to a new feature

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

0