KEYCLOAK-10695 - fixed view permissions of a group#6114
KEYCLOAK-10695 - fixed view permissions of a group#6114br0xpl wants to merge 5 commits intokeycloak:masterfrom
Conversation
There was a problem hiding this comment.
Thanks, @br0xpl. Overall, it looks good to me.
However, there is something that I think you are missing, pagination. If the parameters used for pagination (first and max) are provided you will end up enforcing access for a specific page and, eventually, responding with less or no entries although you may have groups in other pages that the user has access.
We had the same issue with the users pagination which we end up doing some hacks to get this working. For instance, getting the groups beforehand prior to making the query.
For groups, we would need something similar or any other more clever logic.
Hi! @pedroigor What do you think? Thanks. |
|
@pedroigor Another thing is that the travis build failed but because of some maven dependencies being unresolvable (forbidden).. seems some problem with maven artifactory rather than with the PR.. Can we somehow rerun the travis build? |
That's unrelated with this PR, we are trying to figure how to fix this. Meanwhile, I will try to trigger the job again. |
|
Thanks @br0xpl . Like we discussed, it is indeed the most obvious solution although not the most optimal. You also need to provide some tests but before doing so, I will ask @mposolda for his feedback about the current solution. Regarding the other options to pagination, when doing users pagination I also had the same ideas. I think #2 is the best one as it does keep clients simple and requires some relatively simple work on the server side. |
mposolda
left a comment
There was a problem hiding this comment.
+1 for the approach instead of handle pagination on the client. I added few more comments inline.
| results = ModelToRepresentation.searchForGroupByName(realm, search.trim(), firstResult, maxResults); | ||
| } else if(Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) { | ||
| results = ModelToRepresentation.toGroupHierarchy(realm, false, firstResult, maxResults); | ||
| results = realm.searchForGroupByName(search.trim(),null, null); |
There was a problem hiding this comment.
Shouldn't be here "firstResult, maxResults" instead of "null, null" ?
There was a problem hiding this comment.
Indeed. @br0xpl, could you consider both firstResult and maxResults when searching by name ?
There was a problem hiding this comment.
The problem is we are getting maxResults then and some of the groups might get filtered out. So we would have to:
a) fetch maxResults in a loop until we get maxResults after filtering
b) fetch all
I chose b - but if you prefer a just let me know?
@pedroigor , @mposolda : let me know how would you see it done?
But indeed my code misses the filtering first and max in after filtering - this has to be done.
- Filter first and max results out of the filtered results
There was a problem hiding this comment.
@br0xpl, another option would be:
- Check if the user has permissions to view groups (granted by view-users or manage-users)
- If not, obtain the groups that have permission enabled and return those that the user can view
- You can then use the list of groups to filter the results when searching by name
Look at this code in users
KeycloakSession. Then we use this list to filter results in the database.
You should also consider filtering top level groups. Just like it is done today.
There was a problem hiding this comment.
@br0xpl, see https://github.com/pedroigor/keycloak/tree/KEYCLOAK-10695. Similar to users. But still missing the top-level group pagination. Just a quick work to give you some ideas :)
There was a problem hiding this comment.
@pedroigor , @mposolda : I've fixed it according to your description - please see it.
I've used the getGroupsWithViewPermission function of GroupPermissions but I have a doubt about it's behaviour, see here:
and line 323 - it is checking if user has manage _members or view _members permission. Shouldn't it be checking if user has view or manage permission for that group? The function name suggest just "view", not view_members..?
Seems we need to either change function name and create another function with view or we need to change this function?
There was a problem hiding this comment.
We can change the method name. Its intent is to obtain the groups that a user has either view or manage members permission. Good catch.
There was a problem hiding this comment.
I've done that. I moved the common part to generic getGroupsWithPermissions(String... scopes) function and created two functions: getGroupsWithViewPermission /new function/, and renamed the previous: getGroupsWithViewMembersPermission.
@pedroigor : please review all the changes -> I've tested and the groups work as expected now.
|
|
||
| if (Objects.nonNull(search)) { | ||
| results = realm.getGroupsCountByNameContaining(search); | ||
| results = realm.searchForGroupByName(search, null, null); |
There was a problem hiding this comment.
This is potential performance killer, but I don't have better idea how to address this. So I assume we need to live with that. Fortunately there will be thousands of groups at most (not millions) and it is just about admin requests, so hopefully it is ok.
IMO in general, it is probably better to have pagination approach, which doesn't require counts. Something, which always returns the token for next page? Although this approach also has limitations (EG. it is not easily possible to move to the exact page like "Go directly to page 50" etc), and there are probably other limitations. But maybe something to consider in the design of new REST API (CC @pedroigor ). Sorry for hijack the PR :)
There was a problem hiding this comment.
@mposolda, the guideline is now updated with the pagination practice. In a nutshell, we are keeping the existing behavior when paginating results with small improvements on how we communicate whether or not the client reached the last page. We can discuss more there :)
| * TODO: IMHO we should consider different pagination technique: | ||
| * (1) REST return filtered results (in some cases even epty page) and JS | ||
| * client retrieves next pages until it gets all page of results or reaches the end of list | ||
| * (2) or we fetch results in backend page by page until we get all required results. |
| results = ModelToRepresentation.searchForGroupByName(realm, search.trim(), firstResult, maxResults); | ||
| } else if(Objects.nonNull(firstResult) && Objects.nonNull(maxResults)) { | ||
| results = ModelToRepresentation.toGroupHierarchy(realm, false, firstResult, maxResults); | ||
| results = realm.searchForGroupByName(search.trim(),null, null); |
There was a problem hiding this comment.
Indeed. @br0xpl, could you consider both firstResult and maxResults when searching by name ?
pedroigor
left a comment
There was a problem hiding this comment.
Only a few comments. We should also consider adding a test
.
services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
Show resolved
Hide resolved
services/src/main/java/org/keycloak/services/resources/admin/GroupsResource.java
Outdated
Show resolved
Hide resolved
|
@br0xpl, this test is failing GroupTest.searchAndCountGroups. |
…ionsResource adding delete and update methods.
|
@pedroigor: Thanks for your valuable comments. I've added a test for the fine grained permission. While writing the test I've found some methods missing in the keycloak-admin-client code - (update and delete in Scope/Resource PermissionsResource classes) - I've added them. Please verify - thanks! |
|
@br0xpl I believe there were some changes in master, which is causing some conflicts with your changes. Could you please rebase? |
| Response create(ResourcePermissionRepresentation representation); | ||
|
|
||
| @Path("{id}") | ||
| @PUT |
There was a problem hiding this comment.
These changes are not needed because you have these same methods in org.keycloak.admin.client.resource.ResourcePermissionResource.
| Response create(ScopePermissionRepresentation representation); | ||
|
|
||
| @Path("{id}") | ||
| @PUT |
There was a problem hiding this comment.
These changes are not needed because you have these same methods in org.keycloak.admin.client.resource.ScopePermissionResource.
| import java.util.List; | ||
| import java.util.Map; | ||
| import java.util.Objects; | ||
| import java.util.*; |
There was a problem hiding this comment.
Please, don't use wildcards. Import specific types instead. This change is not really necessary. The new types you are importing are fine.
| } | ||
| Set<String> groups = auth.groups().getGroupsWithViewPermission(); | ||
| Stream<String> s = groups.stream(); | ||
| if (search!=null) s=s.filter(group->group.contains(search.trim())); |
There was a problem hiding this comment.
Don't you have to search by name? Also, I think you should consider filtering by name just like the [code](https://github.com/pedroigor/keycloak/commit/81e718bf9af893d335c4cb50ddc369c813b0ed26) I shared with you.
| import org.keycloak.admin.client.resource.RealmResource; | ||
| import org.keycloak.admin.client.resource.RoleMappingResource; | ||
| import org.keycloak.admin.client.resource.UsersResource; | ||
| import org.keycloak.admin.client.resource.*; |
There was a problem hiding this comment.
Same thing here in regards to import statements. Prefer importing types. Most of these changes to import statements can be avoided.
|
@br0xpl, thanks again for your work. In addition to rebasing your branch, could you also squash your commits so that we have a single one ? |
|
@pedroigor, @abstractj : I'll try to come back and finish this once again. @pedroigor I sorry I missed your contribution, I'll make sure to take it as indeed we need to search by the name of course. Please give me some time to fix this and squash all the changes together. Thanks! |
abstractj
left a comment
There was a problem hiding this comment.
@br0xpl this PR has some conflicts with master at the moment. Could you please follow up on @pedroigor's considerations and rebase your changes?
|
Closing this as out of date due to lack of feedback |
Hi,
According to the issue discribed here:
https://issues.jboss.org/browse/KEYCLOAK-10695
I'm sending a PR with a proposition of fix.
Please let me know if this seems good?