8000 fix: do not leak SCIM resource existence to unauthorized callers by waterWang · Pull Request #52151 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,12 @@ public R get(String id, List<String> attributes, List<String> excludedAttributes
M model = getModel(id);

if (model == null) {
// Do not leak the existence of a resource to callers without view permission:
// a missing resource must be reported as forbidden (403), not as not found (404),
// otherwise callers can probe which resource ids exist.
if (!canQuery()) {
throw new ForbiddenException();
}
Comment thread
pedroigor marked this conversation as resolved.
Resolved
Comment on lines +59 to +61
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.

Also discussed here #52304 (comment)

return null;
}
Comment thread
pedroigor marked this conversation as resolved.
Resolved

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,33 @@ public void testUsersAccessDeniedIfRolesNotGranted() {
assertAccessDenied(() -> noAccessClient.users().delete(managedUser.getId()));
}

@Test
public void testMissingResourceDoesNotLeakExistence() {
String missingId = KeycloakModelUtils.generateId();
User user = new User();
user.setId(missingId);
user.setUserName("missing");
// A caller without any access must receive 403 (not 404) even for a missing
// resource, so the response code cannot be used to probe whether a given
// resource id exists.
assertAccessDenied(() -> noAccessClient.users().get(missingId));
assertAccessDenied(() -> noAccessClient.users().update(missingId, user));
assertAccessDenied(() -> noAccessClient.users().patch(missingId, PatchRequest.create()
.add("name.displayName", "new display name")
.build()));
assertAccessDenied(() -> noAccessClient.users().delete(missingId));

assertAccessDenied(() -> noAccessClient.groups().get(missingId));
Group resource = new Group();
resource.setId(missingId);
resource.setDisplayName("display name");
assertAccessDenied(() -> noAccessClient.groups().update(missingId, resource));
assertAccessDenied(() -> noAccessClient.groups().patch(missingId, PatchRequest.create()
.add("displayName", "new display name")
.build()));
assertAccessDenied(() -> noAccessClient.groups().delete(missingId));
}

@Test
public void testUsersCanQueryIfQueryRoleGranted() {
grantAdminRole(AdminRoles.QUERY_USERS);
Expand Down
Loading
0