Skip to content

Commit

Permalink
New permissions for profiles. Fixed permission checks in a few places… (
Browse files Browse the repository at this point in the history
#17986)

* New permissions for profiles. Fixed permission checks in a few places. Migration to upgrade built-in role.

* Improved role name in migration

* More verbose naming of profiles permissions

* Permission naming more verbose in constants as well
  • Loading branch information
luk-kaminski authored Jan 19, 2024
1 parent 383de5a commit 75ce9ac
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 15 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.graylog2.indexer;

import org.graylog2.migrations.V20230905081400_CreateFieldTypeMappingsManagerRole;
import org.graylog2.migrations.V20240118130000_FieldTypeMappingsManagerRoleReceivesProfilePermissions;
import org.graylog2.plugin.PluginModule;
import org.graylog2.rest.resources.system.field_types.FieldTypeMappingsResource;

Expand All @@ -25,5 +26,6 @@ public class FieldTypeManagementModule extends PluginModule {
protected void configure() {
addSystemRestResource(FieldTypeMappingsResource.class);
addMigration(V20230905081400_CreateFieldTypeMappingsManagerRole.class);
addMigration(V20240118130000_FieldTypeMappingsManagerRoleReceivesProfilePermissions.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (C) 2020 Graylog, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the Server Side Public License, version 1,
* as published by MongoDB, Inc.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* Server Side Public License for more details.
*
* You should have received a copy of the Server Side Public License
* along with this program. If not, see
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
package org.graylog2.migrations;

import jakarta.inject.Inject;
import org.graylog2.shared.security.RestPermissions;

import java.time.ZonedDateTime;
import java.util.Set;

public class V20240118130000_FieldTypeMappingsManagerRoleReceivesProfilePermissions extends Migration {
private final MigrationHelpers helpers;

@Inject
public V20240118130000_FieldTypeMappingsManagerRoleReceivesProfilePermissions(final MigrationHelpers migrationHelpers) {
this.helpers = migrationHelpers;
}

@Override
public ZonedDateTime createdAt() {
return ZonedDateTime.parse("2024-01-18T13:00:00Z");
}

@Override
public void upgrade() {
helpers.ensureBuiltinRole("Field Type Mappings Manager",
"Grants full control over custom field type mappings and field type profiles for all index sets (built-in)",
Set.of(RestPermissions.TYPE_MAPPINGS_CREATE,
RestPermissions.TYPE_MAPPINGS_DELETE,
RestPermissions.TYPE_MAPPINGS_EDIT,
RestPermissions.TYPE_MAPPINGS_READ,
RestPermissions.MAPPING_PROFILES_CREATE,
RestPermissions.MAPPING_PROFILES_DELETE,
RestPermissions.MAPPING_PROFILES_EDIT,
RestPermissions.MAPPING_PROFILES_READ));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,6 @@
import io.swagger.annotations.ApiParam;
import io.swagger.annotations.ApiResponse;
import io.swagger.annotations.ApiResponses;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.graylog2.audit.jersey.AuditEvent;
import org.graylog2.indexer.fieldtypes.mapping.FieldTypeMappingsService;
import org.graylog2.indexer.indexset.CustomFieldMapping;
import org.graylog2.indexer.indexset.CustomFieldMappings;
import org.graylog2.rest.bulk.model.BulkOperationResponse;
import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.shared.security.RestPermissions;

import jakarta.inject.Inject;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotNull;
Expand All @@ -40,6 +31,15 @@
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.Response;
import org.apache.shiro.authz.annotation.RequiresAuthentication;
import org.graylog2.audit.jersey.AuditEvent;
import org.graylog2.indexer.fieldtypes.mapping.FieldTypeMappingsService;
import org.graylog2.indexer.indexset.CustomFieldMapping;
import org.graylog2.indexer.indexset.CustomFieldMappings;
import org.graylog2.rest.bulk.model.BulkOperationResponse;
import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.shared.security.RestPermissions;

import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
Expand Down Expand Up @@ -82,7 +82,7 @@ public Map<String, String> getAllFieldTypes() {
public Response changeFieldType(@ApiParam(name = "request")
@Valid
@NotNull(message = "Request body is mandatory") final FieldTypeChangeRequest request) {
checkPermissionsForCreation(request.indexSetsIds());
checkPermissions(request.indexSetsIds(), RestPermissions.TYPE_MAPPINGS_CREATE);

var customMapping = new CustomFieldMapping(request.fieldName(), request.type());
fieldTypeMappingsService.changeFieldType(customMapping, request.indexSetsIds(), request.rotateImmediately());
Expand All @@ -101,7 +101,7 @@ public Response changeFieldType(@ApiParam(name = "request")
public Response setProfile(@ApiParam(name = "request")
@Valid
@NotNull(message = "Request body is mandatory") final FieldTypeProfileChangeRequest request) {
checkPermissionsForCreation(request.indexSetsIds());
checkPermissions(request.indexSetsIds(), RestPermissions.INDEXSETS_EDIT);
fieldTypeMappingsService.setProfile(request.indexSetsIds(), request.profileId(), request.rotateImmediately());

return Response.ok().build();
Expand All @@ -118,7 +118,7 @@ public Response setProfile(@ApiParam(name = "request")
public Response removeProfileFromIndexSets(@ApiParam(name = "request")
@Valid
@NotNull(message = "Request body is mandatory") final FieldTypeProfileUnsetRequest request) {
checkPermissionsForCreation(request.indexSetsIds());
checkPermissions(request.indexSetsIds(), RestPermissions.INDEXSETS_EDIT);
fieldTypeMappingsService.removeProfileFromIndexSets(request.indexSetsIds(), request.rotateImmediately());

return Response.ok().build();
Expand All @@ -135,12 +135,12 @@ public Response removeProfileFromIndexSets(@ApiParam(name = "request")
public Map<String, BulkOperationResponse> removeCustomMapping(@ApiParam(name = "request")
@Valid
@NotNull(message = "Request body is mandatory") final CustomFieldMappingRemovalRequest request) {
checkPermissionsForCreation(request.indexSetsIds());
checkPermissions(request.indexSetsIds(), RestPermissions.TYPE_MAPPINGS_DELETE);

return fieldTypeMappingsService.removeCustomMappingForFields(request.fieldNames(), request.indexSetsIds(), request.rotateImmediately());
}

private void checkPermissionsForCreation(final Set<String> indexSetsIds) {
indexSetsIds.forEach(indexSetId -> checkPermission(RestPermissions.TYPE_MAPPINGS_CREATE, indexSetId));
private void checkPermissions(final Set<String> indexSetsIds, final String permission) {
indexSetsIds.forEach(indexSetId -> checkPermission(permission, indexSetId));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
import org.graylog2.indexer.indexset.profile.IndexFieldTypeProfileWithUsages;
import org.graylog2.rest.models.tools.responses.PageListResponse;
import org.graylog2.shared.rest.resources.RestResource;
import org.graylog2.shared.security.RestPermissions;

import java.util.List;

Expand Down Expand Up @@ -71,6 +72,7 @@ public IndexFieldTypeProfileResource(final IndexFieldTypeProfileService profileS
@NoAuditEvent("No change to the DB")
@ApiOperation(value = "Gets profile by id")
public IndexFieldTypeProfileWithUsages retrieveById(@ApiParam(name = "profile_id") @PathParam("profile_id") String profileId) {
checkPermission(RestPermissions.MAPPING_PROFILES_READ, profileId);
return profileService.getWithUsages(profileId)
.orElseThrow(() -> new NotFoundException("No profile with id : " + profileId));
}
Expand All @@ -91,6 +93,7 @@ public PageListResponse<IndexFieldTypeProfileWithUsages> getPage(@ApiParam(name
@DefaultValue(IndexFieldTypeProfile.NAME_FIELD_NAME) @QueryParam("sort") String sort,
@ApiParam(name = "order", value = "The sort direction", allowableValues = "asc, desc")
@DefaultValue("asc") @QueryParam("order") String order) {
checkPermission(RestPermissions.MAPPING_PROFILES_READ);
return profileService.getPaginated(query, filters, page, perPage, sort, order);
}

Expand All @@ -100,6 +103,7 @@ public PageListResponse<IndexFieldTypeProfileWithUsages> getPage(@ApiParam(name
@NoAuditEvent("No change to the DB")
@ApiOperation(value = "Gets list of all profiles (their ids and names only)")
public List<IndexFieldTypeProfileIdAndName> getAll() {
checkPermission(RestPermissions.MAPPING_PROFILES_READ);
return profileService.getAll();
}

Expand All @@ -108,6 +112,7 @@ public List<IndexFieldTypeProfileIdAndName> getAll() {
@AuditEvent(type = INDEX_FIELD_TYPE_PROFILE_CREATE)
@ApiOperation(value = "Creates a new profile")
public IndexFieldTypeProfile create(@ApiParam(name = "profileData") IndexFieldTypeProfileData profileData) {
checkPermission(RestPermissions.MAPPING_PROFILES_CREATE);
return profileService.save(new IndexFieldTypeProfile(profileData));
}

Expand All @@ -116,6 +121,7 @@ public IndexFieldTypeProfile create(@ApiParam(name = "profileData") IndexFieldTy
@AuditEvent(type = INDEX_FIELD_TYPE_PROFILE_UPDATE)
@ApiOperation(value = "Updates existing profile")
public void update(@ApiParam(name = "profile") IndexFieldTypeProfile profile) {
checkPermission(RestPermissions.MAPPING_PROFILES_EDIT, profile.id());
final boolean updated = profileService.update(profile.id(), profile);
if (!updated) {
throw new NotFoundException("Profile does not exist : " + profile.id());
Expand All @@ -128,6 +134,7 @@ public void update(@ApiParam(name = "profile") IndexFieldTypeProfile profile) {
@AuditEvent(type = INDEX_FIELD_TYPE_PROFILE_DELETE)
@ApiOperation(value = "Removes a profile")
public void delete(@ApiParam(name = "profile_id") @PathParam("profile_id") String profileId) {
checkPermission(RestPermissions.MAPPING_PROFILES_DELETE, profileId);
profileService.delete(profileId);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@ public class RestPermissions implements PluginPermissions {
public static final String TYPE_MAPPINGS_DELETE = "typemappings:delete";
public static final String TYPE_MAPPINGS_EDIT = "typemappings:edit";
public static final String TYPE_MAPPINGS_READ = "typemappings:read";
public static final String MAPPING_PROFILES_CREATE = "mappingprofiles:create";
public static final String MAPPING_PROFILES_DELETE = "mappingprofiles:delete";
public static final String MAPPING_PROFILES_EDIT = "mappingprofiles:edit";
public static final String MAPPING_PROFILES_READ = "mappingprofiles:read";
public static final String URL_WHITELIST_READ = "urlwhitelist:read";
public static final String URL_WHITELIST_WRITE = "urlwhitelist:write";
public static final String USERS_CREATE = "users:create";
Expand Down Expand Up @@ -302,6 +306,14 @@ public class RestPermissions implements PluginPermissions {
.add(create(SEARCH_FILTERS_READ, ""))
.add(create(SEARCH_FILTERS_EDIT, ""))
.add(create(SEARCH_FILTERS_DELETE, ""))
.add(create(TYPE_MAPPINGS_CREATE, ""))
.add(create(TYPE_MAPPINGS_DELETE, ""))
.add(create(TYPE_MAPPINGS_EDIT, ""))
.add(create(TYPE_MAPPINGS_READ, ""))
.add(create(MAPPING_PROFILES_CREATE, ""))
.add(create(MAPPING_PROFILES_DELETE, ""))
.add(create(MAPPING_PROFILES_EDIT, ""))
.add(create(MAPPING_PROFILES_READ, ""))
.build();

// Standard set of PERMISSIONS of readers.
Expand Down

0 comments on commit 75ce9ac

Please sign in to comment.