Skip to content

Commit 8ae1292

Browse files
kodjo-anipahlaura-b-ggally47ousmaneo
authored
Refactor permission checks, support team_users entity (#23439)
* add more specific doc * move user permission check to entitiy level * move role permissions check to entity level * verify based on role id & fix test * resolve permission against role name * Add spacing to section header * Support team_users entity * Change teams permission to team * add endpoint to check username availability * give self user read permission * Use new call for user name validation * Add Icon and Tooltip to indicate restricted access to an entity * Only link user over item for edit permission * Adjust shared entity overview and collection owners cell * Use entity permission for grn * Remove obsolete import * Use correct permission * shared entities: Make sure to use edit permission for team * Add missing permissions * check permissions for admin user * Remove duplicate file and fix license header * Use list permission in user page navigation tabs * fix paginated permission check & only return users based on user:read permissioN * fix unit tests * add to upgrading md * Fix tests * grn check should be against username * Fix owners cell with global share * Remove unused import * Remove permissions around user and teams tabs and user menu item * format builder --------- Co-authored-by: Laura Bergenthal-Grotlüschen <[email protected]> Co-authored-by: Mohamed OULD HOCINE <[email protected]> Co-authored-by: Ousmane SAMBA <[email protected]>
1 parent cb505e3 commit 8ae1292

File tree

33 files changed

+423
-233
lines changed

33 files changed

+423
-233
lines changed

UPGRADING.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ is now used as the primary color for elements like buttons and badges in the UI.
6060
- Event procedure
6161
- Event step
6262
- Content Pack installation
63+
- Teams
6364

6465
<br> For example, the request payload to create a stream might now look like this:
6566

graylog2-server/src/main/java/org/graylog/security/authzroles/AuthzRolesResource.java

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,8 +37,8 @@
3737
import jakarta.ws.rs.Produces;
3838
import jakarta.ws.rs.QueryParam;
3939
import jakarta.ws.rs.core.MediaType;
40+
import java.util.function.Predicate;
4041
import org.apache.shiro.authz.annotation.RequiresAuthentication;
41-
import org.apache.shiro.authz.annotation.RequiresPermissions;
4242
import org.graylog2.audit.AuditEventTypes;
4343
import org.graylog2.audit.jersey.AuditEvent;
4444
import org.graylog2.database.PaginatedList;
@@ -106,7 +106,6 @@ public AuthzRolesResource(PaginatedAuthzRolesService authzRolesService, Paginate
106106
@GET
107107
@Timed
108108
@ApiOperation(value = "Get a paginated list of all roles")
109-
@RequiresPermissions(RestPermissions.ROLES_READ)
110109
public PaginatedResponse<AuthzRoleDTO> getList(
111110
@ApiParam(name = "page") @QueryParam("page") @DefaultValue("1") int page,
112111
@ApiParam(name = "per_page") @QueryParam("per_page") @DefaultValue("50") int perPage,
@@ -125,9 +124,8 @@ public PaginatedResponse<AuthzRoleDTO> getList(
125124
} catch (IllegalArgumentException e) {
126125
throw new BadRequestException("Invalid argument in search query: " + e.getMessage());
127126
}
128-
129-
final PaginatedList<AuthzRoleDTO> result = authzRolesService.findPaginated(
130-
searchQuery, page, perPage, sort, order);
127+
final Predicate<String> roleNamePermissionPredicate = getRoleNamePermissionPredicate();
128+
final PaginatedList<AuthzRoleDTO> result = authzRolesService.findPaginated(roleNamePermissionPredicate, searchQuery, page, perPage, sort, order);
131129
final Map<String, Set<Map<String, String>>> userRoleMap = userRoleContext(result);
132130

133131
return PaginatedResponse.create("roles", result, query, ImmutableMap.of("users", userRoleMap));
@@ -137,7 +135,6 @@ public PaginatedResponse<AuthzRoleDTO> getList(
137135
@ApiOperation(value = "Get a paginated list of users for a role")
138136
@Path("/{roleId}/assignees")
139137
@Produces(MediaType.APPLICATION_JSON)
140-
@RequiresPermissions(RestPermissions.USERS_LIST)
141138
public PaginatedResponse<UserOverviewDTO> getUsersForRole(
142139
@ApiParam(name = "roleId") @PathParam("roleId") @NotEmpty String roleId,
143140
@ApiParam(name = "page") @QueryParam("page") @DefaultValue("1") int page,
@@ -158,10 +155,12 @@ public PaginatedResponse<UserOverviewDTO> getUsersForRole(
158155
throw new BadRequestException("Invalid argument in search query: " + e.getMessage());
159156
}
160157

161-
final PaginatedList<UserOverviewDTO> result = paginatedUserService.findPaginatedByRole(
162-
searchQuery, page, perPage, sort, order, ImmutableSet.of(roleId));
158+
final Predicate<String> userNamePermissionPredicate = roleName -> isPermitted(RestPermissions.USERS_READ, roleName);
159+
final Predicate<String> roleNamePermissionPredicate = getRoleNamePermissionPredicate();
160+
161+
final PaginatedList<UserOverviewDTO> result = paginatedUserService.findPaginatedByRole(userNamePermissionPredicate, searchQuery, page, perPage, sort, order, ImmutableSet.of(roleId));
163162
final Set<String> roleIds = result.stream().flatMap(u -> u.roles().stream()).collect(Collectors.toSet());
164-
final Map<String, String> rolesMap = authzRolesService.findPaginatedByIds(
163+
final Map<String, String> rolesMap = authzRolesService.findPaginatedByIds(roleNamePermissionPredicate,
165164
new SearchQuery(""), 0, 0, AuthzRoleDTO.FIELD_NAME, SortOrder.ASCENDING, roleIds)
166165
.stream().collect(Collectors.toMap(AuthzRoleDTO::id, AuthzRoleDTO::name));
167166
final List<UserOverviewDTO> users = result.stream().map(u -> {
@@ -174,6 +173,10 @@ public PaginatedResponse<UserOverviewDTO> getUsersForRole(
174173
return PaginatedResponse.create("users", enrichedResult, query);
175174
}
176175

176+
private Predicate<String> getRoleNamePermissionPredicate() {
177+
return roleName -> isPermitted(RestPermissions.ROLES_READ, roleName);
178+
}
179+
177180
@GET
178181
@ApiOperation(value = "Get a single role")
179182
@Path("{roleId}")
@@ -187,7 +190,6 @@ public AuthzRoleDTO get(@ApiParam(name = "roleId") @PathParam("roleId") @NotBlan
187190
@GET
188191
@ApiOperation(value = "Get a paginated list roles for a user")
189192
@Path("/user/{username}")
190-
@RequiresPermissions(RestPermissions.ROLES_READ)
191193
public PaginatedResponse<AuthzRoleDTO> getListForUser(
192194
@ApiParam(name = "username") @PathParam("username") @NotEmpty String username,
193195
@ApiParam(name = "page") @QueryParam("page") @DefaultValue("1") int page,
@@ -208,10 +210,11 @@ public PaginatedResponse<AuthzRoleDTO> getListForUser(
208210
throw new BadRequestException("Invalid argument in search query: " + e.getMessage());
209211
}
210212

213+
checkPermission(RestPermissions.USERS_READ, username);
211214
final User user = Optional.ofNullable(userService.load(username))
212215
.orElseThrow(() -> new NotFoundException("Couldn't find user: " + username));
213-
214-
final PaginatedList<AuthzRoleDTO> result = authzRolesService.findPaginatedByIds(
216+
final Predicate<String> roleNamePermissionPredicate = getRoleNamePermissionPredicate();
217+
final PaginatedList<AuthzRoleDTO> result = authzRolesService.findPaginatedByIds(roleNamePermissionPredicate,
215218
searchQuery, page, perPage, sort, order, user.getRoleIds());
216219
return PaginatedResponse.create("roles", result, query);
217220
}
@@ -283,7 +286,8 @@ public void delete(@ApiParam(name = "roleId") @PathParam("roleId") @NotBlank Str
283286

284287

285288
private Map<String, Set<Map<String, String>>> userRoleContext(PaginatedList<AuthzRoleDTO> roles) {
286-
final PaginatedList<UserOverviewDTO> users = paginatedUserService.findPaginatedByRole(new SearchQuery(""),
289+
final Predicate<String> userNamePermissionPredicate = roleName -> isPermitted(RestPermissions.USERS_READ, roleName);
290+
final PaginatedList<UserOverviewDTO> users = paginatedUserService.findPaginatedByRole(userNamePermissionPredicate, new SearchQuery(""),
287291
1, 0, UserOverviewDTO.FIELD_USERNAME, SortOrder.ASCENDING,
288292
roles.stream().map(AuthzRoleDTO::id).collect(Collectors.toSet()));
289293
final Map<String, Set<Map<String, String>>> userRoleMap = new HashMap<>(roles.size());

graylog2-server/src/main/java/org/graylog/security/authzroles/PaginatedAuthzRolesService.java

Lines changed: 5 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -78,39 +78,18 @@ public List<AuthzRoleDTO> findByIds(Collection<String> ids) {
7878
return collection.find(MongoUtils.stringIdsIn(ids)).into(new ArrayList<>());
7979
}
8080

81-
/**
82-
* @deprecated Use {@link #findPaginated(SearchQuery, int, int, String, SortOrder)}
83-
*/
84-
@Deprecated
85-
public PaginatedList<AuthzRoleDTO> findPaginated(SearchQuery searchQuery, int page,
86-
int perPage, String sortField, String order) {
87-
return findPaginated(searchQuery, page, perPage, sortField, SortOrder.fromString(order));
88-
}
89-
90-
public PaginatedList<AuthzRoleDTO> findPaginated(SearchQuery searchQuery, int page,
81+
public PaginatedList<AuthzRoleDTO> findPaginated(Predicate<String> roleNamePermissionPredicate, SearchQuery searchQuery, int page,
9182
int perPage, String sortField, SortOrder order) {
9283
return paginationHelper
9384
.filter(searchQuery.toBson())
9485
.sort(order.toBsonSort(sortField))
9586
.perPage(perPage)
9687
.includeGrandTotal(true)
97-
.page(page);
98-
}
99-
100-
/**
101-
* @deprecated use {@link #findPaginatedByIds(SearchQuery, int, int, String, SortOrder, Set)}
102-
*/
103-
@Deprecated
104-
public PaginatedList<AuthzRoleDTO> findPaginatedByIds(SearchQuery searchQuery,
105-
int page,
106-
int perPage,
107-
String sortField,
108-
String order,
109-
Set<String> roleIds) {
110-
return findPaginatedByIds(searchQuery, page, perPage, sortField, SortOrder.fromString(order), roleIds);
88+
.page(page, role -> roleNamePermissionPredicate.test(role.name()));
11189
}
11290

113-
public PaginatedList<AuthzRoleDTO> findPaginatedByIds(SearchQuery searchQuery,
91+
public PaginatedList<AuthzRoleDTO> findPaginatedByIds(Predicate<String> roleNamePermissionPredicate,
92+
SearchQuery searchQuery,
11493
int page,
11594
int perPage,
11695
String sortField,
@@ -121,7 +100,7 @@ public PaginatedList<AuthzRoleDTO> findPaginatedByIds(SearchQuery searchQuery,
121100
.sort(order.toBsonSort(sortField))
122101
.perPage(perPage)
123102
.includeGrandTotal(true)
124-
.page(page);
103+
.page(page, role -> roleNamePermissionPredicate.test(role.name()));
125104
}
126105

127106
/**

graylog2-server/src/main/java/org/graylog/security/shares/PluggableEntityHandler.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,12 @@ public interface PluggableEntityHandler {
2828
*/
2929
void onCreate(GRN entity, Set<GRN> collections);
3030

31+
/**
32+
* Returns a predicate that tests whether a given GRN should be excluded from handling by this Entity Handler.
33+
*
34+
* @return a predicate that returns {@code true} if the GRN should not be handled,
35+
* or {@code false} if it can be handled
36+
*/
3137
Predicate<GRN> entityFilter();
3238

3339
Stream<GRN> expand(GRN grn);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*
2+
* Copyright (C) 2020 Graylog, Inc.
3+
*
4+
* This program is free software: you can redistribute it and/or modify
5+
* it under the terms of the Server Side Public License, version 1,
6+
* as published by MongoDB, Inc.
7+
*
8+
* This program is distributed in the hope that it will be useful,
9+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
10+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11+
* Server Side Public License for more details.
12+
*
13+
* You should have received a copy of the Server Side Public License
14+
* along with this program. If not, see
15+
* <http://www.mongodb.com/licensing/server-side-public-license>.
16+
*/
17+
package org.graylog2.rest.models.users.responses;
18+
19+
public record UsernameAvailabilityResponse(String username, boolean available) { }

0 commit comments

Comments
 (0)