From 828a88b0d268d55c414541f3b92408190d2ff429 Mon Sep 17 00:00:00 2001 From: Mikel Alejo Barcina Ribera Date: Fri, 14 Feb 2025 15:06:11 +0100 Subject: [PATCH 1/2] refactor: authorization in handlers The changes make use of the new "Authorization" annotation to simplify the code and improve maintainability. RHCLOUD-37536 --- .../handlers/endpoint/EndpointResource.java | 329 +++--------------- .../handlers/endpoint/EndpointResourceV2.java | 52 ++- .../routers/handlers/event/EventResource.java | 23 +- .../notification/NotificationResource.java | 312 ++--------------- .../handlers/orgconfig/OrgConfigResource.java | 57 +-- .../endpoint/EndpointResourceTest.java | 5 +- 6 files changed, 125 insertions(+), 653 deletions(-) diff --git a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java index 31d3cef53c..b577f27072 100644 --- a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java +++ b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java @@ -2,6 +2,8 @@ import com.redhat.cloud.notifications.Constants; import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider; +import com.redhat.cloud.notifications.auth.annotation.Authorization; +import com.redhat.cloud.notifications.auth.annotation.IntegrationId; import com.redhat.cloud.notifications.auth.kessel.KesselAssets; import com.redhat.cloud.notifications.auth.kessel.KesselAuthorization; import com.redhat.cloud.notifications.auth.kessel.permission.IntegrationPermission; @@ -46,7 +48,6 @@ import com.redhat.cloud.notifications.routers.sources.SecretUtils; import io.quarkus.logging.Log; import io.vertx.core.json.JsonObject; -import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.validation.Valid; @@ -185,28 +186,14 @@ static class V1 extends EndpointResource { schema = @Schema(type = SchemaType.BOOLEAN) ) }) - public List getEndpointHistory(@Context SecurityContext sec, @PathParam("id") UUID id, @QueryParam("includeDetail") Boolean includeDetail, @BeanParam Query query) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW_HISTORY, id); - - return this.internalGetEndpointHistory(sec, id, includeDetail, query); - } else { - return this.legacyRBACGetEndpointHistory(sec, id, includeDetail, query); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS) - protected List legacyRBACGetEndpointHistory(final SecurityContext securityContext, final UUID id, final Boolean includeDetail, final Query query) { - return this.internalGetEndpointHistory(securityContext, id, includeDetail, query); - } - - protected List internalGetEndpointHistory(final SecurityContext securityContext, final UUID id, final Boolean includeDetail, @Valid final Query query) { - if (!this.endpointRepository.existsByUuidAndOrgId(id, getOrgId(securityContext))) { + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.VIEW_HISTORY}) + public List getEndpointHistory(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID id, @QueryParam("includeDetail") Boolean includeDetail, @Valid @BeanParam Query query) { + if (!this.endpointRepository.existsByUuidAndOrgId(id, getOrgId(sec))) { throw new NotFoundException("Endpoint not found"); } // TODO We need globally limitations (Paging support and limits etc) - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); boolean doDetail = includeDetail != null && includeDetail; return commonMapper.notificationHistoryListToNotificationHistoryDTOList(notificationRepository.getNotificationHistory(orgId, id, doDetail, query)); } @@ -236,34 +223,24 @@ public EndpointPage getEndpoints( @QueryParam("active") Boolean activeOnly, @QueryParam("name") String name ) { + Set authorizedIds = null; if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { // Fetch the set of integration IDs the user is authorized to view. - final Set authorizedIds = this.kesselAuthorization.lookupAuthorizedIntegrations(sec, IntegrationPermission.VIEW); + authorizedIds = this.kesselAuthorization.lookupAuthorizedIntegrations(sec, IntegrationPermission.VIEW); if (authorizedIds.isEmpty()) { Log.infof("[org_id: %s][username: %s] Kessel did not return any integration IDs for the request", getOrgId(sec), getUsername(sec)); return new EndpointPage(new ArrayList<>(), new HashMap<>(), new Meta(0L)); } - - return this.internalGetEndpoints(sec, query, targetType, activeOnly, name, authorizedIds, false); } else { - return this.getEndpointsLegacyRBACRoles(sec, query, targetType, activeOnly, name, false); + // Legacy RBAC permission checking. The permission will have been + // prefetched and processed by the "ConsoleIdentityProvider". + if (!sec.isUserInRole(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS)) { + throw new ForbiddenException(); + } } - } - /** - * Gets the list of endpoints. Checks the principal's authorization by - * looking at its roles. - * @param securityContext the security context of the request. - * @param query the page related query elements. - * @param targetType the types of the endpoints to fetch. - * @param activeOnly should only the active endpoints be fetched? - * @param name filter endpoints by name. - * @return a page containing the requested endpoints. - */ - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS) - protected EndpointPage getEndpointsLegacyRBACRoles(final SecurityContext securityContext, final Query query, final List targetType, final Boolean activeOnly, final String name, final boolean includeLinkedEventTypes) { - return this.internalGetEndpoints(securityContext, query, targetType, activeOnly, name, null, includeLinkedEventTypes); + return internalGetEndpoints(sec, query, targetType, activeOnly, name, authorizedIds, false); } /** @@ -335,32 +312,16 @@ protected EndpointPage internalGetEndpoints( @APIResponse(responseCode = "200", content = @Content(mediaType = APPLICATION_JSON, schema = @Schema(implementation = EndpointDTO.class))), @APIResponse(responseCode = "400", description = "Bad data passed, that does not correspond to the definition or Endpoint.properties are empty") }) + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, workspacePermissions = {WorkspacePermission.INTEGRATIONS_CREATE}) public EndpointDTO createEndpoint( - @Context SecurityContext sec, - @RequestBody(required = true) EndpointDTO endpointDTO + @Context final SecurityContext sec, + @NotNull @Valid @RequestBody(required = true) final EndpointDTO endpointDTO ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.INTEGRATIONS_CREATE, workspaceId); - - return this.internalCreateEndpoint(sec, endpointDTO); - } else { - return this.legacyRBACCreateEndpoint(sec, endpointDTO); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS) - protected EndpointDTO legacyRBACCreateEndpoint(final SecurityContext securityContext, final EndpointDTO endpointDTO) { - return this.internalCreateEndpoint(securityContext, endpointDTO); - } - - protected EndpointDTO internalCreateEndpoint(final SecurityContext securityContext, @NotNull @Valid final EndpointDTO endpointDTO) { final Endpoint endpoint = this.endpointMapper.toEntity(endpointDTO); try { return this.endpointMapper.toDTO( - this.internalCreateEndpoint(securityContext, endpoint, endpointDTO.eventTypes) + this.internalCreateEndpoint(sec, endpoint, endpointDTO.eventTypes) ); } catch (final Exception e) { // Clean up the secrets from Sources if any were created. @@ -465,21 +426,10 @@ private void checkHttpsEndpoint(CamelProperties camelProperties) { @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @Operation(summary = "Create an email subscription endpoint", description = "Adds the email subscription endpoint into the system and specifies the role-based access control (RBAC) group that will receive email notifications. Use this endpoint in behavior groups to send emails when an action linked to the behavior group is triggered.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, workspacePermissions = {WorkspacePermission.CREATE_EMAIL_SUBSCRIPTION_INTEGRATION}) @Transactional - public EndpointDTO getOrCreateEmailSubscriptionEndpoint(@Context SecurityContext sec, @RequestBody(required = true) RequestSystemSubscriptionProperties requestProps) { - final Endpoint endpoint; - - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.CREATE_EMAIL_SUBSCRIPTION_INTEGRATION, workspaceId); - - endpoint = this.getOrCreateSystemSubscriptionEndpoint(sec, requestProps, EMAIL_SUBSCRIPTION); - } else { - endpoint = this.legacyRBACGetOrCreateSystemSubscriptionEndpoint(sec, requestProps, EMAIL_SUBSCRIPTION); - } - - return this.endpointMapper.toDTO(endpoint); + public EndpointDTO getOrCreateEmailSubscriptionEndpoint(@Context SecurityContext sec, @NotNull @Valid @RequestBody(required = true) RequestSystemSubscriptionProperties requestProps) { + return this.endpointMapper.toDTO(getOrCreateSystemSubscriptionEndpoint(sec, requestProps, EMAIL_SUBSCRIPTION)); } @POST @@ -487,29 +437,13 @@ public EndpointDTO getOrCreateEmailSubscriptionEndpoint(@Context SecurityContext @Consumes(APPLICATION_JSON) @Produces(APPLICATION_JSON) @Operation(summary = "Add a drawer endpoint", description = "Adds the drawer system endpoint into the system and specifies the role-based access control (RBAC) group that will receive notifications. Use this endpoint to add an animation as a notification in the UI.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, workspacePermissions = {WorkspacePermission.CREATE_DRAWER_INTEGRATION}) @Transactional - public EndpointDTO getOrCreateDrawerSubscriptionEndpoint(@Context SecurityContext sec, @RequestBody(required = true) RequestSystemSubscriptionProperties requestProps) { - final Endpoint endpoint; - - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.CREATE_DRAWER_INTEGRATION, workspaceId); - - endpoint = this.getOrCreateSystemSubscriptionEndpoint(sec, requestProps, DRAWER); - } else { - endpoint = this.legacyRBACGetOrCreateSystemSubscriptionEndpoint(sec, requestProps, DRAWER); - } - - return this.endpointMapper.toDTO(endpoint); - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS) - protected Endpoint legacyRBACGetOrCreateSystemSubscriptionEndpoint(final SecurityContext securityContext, final RequestSystemSubscriptionProperties requestProps, final EndpointType endpointType) { - return this.getOrCreateSystemSubscriptionEndpoint(securityContext, requestProps, endpointType); + public EndpointDTO getOrCreateDrawerSubscriptionEndpoint(@Context SecurityContext sec, @NotNull @Valid @RequestBody(required = true) RequestSystemSubscriptionProperties requestProps) { + return this.endpointMapper.toDTO(this.getOrCreateSystemSubscriptionEndpoint(sec, requestProps, DRAWER)); } - protected Endpoint getOrCreateSystemSubscriptionEndpoint(SecurityContext sec, @NotNull @Valid RequestSystemSubscriptionProperties requestProps, EndpointType endpointType) { + protected Endpoint getOrCreateSystemSubscriptionEndpoint(SecurityContext sec, RequestSystemSubscriptionProperties requestProps, EndpointType endpointType) { RhIdPrincipal principal = (RhIdPrincipal) sec.getUserPrincipal(); String accountId = getAccountId(sec); String orgId = getOrgId(sec); @@ -555,19 +489,9 @@ private void getOrCreateInternalEndpointCommonChecks(RequestSystemSubscriptionPr @Path("/{id}") @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve an endpoint", description = "Retrieves the public information associated with an endpoint such as its description, name, and properties.") - public EndpointDTO getEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW, id); - - return this.internalGetEndpoint(sec, id, false); - } else { - return this.legacyGetEndpoint(sec, id, false); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS) - protected EndpointDTO legacyGetEndpoint(final SecurityContext securityContext, final UUID id, final boolean includeLinkedEventTypes) { - return this.internalGetEndpoint(securityContext, id, includeLinkedEventTypes); + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.VIEW}) + public EndpointDTO getEndpoint(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID id) { + return internalGetEndpoint(sec, id, false); } protected EndpointDTO internalGetEndpoint(final SecurityContext securityContext, final UUID id, final boolean includeLinkedEventTypes) { @@ -594,24 +518,10 @@ protected EndpointDTO internalGetEndpoint(final SecurityContext securityContext, @Path("/{id}") @Operation(summary = "Delete an endpoint", description = "Deletes an endpoint. Use this endpoint to delete an endpoint that is no longer needed. Deleting an endpoint that is already linked to a behavior group will unlink it from the behavior group. You cannot delete system endpoints.") @APIResponse(responseCode = "204", description = "The integration has been deleted", content = @Content(schema = @Schema(type = SchemaType.STRING))) + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.DELETE}) @Transactional - public Response deleteEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.DELETE, id); - - return this.internalDeleteEndpoint(sec, id); - } else { - return this.legacyRBACDeleteEndpoint(sec, id); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS) - protected Response legacyRBACDeleteEndpoint(final SecurityContext securityContext, final UUID id) { - return this.internalDeleteEndpoint(securityContext, id); - } - - private Response internalDeleteEndpoint(final SecurityContext securityContext, final UUID id) { - String orgId = getOrgId(securityContext); + public Response deleteEndpoint(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID id) { + String orgId = getOrgId(sec); EndpointType endpointType = endpointRepository.getEndpointTypeById(orgId, id); if (!isEndpointTypeAllowed(endpointType)) { throw new BadRequestException(UNSUPPORTED_ENDPOINT_TYPE); @@ -629,7 +539,7 @@ private Response internalDeleteEndpoint(final SecurityContext securityContext, f // integration will not be deleted from our database. final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(orgId); - this.kesselAssets.deleteIntegration(securityContext, workspaceId.toString(), id.toString()); + this.kesselAssets.deleteIntegration(sec, workspaceId.toString(), id.toString()); } // Attempt deleting the secrets for the given endpoint. In the case @@ -646,7 +556,7 @@ private Response internalDeleteEndpoint(final SecurityContext securityContext, f if (this.backendConfig.isKesselInventoryEnabled(orgId)) { final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(orgId); - this.kesselAssets.createIntegration(securityContext, workspaceId.toString(), id.toString()); + this.kesselAssets.createIntegration(sec, workspaceId.toString(), id.toString()); } throw e; @@ -660,24 +570,10 @@ private Response internalDeleteEndpoint(final SecurityContext securityContext, f @Produces(TEXT_PLAIN) @Operation(summary = "Enable an endpoint", description = "Enables an endpoint that is disabled so that the endpoint will be executed on the following operations that use the endpoint. An operation must be restarted to use the enabled endpoint.") @APIResponse(responseCode = "200", content = @Content(schema = @Schema(type = SchemaType.STRING))) + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.ENABLE}) @Transactional - public Response enableEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.ENABLE, id); - - return this.internalEnableEndpoint(sec, id); - } else { - return this.legacyRBACEnableEndpoint(sec, id); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS) - protected Response legacyRBACEnableEndpoint(final SecurityContext securityContext, final UUID id) { - return this.internalEnableEndpoint(securityContext, id); - } - - private Response internalEnableEndpoint(final SecurityContext securityContext, final UUID id) { - String orgId = getOrgId(securityContext); + public Response enableEndpoint(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID id) { + String orgId = getOrgId(sec); EndpointType endpointType = endpointRepository.getEndpointTypeById(orgId, id); if (!isEndpointTypeAllowed(endpointType)) { throw new BadRequestException(UNSUPPORTED_ENDPOINT_TYPE); @@ -692,23 +588,9 @@ private Response internalEnableEndpoint(final SecurityContext securityContext, f @Operation(summary = "Disable an endpoint", description = "Disables an endpoint so that the endpoint will not be executed after an operation that uses the endpoint is started. An operation that is already running can still execute the endpoint. Disable an endpoint when you want to stop it from running and might want to re-enable it in the future.") @APIResponse(responseCode = "204", description = "The integration has been disabled", content = @Content(schema = @Schema(type = SchemaType.STRING))) @Transactional - public Response disableEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.DISABLE, id); - - return this.internalDisableEndpoint(sec, id); - } else { - return this.legacyRBACDisableEndpoint(sec, id); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS) - protected Response legacyRBACDisableEndpoint(final SecurityContext securityContext, final UUID id) { - return this.internalDisableEndpoint(securityContext, id); - } - - private Response internalDisableEndpoint(final SecurityContext securityContext, final UUID id) { - String orgId = getOrgId(securityContext); + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.DISABLE}) + public Response disableEndpoint(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID id) { + String orgId = getOrgId(sec); EndpointType endpointType = endpointRepository.getEndpointTypeById(orgId, id); if (!isEndpointTypeAllowed(endpointType)) { throw new BadRequestException(UNSUPPORTED_ENDPOINT_TYPE); @@ -724,42 +606,13 @@ private Response internalDisableEndpoint(final SecurityContext securityContext, @Path("/{id}") @Produces(TEXT_PLAIN) @PUT + @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.EDIT}) public Response updateEndpoint( @Context SecurityContext securityContext, - @PathParam("id") UUID id, + @PathParam("id") @IntegrationId UUID id, @RequestBody(required = true) @NotNull @Valid EndpointDTO endpointDTO ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - this.kesselAuthorization.hasPermissionOnIntegration(securityContext, IntegrationPermission.EDIT, id); - - return this.internalUpdateEndpoint(securityContext, id, endpointDTO); - } - - return this.updateEndpointLegacyRBACRoles(securityContext, id, endpointDTO); - } - - /** - * Updates an endpoint. Checks the principal's authorization by looking at - * its roles. - * @param securityContext the security context of the request. - * @param endpointId the ID of the endpoint to be updated. - * @param endpointDTO the received request body. - * @return a response specifying the outcome of the operation. - */ - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS) - protected Response updateEndpointLegacyRBACRoles(final SecurityContext securityContext, final UUID endpointId, final EndpointDTO endpointDTO) { - return this.internalUpdateEndpoint(securityContext, endpointId, endpointDTO); - } - - /** - * Updates an endpoint. - * @param sec the security context of the request. - * @param id the endpoint's identifier. - * @param endpointDTO the updated endpoint's body. - * @return a response specifying the outcome of the oeration. - */ - @Transactional - protected Response internalUpdateEndpoint(final SecurityContext sec, final UUID id, final @NotNull @Valid EndpointDTO endpointDTO) { final Endpoint endpoint = this.endpointMapper.toEntity(endpointDTO); if (!isEndpointTypeAllowed(endpoint.getType())) { @@ -767,8 +620,8 @@ protected Response internalUpdateEndpoint(final SecurityContext sec, final UUID } // This prevents from updating an endpoint from whatever EndpointType to a system EndpointType checkSystemEndpoint(endpoint.getType()); - String accountId = getAccountId(sec); - String orgId = getOrgId(sec); + String accountId = getAccountId(securityContext); + String orgId = getOrgId(securityContext); endpoint.setAccountId(accountId); endpoint.setOrgId(orgId); endpoint.setId(id); @@ -815,7 +668,7 @@ protected Response internalUpdateEndpoint(final SecurityContext sec, final UUID } if (null != endpointDTO.eventTypes) { - internalUpdateEventTypesLinkedToEndpoint(sec, id, endpointDTO.eventTypes); + internalUpdateEventTypesLinkedToEndpoint(securityContext, id, endpointDTO.eventTypes); } return Response.ok().build(); } @@ -825,23 +678,9 @@ protected Response internalUpdateEndpoint(final SecurityContext sec, final UUID @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve event notification details", description = "Retrieves extended information about the outcome of an event notification related to the specified endpoint. Use this endpoint to learn why an event delivery failed.") @APIResponse(responseCode = "200", content = @Content(schema = @Schema(type = SchemaType.STRING))) - public Response getDetailedEndpointHistory(@Context SecurityContext sec, @PathParam("id") UUID endpointId, @PathParam("history_id") UUID historyId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW_HISTORY, endpointId); - - return this.internalGetDetailedEndpointHistory(sec, endpointId, historyId); - } else { - return this.legacyRBACGetDetailedEndpointHistory(sec, endpointId, historyId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS) - protected Response legacyRBACGetDetailedEndpointHistory(final SecurityContext securityContext, final UUID endpointId, final UUID historyId) { - return this.internalGetDetailedEndpointHistory(securityContext, endpointId, historyId); - } - - private Response internalGetDetailedEndpointHistory(final SecurityContext securityContext, final UUID endpointId, final UUID historyId) { - String orgId = getOrgId(securityContext); + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.VIEW_HISTORY}) + public Response getDetailedEndpointHistory(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID endpointId, @PathParam("history_id") UUID historyId) { + String orgId = getOrgId(sec); JsonObject json = notificationRepository.getNotificationDetails(orgId, endpointId, historyId); if (json == null) { // Maybe 404 should only be returned if history_id matches nothing? Otherwise 204 @@ -872,29 +711,15 @@ private Response internalGetDetailedEndpointHistory(final SecurityContext securi schema = @Schema(type = SchemaType.STRING) ) }) - public void testEndpoint(@Context SecurityContext sec, @RestPath UUID uuid, @RequestBody final EndpointTestRequest requestBody) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.TEST, uuid); - - this.internalTestEndpoint(sec, uuid, requestBody); - } else { - this.legacyRBACTestEndpoint(sec, uuid, requestBody); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS) - protected void legacyRBACTestEndpoint(final SecurityContext securityContext, final UUID uuid, final EndpointTestRequest requestBody) { - this.internalTestEndpoint(securityContext, uuid, requestBody); - } - - protected void internalTestEndpoint(final SecurityContext securityContext, final UUID uuid, @Valid final EndpointTestRequest requestBody) { - if (!this.endpointRepository.existsByUuidAndOrgId(uuid, getOrgId(securityContext))) { + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.TEST}) + public void testEndpoint(@Context SecurityContext sec, @IntegrationId @RestPath UUID uuid, @Valid @RequestBody final EndpointTestRequest requestBody) { + if (!this.endpointRepository.existsByUuidAndOrgId(uuid, getOrgId(sec))) { throw new NotFoundException("integration not found"); } final InternalEndpointTestRequest internalEndpointTestRequest = new InternalEndpointTestRequest(); internalEndpointTestRequest.endpointUuid = uuid; - internalEndpointTestRequest.orgId = getOrgId(securityContext); + internalEndpointTestRequest.orgId = getOrgId(sec); if (requestBody != null) { internalEndpointTestRequest.message = requestBody.message; } @@ -971,22 +796,8 @@ protected void redactSecretsForEndpoint(final SecurityContext securityContext, f }) @Tag(name = OApiFilter.PRIVATE) @Transactional - public void deleteEventTypeFromEndpoint(@Context final SecurityContext securityContext, @RestPath final UUID eventTypeId, @RestPath final UUID endpointId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - this.kesselAuthorization.hasPermissionOnIntegration(securityContext, IntegrationPermission.EDIT, endpointId); - - internalDeleteEventTypeFromEndpoint(securityContext, eventTypeId, endpointId); - } else { - legacyRBACDeleteEventTypeFromEndpoint(securityContext, eventTypeId, endpointId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - protected void legacyRBACDeleteEventTypeFromEndpoint(final SecurityContext securityContext, final UUID eventTypeId, final UUID endpointId) { - internalDeleteEventTypeFromEndpoint(securityContext, eventTypeId, endpointId); - } - - private void internalDeleteEventTypeFromEndpoint(final SecurityContext securityContext, final UUID eventTypeId, final UUID endpointId) { + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, integrationPermissions = {IntegrationPermission.EDIT}) + public void deleteEventTypeFromEndpoint(@Context final SecurityContext securityContext, @RestPath final UUID eventTypeId, @IntegrationId @RestPath final UUID endpointId) { final String orgId = getOrgId(securityContext); endpointEventTypeRepository.deleteEndpointFromEventType(eventTypeId, endpointId, orgId); @@ -1013,22 +824,8 @@ private void internalDeleteEventTypeFromEndpoint(final SecurityContext securityC }) @Tag(name = OApiFilter.PRIVATE) @Transactional - public void addEventTypeToEndpoint(@Context final SecurityContext securityContext, @RestPath final UUID eventTypeId, @RestPath final UUID endpointId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - this.kesselAuthorization.hasPermissionOnIntegration(securityContext, IntegrationPermission.EDIT, endpointId); - - internalAddEventTypeToEndpoint(securityContext, eventTypeId, endpointId); - } else { - legacyRbacAddEventTypeToEndpoint(securityContext, eventTypeId, endpointId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public void legacyRbacAddEventTypeToEndpoint(final SecurityContext securityContext, final UUID eventTypeId, final UUID endpointId) { - internalAddEventTypeToEndpoint(securityContext, eventTypeId, endpointId); - } - - private void internalAddEventTypeToEndpoint(final SecurityContext securityContext, final UUID eventTypeId, final UUID endpointId) { + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, integrationPermissions = {IntegrationPermission.EDIT}) + public void addEventTypeToEndpoint(@Context final SecurityContext securityContext, @RestPath final UUID eventTypeId, @IntegrationId @RestPath final UUID endpointId) { final String orgId = getOrgId(securityContext); final String accountId = getAccountId(securityContext); @@ -1047,18 +844,8 @@ private void internalAddEventTypeToEndpoint(final SecurityContext securityContex description = "No event type or endpoint found with passed ids.") }) @Transactional - public void updateEventTypesLinkedToEndpoint(@Context final SecurityContext securityContext, @RestPath final UUID endpointId, @Parameter(description = "Set of event type ids to associate") Set eventTypeIds) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - this.kesselAuthorization.hasPermissionOnIntegration(securityContext, IntegrationPermission.EDIT, endpointId); - - internalUpdateEventTypesLinkedToEndpoint(securityContext, endpointId, eventTypeIds); - } else { - legacyRbacUpdateEventTypesLinkedToEndpoint(securityContext, endpointId, eventTypeIds); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public void legacyRbacUpdateEventTypesLinkedToEndpoint(final SecurityContext securityContext, final UUID endpointId, final Set eventTypeIds) { + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, integrationPermissions = {IntegrationPermission.EDIT}) + public void updateEventTypesLinkedToEndpoint(@Context final SecurityContext securityContext, @IntegrationId @RestPath final UUID endpointId, @Parameter(description = "Set of event type ids to associate") Set eventTypeIds) { internalUpdateEventTypesLinkedToEndpoint(securityContext, endpointId, eventTypeIds); } diff --git a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceV2.java b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceV2.java index 53e9ae42f5..8913fba933 100644 --- a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceV2.java +++ b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceV2.java @@ -2,6 +2,8 @@ import com.redhat.cloud.notifications.Constants; import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider; +import com.redhat.cloud.notifications.auth.annotation.Authorization; +import com.redhat.cloud.notifications.auth.annotation.IntegrationId; import com.redhat.cloud.notifications.auth.kessel.permission.IntegrationPermission; import com.redhat.cloud.notifications.db.Query; import com.redhat.cloud.notifications.models.NotificationHistory; @@ -12,9 +14,9 @@ import com.redhat.cloud.notifications.routers.models.Page; import com.redhat.cloud.notifications.routers.models.PageLinksBuilder; import io.quarkus.logging.Log; -import jakarta.annotation.security.RolesAllowed; import jakarta.validation.Valid; import jakarta.ws.rs.BeanParam; +import jakarta.ws.rs.ForbiddenException; import jakarta.ws.rs.GET; import jakarta.ws.rs.NotFoundException; import jakarta.ws.rs.Path; @@ -68,33 +70,19 @@ public class EndpointResourceV2 extends EndpointResource { ) } ) + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.VIEW_HISTORY}) public Page getEndpointHistory( @Context SecurityContext sec, @Context UriInfo uriInfo, - @PathParam("id") UUID id, + @IntegrationId @PathParam("id") UUID id, @QueryParam("includeDetail") Boolean includeDetail, - @BeanParam Query query + @Valid @BeanParam Query query ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW_HISTORY, id); - - return this.internalGetEndpointHistory(sec, uriInfo, id, includeDetail, query); - } else { - return this.legacyRBACGetEndpointHistory(sec, uriInfo, id, includeDetail, query); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS) - protected Page legacyRBACGetEndpointHistory(final SecurityContext securityContext, final UriInfo uriInfo, final UUID id, final Boolean includeDetail, final Query query) { - return this.internalGetEndpointHistory(securityContext, uriInfo, id, includeDetail, query); - } - - protected Page internalGetEndpointHistory(final SecurityContext securityContext, final UriInfo uriInfo, final UUID id, final Boolean includeDetail, @Valid final Query query) { - if (!this.endpointRepository.existsByUuidAndOrgId(id, getOrgId(securityContext))) { + if (!this.endpointRepository.existsByUuidAndOrgId(id, getOrgId(sec))) { throw new NotFoundException("Endpoint not found"); } - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); boolean doDetail = includeDetail != null && includeDetail; final List notificationHistory = this.notificationRepository.getNotificationHistory(orgId, id, doDetail, query); @@ -111,14 +99,9 @@ protected Page internalGetEndpointHistory(final Security @Path("/{id}") @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve an endpoint", description = "Retrieves the public information associated with an endpoint such as its description, name, and properties.") - public EndpointDTO getEndpoint(@Context SecurityContext sec, @PathParam("id") UUID id) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW, id); - - return this.internalGetEndpoint(sec, id, true); - } else { - return legacyGetEndpoint(sec, id, true); - } + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.VIEW}) + public EndpointDTO getEndpoint(@Context SecurityContext sec, @IntegrationId @PathParam("id") UUID id) { + return internalGetEndpoint(sec, id, true); } @GET @@ -147,18 +130,23 @@ public EndpointPage getEndpoints( @QueryParam("active") Boolean activeOnly, @QueryParam("name") String name ) { + Set authorizedIds = null; if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { // Fetch the set of integration IDs the user is authorized to view. - final Set authorizedIds = this.kesselAuthorization.lookupAuthorizedIntegrations(sec, IntegrationPermission.VIEW); + authorizedIds = this.kesselAuthorization.lookupAuthorizedIntegrations(sec, IntegrationPermission.VIEW); if (authorizedIds.isEmpty()) { Log.infof("[org_id: %s][username: %s] Kessel did not return any integration IDs for the request", getOrgId(sec), getUsername(sec)); return new EndpointPage(new ArrayList<>(), new HashMap<>(), new Meta(0L)); } - - return internalGetEndpoints(sec, query, targetType, activeOnly, name, authorizedIds, true); + } else { + // Legacy RBAC permission checking. The permission will have been + // prefetched and processed by the "ConsoleIdentityProvider". + if (!sec.isUserInRole(ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS)) { + throw new ForbiddenException(); + } } - return getEndpointsLegacyRBACRoles(sec, query, targetType, activeOnly, name, true); + return internalGetEndpoints(sec, query, targetType, activeOnly, name, authorizedIds, true); } } diff --git a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/event/EventResource.java b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/event/EventResource.java index 95187178ce..d28c435e4e 100644 --- a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/event/EventResource.java +++ b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/event/EventResource.java @@ -1,5 +1,7 @@ package com.redhat.cloud.notifications.routers.handlers.event; +import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider; +import com.redhat.cloud.notifications.auth.annotation.Authorization; import com.redhat.cloud.notifications.auth.kessel.KesselAuthorization; import com.redhat.cloud.notifications.auth.kessel.permission.WorkspacePermission; import com.redhat.cloud.notifications.auth.rbac.workspace.WorkspaceUtils; @@ -17,7 +19,6 @@ import com.redhat.cloud.notifications.routers.models.Page; import com.redhat.cloud.notifications.routers.models.PageLinksBuilder; import io.quarkus.logging.Log; -import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.validation.Valid; import jakarta.ws.rs.BadRequestException; @@ -43,7 +44,6 @@ import java.util.stream.Collectors; import static com.redhat.cloud.notifications.Constants.API_NOTIFICATIONS_V_1_0; -import static com.redhat.cloud.notifications.auth.ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS_EVENTS; import static com.redhat.cloud.notifications.routers.SecurityContextUtil.getOrgId; import static jakarta.ws.rs.core.MediaType.APPLICATION_JSON; @@ -65,6 +65,7 @@ public class EventResource { @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve the event log entries", description = "Retrieves the event log entries. Use this endpoint to review a full history of the events related to the tenant. You can sort by the bundle, application, event, and created fields. You can specify the sort order by appending :asc or :desc to the field, for example bundle:desc. Sorting defaults to desc for the created field and to asc for all other fields." ) + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS_EVENTS, workspacePermissions = {WorkspacePermission.EVENT_LOG_VIEW}) public Page getEvents(@Context SecurityContext securityContext, @Context UriInfo uriInfo, @RestQuery Set bundleIds, @RestQuery Set appIds, @RestQuery String eventTypeDisplayName, @RestQuery LocalDate startDate, @RestQuery LocalDate endDate, @@ -72,24 +73,6 @@ public Page getEvents(@Context SecurityContext securityContext, @ @RestQuery Set status, @BeanParam @Valid Query query, @RestQuery boolean includeDetails, @RestQuery boolean includePayload, @RestQuery boolean includeActions) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.EVENT_LOG_VIEW, workspaceId); - - return this.getInternalEvents(securityContext, uriInfo, bundleIds, appIds, eventTypeDisplayName, startDate, endDate, endpointTypes, invocationResults, status, query, includeDetails, includePayload, includeActions); - } else { - return this.getEventsLegacyRBACRoles(securityContext, uriInfo, bundleIds, appIds, eventTypeDisplayName, startDate, endDate, endpointTypes, invocationResults, status, query, includeDetails, includePayload, includeActions); - } - - } - - @RolesAllowed(RBAC_READ_NOTIFICATIONS_EVENTS) - public Page getEventsLegacyRBACRoles(final SecurityContext securityContext, final UriInfo uriInfo, final Set bundleIds, final Set appIds, final String eventTypeDisplayName, final LocalDate startDate, final LocalDate endDate, final Set endpointTypes, final Set invocationResults, final Set status, final Query query, final boolean includeDetails, final boolean includePayload, final boolean includeActions) { - return this.getInternalEvents(securityContext, uriInfo, bundleIds, appIds, eventTypeDisplayName, startDate, endDate, endpointTypes, invocationResults, status, query, includeDetails, includePayload, includeActions); - } - - public Page getInternalEvents(final SecurityContext securityContext, final UriInfo uriInfo, final Set bundleIds, final Set appIds, final String eventTypeDisplayName, final LocalDate startDate, final LocalDate endDate, final Set endpointTypes, final Set invocationResults, final Set status, final Query query, final boolean includeDetails, final boolean includePayload, final boolean includeActions) { Set basicTypes = Collections.emptySet(); Set compositeTypes = Collections.emptySet(); Set notificationStatusSet = status == null ? Set.of() : toNotificationStatus(status); diff --git a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/notification/NotificationResource.java b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/notification/NotificationResource.java index ed4bc57367..04477a3ae1 100644 --- a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/notification/NotificationResource.java +++ b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/notification/NotificationResource.java @@ -2,6 +2,8 @@ import com.redhat.cloud.notifications.Constants; import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider; +import com.redhat.cloud.notifications.auth.annotation.Authorization; +import com.redhat.cloud.notifications.auth.annotation.IntegrationId; import com.redhat.cloud.notifications.auth.kessel.KesselAuthorization; import com.redhat.cloud.notifications.auth.kessel.permission.IntegrationPermission; import com.redhat.cloud.notifications.auth.kessel.permission.WorkspacePermission; @@ -117,29 +119,13 @@ public static class V1 extends NotificationResource { @Path("/eventTypes/{eventTypeId}/behaviorGroups") @Produces(APPLICATION_JSON) @Operation(summary = "List the behavior groups linked to an event type", description = "Lists the behavior groups that are linked to an event type. Use this endpoint to see which behavior groups will be affected if you delete an event type.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_VIEW, WorkspacePermission.EVENT_TYPES_VIEW}) public List getLinkedBehaviorGroups( @Context SecurityContext sec, @PathParam("eventTypeId") UUID eventTypeId, @BeanParam @Valid Query query ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_VIEW, workspaceId); - - return this.internalGetLinkedBehaviorGroups(sec, eventTypeId, query); - } else { - return this.legacyRBACGetLinkedBehaviorGroups(sec, eventTypeId, query); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public List legacyRBACGetLinkedBehaviorGroups(final SecurityContext securityContext, final UUID eventTypeId, @Valid final Query query) { - return this.internalGetLinkedBehaviorGroups(securityContext, eventTypeId, query); - } - - public List internalGetLinkedBehaviorGroups(final SecurityContext securityContext, final UUID eventTypeId, @Valid final Query query) { - String orgId = getOrgId(securityContext); + final String orgId = getOrgId(sec); return behaviorGroupRepository.findBehaviorGroupsByEventTypeId(orgId, eventTypeId, query); } @@ -149,26 +135,11 @@ public List internalGetLinkedBehaviorGroups(final SecurityContext @Path("/eventTypes") @Produces(APPLICATION_JSON) @Operation(summary = "List all event types", description = "Lists all event types. You can filter the returned list by bundle, application name, or unmuted types.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.EVENT_TYPES_VIEW}) public Page getEventTypes( @Context SecurityContext securityContext, @Context UriInfo uriInfo, @BeanParam @Valid Query query, @QueryParam("applicationIds") Set applicationIds, @QueryParam("bundleId") UUID bundleId, @QueryParam("eventTypeName") String eventTypeName, @QueryParam("excludeMutedTypes") boolean excludeMutedTypes ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - - return this.internalGetEventTypes(securityContext, uriInfo, query, applicationIds, bundleId, eventTypeName, excludeMutedTypes); - } else { - return this.legacyRBACGetEventTypes(securityContext, uriInfo, query, applicationIds, bundleId, eventTypeName, excludeMutedTypes); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public Page legacyRBACGetEventTypes(final SecurityContext securityContext, final UriInfo uriInfo, @Valid final Query query, final Set applicationIds, final UUID bundleId, final String eventTypeName, final boolean excludeMutedTypes) { - return this.internalGetEventTypes(securityContext, uriInfo, query, applicationIds, bundleId, eventTypeName, excludeMutedTypes); - } - - public Page internalGetEventTypes(final SecurityContext securityContext, final UriInfo uriInfo, @Valid final Query query, final Set applicationIds, final UUID bundleId, final String eventTypeName, final boolean excludeMutedTypes) { List unmutedEventTypeIds = excludeMutedTypes ? behaviorGroupRepository.findUnmutedEventTypes(getOrgId(securityContext), bundleId) : null; @@ -186,23 +157,8 @@ public Page internalGetEventTypes(final SecurityContext securityConte @Path("/bundles/{bundleName}") @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve a bundle by name", description = "Retrieves the details of a bundle by searching by its name.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BUNDLES_VIEW}) public Bundle getBundleByName(@Context final SecurityContext securityContext, @PathParam("bundleName") String bundleName) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.BUNDLES_VIEW, workspaceId); - - return this.internalGetBundleByName(bundleName); - } else { - return this.legacyRBACGetBundleByName(bundleName); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public Bundle legacyRBACGetBundleByName(final String bundleName) { - return this.internalGetBundleByName(bundleName); - } - - public Bundle internalGetBundleByName(final String bundleName) { Bundle bundle = bundleRepository.getBundle(bundleName); if (bundle == null) { throw new NotFoundException(); @@ -215,29 +171,12 @@ public Bundle internalGetBundleByName(final String bundleName) { @Path("/bundles/{bundleName}/applications/{applicationName}") @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve an application by bundle and application names", description = "Retrieves an application by bundle and application names. Use this endpoint to find an application by searching for the bundle that the application is part of. This is useful if you do not know the UUID of the bundle or application.") - + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BUNDLES_VIEW, WorkspacePermission.APPLICATIONS_VIEW}) public Application getApplicationByNameAndBundleName( @Context SecurityContext securityContext, @PathParam("bundleName") String bundleName, @PathParam("applicationName") String applicationName ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.BUNDLES_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.APPLICATIONS_VIEW, workspaceId); - - return this.internalGetApplicationByNameAndBundleName(bundleName, applicationName); - } else { - return this.legacyRBACGetAppliactionByNameAndBundleName(bundleName, applicationName); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public Application legacyRBACGetAppliactionByNameAndBundleName(final String bundleName, final String applicationName) { - return this.internalGetApplicationByNameAndBundleName(bundleName, applicationName); - } - - public Application internalGetApplicationByNameAndBundleName(final String bundleName, final String applicationName) { Application application = applicationRepository.getApplication(bundleName, applicationName); if (application == null) { throw new NotFoundException(); @@ -250,31 +189,13 @@ public Application internalGetApplicationByNameAndBundleName(final String bundle @Path("/bundles/{bundleName}/applications/{applicationName}/eventTypes/{eventTypeName}") @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve an event type by bundle, application and event type names", description = "Retrieves the details of an event type by specifying the bundle name, the application name, and the event type name.") - + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BUNDLES_VIEW, WorkspacePermission.APPLICATIONS_VIEW, WorkspacePermission.EVENT_TYPES_VIEW}) public EventType getEventTypesByNameAndBundleAndApplicationName( @Context SecurityContext securityContext, @PathParam("bundleName") String bundleName, @PathParam("applicationName") String applicationName, @PathParam("eventTypeName") String eventTypeName ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.BUNDLES_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.APPLICATIONS_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - - return this.internalGetEventTypesByNameAndBundleAndApplicationName(bundleName, applicationName, eventTypeName); - } else { - return this.legacyRBACGetEventTypesByNameAndBundleAndApplicationName(bundleName, applicationName, eventTypeName); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public EventType legacyRBACGetEventTypesByNameAndBundleAndApplicationName(final String bundleName, final String applicationName, final String eventTypeName) { - return this.internalGetEventTypesByNameAndBundleAndApplicationName(bundleName, applicationName, eventTypeName); - } - - public EventType internalGetEventTypesByNameAndBundleAndApplicationName(final String bundleName, final String applicationName, final String eventTypeName) { EventType eventType = applicationRepository.getEventType(bundleName, applicationName, eventTypeName); if (eventType == null) { throw new NotFoundException(); @@ -292,26 +213,10 @@ public EventType internalGetEventTypesByNameAndBundleAndApplicationName(final St @Path("/eventTypes/affectedByRemovalOfBehaviorGroup/{behaviorGroupId}") @Produces(APPLICATION_JSON) @Operation(summary = "List the event types affected by the removal of a behavior group", description = "Lists the event types that will be affected by the removal of a behavior group. Use this endpoint to see which event types will be removed if you delete a behavior group.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_VIEW, WorkspacePermission.EVENT_TYPES_VIEW}) public List getEventTypesAffectedByRemovalOfBehaviorGroup(@Context SecurityContext sec, @Parameter(description = "The UUID of the behavior group to check") @PathParam("behaviorGroupId") UUID behaviorGroupId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - - return this.internalGetEventTypesAffectedByRemovalOfBehaviorGroup(sec, behaviorGroupId); - } else { - return this.legacyRBACGetEventTypesAffectedByRemovalOfBehaviorGroup(sec, behaviorGroupId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public List legacyRBACGetEventTypesAffectedByRemovalOfBehaviorGroup(final SecurityContext securityContext, final UUID behaviorGroupId) { - return this.internalGetEventTypesAffectedByRemovalOfBehaviorGroup(securityContext, behaviorGroupId); - } - - public List internalGetEventTypesAffectedByRemovalOfBehaviorGroup(final SecurityContext securityContext, final UUID behaviorGroupId) { - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); return behaviorGroupRepository.findEventTypesByBehaviorGroupId(orgId, behaviorGroupId); } @@ -323,24 +228,8 @@ public List internalGetEventTypesAffectedByRemovalOfBehaviorGroup(fin @Path("/behaviorGroups/affectedByRemovalOfEndpoint/{endpointId}") @Produces(APPLICATION_JSON) @Operation(summary = "List the behavior groups affected by the removal of an endpoint", description = "Lists the behavior groups that are affected by the removal of an endpoint. Use this endpoint to understand how removing an endpoint affects existing behavior groups.") - public List getBehaviorGroupsAffectedByRemovalOfEndpoint(@Context SecurityContext sec, @PathParam("endpointId") UUID endpointId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnIntegration(sec, IntegrationPermission.VIEW, endpointId); - - return this.internalGetBehaviorGroupsAffectedByRemovalOfEndpoint(sec, endpointId); - } else { - return this.legacyRBACGetBehaviorGroupsAffectedByRemovalOfEndpoint(sec, endpointId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public List legacyRBACGetBehaviorGroupsAffectedByRemovalOfEndpoint(final SecurityContext securityContext, final UUID endpointId) { - return this.internalGetBehaviorGroupsAffectedByRemovalOfEndpoint(securityContext, endpointId); - } - - public List internalGetBehaviorGroupsAffectedByRemovalOfEndpoint(final SecurityContext sec, final UUID endpointId) { + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, integrationPermissions = {IntegrationPermission.VIEW}, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_VIEW}) + public List getBehaviorGroupsAffectedByRemovalOfEndpoint(@Context SecurityContext sec, @IntegrationId @PathParam("endpointId") UUID endpointId) { String orgId = getOrgId(sec); return behaviorGroupRepository.findBehaviorGroupsByEndpointId(orgId, endpointId); } @@ -396,28 +285,13 @@ public List getBundleFacets(@Context SecurityContext sec, @QueryParam("in @APIResponse(responseCode = "400", content = @Content(mediaType = TEXT_PLAIN, schema = @Schema(type = SchemaType.STRING)), description = "Bad or no content passed.") }) @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT}) public CreateBehaviorGroupResponse createBehaviorGroup( @Context final SecurityContext sec, - @RequestBody(required = true) final CreateBehaviorGroupRequest request + @NotNull @Valid @RequestBody(required = true) final CreateBehaviorGroupRequest request ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - - return this.internalCreateBehaviorGroup(sec, request); - } else { - return this.legacyRBACInternalCreateBehaviorGroup(sec, request); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public CreateBehaviorGroupResponse legacyRBACInternalCreateBehaviorGroup(final SecurityContext securityContext, final CreateBehaviorGroupRequest request) { - return this.internalCreateBehaviorGroup(securityContext, request); - } - - public CreateBehaviorGroupResponse internalCreateBehaviorGroup(final SecurityContext securityContext, @NotNull @Valid CreateBehaviorGroupRequest request) { - String accountId = getAccountId(securityContext); - String orgId = getOrgId(securityContext); + String accountId = getAccountId(sec); + String orgId = getOrgId(sec); // We know that either the ID or the name are present because the // request gets validated before reaching this point, and therefore it @@ -472,26 +346,11 @@ public CreateBehaviorGroupResponse internalCreateBehaviorGroup(final SecurityCon }) @Operation(summary = "Update a behavior group", description = "Updates the details of a behavior group. Use this endpoint to update the list of related endpoints and event types associated with this behavior group.") @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT}) public Response updateBehaviorGroup(@Context SecurityContext sec, @Parameter(description = "The UUID of the behavior group to update") @PathParam("id") UUID id, - @RequestBody(description = "New parameters", required = true) UpdateBehaviorGroupRequest request) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - - return this.internalUpdateBehaviorGroup(sec, id, request); - } else { - return this.legacyRBACInternalUpdateBehaviorGroup(sec, id, request); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public Response legacyRBACInternalUpdateBehaviorGroup(final SecurityContext securityContext, final UUID id, UpdateBehaviorGroupRequest request) { - return this.internalUpdateBehaviorGroup(securityContext, id, request); - } - - public Response internalUpdateBehaviorGroup(final SecurityContext securityContext, final UUID id, @NotNull @Valid UpdateBehaviorGroupRequest request) { - String orgId = getOrgId(securityContext); + @NotNull @RequestBody(description = "New parameters", required = true) @Valid UpdateBehaviorGroupRequest request) { + String orgId = getOrgId(sec); if (request.displayName != null) { UUID bundleId = behaviorGroupRepository.getBundleId(orgId, id); @@ -523,25 +382,10 @@ public Response internalUpdateBehaviorGroup(final SecurityContext securityContex @Produces(APPLICATION_JSON) @Operation(summary = "Delete a behavior group", description = "Deletes a behavior group and all of its configured actions. Use this endpoint when you no longer need a behavior group.") @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT}) public Boolean deleteBehaviorGroup(@Context SecurityContext sec, @Parameter(description = "The UUID of the behavior group to delete") @PathParam("id") UUID behaviorGroupId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - - return this.internalDeleteBehaviorGroup(sec, behaviorGroupId); - } else { - return this.legacyRBACDeleteBehaviorGroup(sec, behaviorGroupId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public Boolean legacyRBACDeleteBehaviorGroup(final SecurityContext securityContext, final UUID behaviorGroupId) { - return this.internalDeleteBehaviorGroup(securityContext, behaviorGroupId); - } - - public Boolean internalDeleteBehaviorGroup(final SecurityContext securityContext, final UUID behaviorGroupId) { - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); final List endpointsLinkedToBgToDelete = endpointEventTypeRepository.findEndpointsByBehaviorGroupId(orgId, Set.of(behaviorGroupId)); final Boolean response = behaviorGroupRepository.delete(orgId, behaviorGroupId); endpointEventTypeRepository.refreshEndpointLinksToEventType(orgId, endpointsLinkedToBgToDelete); @@ -555,25 +399,10 @@ public Boolean internalDeleteBehaviorGroup(final SecurityContext securityContext @Operation(summary = "Update the list of behavior group actions", description = "Updates the list of actions to be executed in that particular behavior group after an event is received.") @APIResponse(responseCode = "200", content = @Content(schema = @Schema(type = SchemaType.STRING))) @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT}) public Response updateBehaviorGroupActions(@Context SecurityContext sec, @Parameter(description = "The UUID of the behavior group to update") @PathParam("behaviorGroupId") UUID behaviorGroupId, @Parameter(description = "List of endpoint ids of the actions") List endpointIds) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - - return this.internalUpdateBehaviorGroupActions(sec, behaviorGroupId, endpointIds); - } else { - return this.legacyRBACUpdateBehaviorGroupActions(sec, behaviorGroupId, endpointIds); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public Response legacyRBACUpdateBehaviorGroupActions(final SecurityContext securityContext, final UUID behaviorGroupId, final List endpointIds) { - return this.internalUpdateBehaviorGroupActions(securityContext, behaviorGroupId, endpointIds); - } - - public Response internalUpdateBehaviorGroupActions(final SecurityContext securityContext, final UUID behaviorGroupId, final List endpointIds) { if (endpointIds == null) { throw new BadRequestException("The request body must contain a list (possibly empty) of endpoints identifiers"); } @@ -584,7 +413,7 @@ public Response internalUpdateBehaviorGroupActions(final SecurityContext securit if (endpointIds.size() != endpointIds.stream().distinct().count()) { throw new BadRequestException("The endpoints identifiers list should not contain duplicates"); } - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); final List endpointLinkedToBgBeforeUpdate = endpointEventTypeRepository.findEndpointsByBehaviorGroupId(orgId, Set.of(behaviorGroupId)); behaviorGroupRepository.updateBehaviorGroupActions(orgId, behaviorGroupId, endpointIds); final List endpointLinkedToBgAfterUpdate = endpointEventTypeRepository.findEndpointsByBehaviorGroupId(orgId, Set.of(behaviorGroupId)); @@ -601,27 +430,10 @@ public Response internalUpdateBehaviorGroupActions(final SecurityContext securit @Operation(summary = "Update the list of behavior groups for an event type", description = "Updates the list of behavior groups associated with an event type.") @APIResponse(responseCode = "200", content = @Content(schema = @Schema(type = SchemaType.STRING))) @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT, WorkspacePermission.EVENT_TYPES_VIEW}) public Response updateEventTypeBehaviors(@Context SecurityContext sec, @Parameter(description = "UUID of the eventType to associate with the behavior group(s)") @PathParam("eventTypeId") UUID eventTypeId, @Parameter(description = "Set of behavior group ids to associate") Set behaviorGroupIds) { - - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - - return this.internalUpdateEventTypeBehaviors(sec, eventTypeId, behaviorGroupIds); - } else { - return this.legacyRBACUpdateEventTypeBehaviors(sec, eventTypeId, behaviorGroupIds); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public Response legacyRBACUpdateEventTypeBehaviors(final SecurityContext securityContext, final UUID eventTypeId, final Set behaviorGroupIds) { - return this.internalUpdateEventTypeBehaviors(securityContext, eventTypeId, behaviorGroupIds); - } - - public Response internalUpdateEventTypeBehaviors(final SecurityContext securityContext, final UUID eventTypeId, final Set behaviorGroupIds) { if (behaviorGroupIds == null) { throw new BadRequestException("The request body must contain a list (possibly empty) of behavior groups identifiers"); } @@ -629,7 +441,7 @@ public Response internalUpdateEventTypeBehaviors(final SecurityContext securityC if (behaviorGroupIds.contains(null)) { throw new BadRequestException("The behavior groups identifiers list should not contain empty values"); } - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); final Set updatedBgs = behaviorGroupRepository.updateEventTypeBehaviors(orgId, eventTypeId, behaviorGroupIds); // Sync new endpoint to evenType data model @@ -647,28 +459,12 @@ public Response internalUpdateEventTypeBehaviors(final SecurityContext securityC @Path("/eventTypes/{eventTypeUuid}/behaviorGroups/{behaviorGroupUuid}") @Operation(summary = "Add a behavior group to the given event type.") @APIResponse(responseCode = "204") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT, WorkspacePermission.EVENT_TYPES_VIEW}) public void appendBehaviorGroupToEventType( @Context final SecurityContext securityContext, @RestPath final UUID behaviorGroupUuid, @RestPath final UUID eventTypeUuid ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - - this.internalAppendBehaviorGroupToEventType(securityContext, behaviorGroupUuid, eventTypeUuid); - } else { - this.legacyRBACAppendBehaviorGroupToEventType(securityContext, behaviorGroupUuid, eventTypeUuid); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - protected void legacyRBACAppendBehaviorGroupToEventType(final SecurityContext securityContext, final UUID behaviorGroupUuid, final UUID eventTypeUuid) { - this.internalAppendBehaviorGroupToEventType(securityContext, behaviorGroupUuid, eventTypeUuid); - } - - protected void internalAppendBehaviorGroupToEventType(final SecurityContext securityContext, final UUID behaviorGroupUuid, final UUID eventTypeUuid) { final String orgId = getOrgId(securityContext); this.behaviorGroupRepository.appendBehaviorGroupToEventType(orgId, behaviorGroupUuid, eventTypeUuid); @@ -681,28 +477,12 @@ protected void internalAppendBehaviorGroupToEventType(final SecurityContext secu @Path("/eventTypes/{eventTypeId}/behaviorGroups/{behaviorGroupId}") @Operation(summary = "Delete a behavior group from an event type", description = "Delete a behavior group from the specified event type.") @APIResponse(responseCode = "204") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BEHAVIOR_GROUPS_EDIT, WorkspacePermission.EVENT_TYPES_VIEW}) public void deleteBehaviorGroupFromEventType( @Context final SecurityContext securityContext, @RestPath final UUID eventTypeId, @RestPath final UUID behaviorGroupId ) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(securityContext)); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.EVENT_TYPES_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(securityContext, WorkspacePermission.BEHAVIOR_GROUPS_EDIT, workspaceId); - - this.internalDeleteBehaviorGroupFromEventType(securityContext, eventTypeId, behaviorGroupId); - } else { - this.legacyRBACInternalDeleteBehaviorGroupFromEventType(securityContext, eventTypeId, behaviorGroupId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - protected void legacyRBACInternalDeleteBehaviorGroupFromEventType(final SecurityContext securityContext, final UUID eventTypeId, final UUID behaviorGroupId) { - this.internalDeleteBehaviorGroupFromEventType(securityContext, eventTypeId, behaviorGroupId); - } - - protected void internalDeleteBehaviorGroupFromEventType(final SecurityContext securityContext, final UUID eventTypeId, final UUID behaviorGroupId) { final String orgId = getOrgId(securityContext); this.behaviorGroupRepository.deleteBehaviorGroupFromEventType(eventTypeId, behaviorGroupId, orgId); @@ -715,27 +495,10 @@ protected void internalDeleteBehaviorGroupFromEventType(final SecurityContext se @Path("/bundles/{bundleId}/behaviorGroups") @Produces(APPLICATION_JSON) @Operation(summary = "List behavior groups in a bundle", description = "Lists the behavior groups associated with a bundle. Use this endpoint to see the behavior groups that are configured for a particular bundle for a particular tenant.") - + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.BUNDLES_VIEW, WorkspacePermission.BEHAVIOR_GROUPS_VIEW}) public List findBehaviorGroupsByBundleId(@Context SecurityContext sec, @Parameter(description = "UUID of the bundle to retrieve the behavior groups for.") @PathParam("bundleId") UUID bundleId) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BUNDLES_VIEW, workspaceId); - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.BEHAVIOR_GROUPS_VIEW, workspaceId); - - return this.internalFindBehaviorGroupsByBundleId(sec, bundleId); - } else { - return this.legacyRBACInternalFindBehaviorGroupsByBundleId(sec, bundleId); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - protected List legacyRBACInternalFindBehaviorGroupsByBundleId(final SecurityContext securityContext, final UUID bundleId) { - return this.internalFindBehaviorGroupsByBundleId(securityContext, bundleId); - } - - protected List internalFindBehaviorGroupsByBundleId(final SecurityContext securityContext, final UUID bundleId) { - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); List behaviorGroups = behaviorGroupRepository.findByBundleId(orgId, bundleId); endpointRepository.loadProperties( behaviorGroups @@ -802,6 +565,7 @@ private Page internalGetLinkedEndpoints(final SecurityContext sec, @Operation(summary = "Update the list of endpoints for an event type", description = "Updates the list of endpoints associated with an event type.") @APIResponse(responseCode = "200", content = @Content(schema = @Schema(type = SchemaType.STRING))) @Transactional + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) public Response updateEventTypeEndpoints(@Context SecurityContext securityContext, @Parameter(description = "UUID of the eventType to associate with the endpoint(s)") @PathParam("eventTypeId") UUID eventTypeId, @Parameter(description = "Set of endpoint ids to associate") Set endpointsIds) { @@ -813,22 +577,14 @@ public Response updateEventTypeEndpoints(@Context SecurityContext securityContex throw new BadRequestException("The endpoints identifiers list should not contain empty values"); } - if (backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { - for (UUID endpointId : endpointsIds) { + // When Kessel is enabled we need to make sure that the principal has + // edit access to all the integrations. + if (this.backendConfig.isKesselRelationsEnabled(getOrgId(securityContext))) { + for (final UUID endpointId : endpointsIds) { kesselAuthorization.hasPermissionOnIntegration(securityContext, IntegrationPermission.EDIT, endpointId); } - return internalUpdateEventTypeEndpoints(securityContext, endpointsIds, eventTypeId); - } else { - return legacyRbacUpdateEventTypeEndpoints(securityContext, endpointsIds, eventTypeId); } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public Response legacyRbacUpdateEventTypeEndpoints(SecurityContext securityContext, Set endpointsIds, UUID eventTypeId) { - return internalUpdateEventTypeEndpoints(securityContext, endpointsIds, eventTypeId); - } - public Response internalUpdateEventTypeEndpoints(SecurityContext securityContext, Set endpointsIds, UUID eventTypeId) { String orgId = getOrgId(securityContext); String accountId = getAccountId(securityContext); diff --git a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/orgconfig/OrgConfigResource.java b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/orgconfig/OrgConfigResource.java index 229ab5eb6e..f169223618 100644 --- a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/orgconfig/OrgConfigResource.java +++ b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/orgconfig/OrgConfigResource.java @@ -2,14 +2,11 @@ import com.redhat.cloud.notifications.Constants; import com.redhat.cloud.notifications.auth.ConsoleIdentityProvider; -import com.redhat.cloud.notifications.auth.kessel.KesselAuthorization; +import com.redhat.cloud.notifications.auth.annotation.Authorization; import com.redhat.cloud.notifications.auth.kessel.permission.WorkspacePermission; -import com.redhat.cloud.notifications.auth.rbac.workspace.WorkspaceUtils; -import com.redhat.cloud.notifications.config.BackendConfig; import com.redhat.cloud.notifications.db.repositories.AggregationOrgConfigRepository; import com.redhat.cloud.notifications.models.AggregationOrgConfig; import io.quarkus.logging.Log; -import jakarta.annotation.security.RolesAllowed; import jakarta.inject.Inject; import jakarta.transaction.Transactional; import jakarta.validation.constraints.NotNull; @@ -32,7 +29,6 @@ import java.time.LocalTime; import java.util.Arrays; import java.util.List; -import java.util.UUID; import java.util.stream.Collectors; import static com.redhat.cloud.notifications.routers.SecurityContextUtil.getOrgId; @@ -40,15 +36,6 @@ @Path(Constants.API_NOTIFICATIONS_V_1_0 + "/org-config") public class OrgConfigResource { - @Inject - BackendConfig backendConfig; - - @Inject - KesselAuthorization kesselAuthorization; - - @Inject - WorkspaceUtils workspaceUtils; - static final List ALLOWED_MINUTES = Arrays.asList(0, 15, 30, 45); @Inject @@ -64,25 +51,9 @@ public class OrgConfigResource { @Consumes(APPLICATION_JSON) @Transactional @Operation(summary = "Set the daily digest time", description = "Sets the daily digest UTC time. The accepted minute values are 00, 15, 30, and 45. Use this endpoint to set the time when daily emails are sent.") - public void saveDailyDigestTimePreference(@Context SecurityContext sec, LocalTime expectedTime) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.DAILY_DIGEST_PREFERENCE_EDIT, workspaceId); - - this.internalSaveDailyDigestTimePreference(sec, expectedTime); - } else { - this.legacyRBACInternalSaveDailyDigestTimePreference(sec, expectedTime); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS) - public void legacyRBACInternalSaveDailyDigestTimePreference(final SecurityContext securityContext, final LocalTime expectedTime) { - this.internalSaveDailyDigestTimePreference(securityContext, expectedTime); - } - - public void internalSaveDailyDigestTimePreference(final SecurityContext securityContext, @NotNull final LocalTime expectedTime) { - String orgId = getOrgId(securityContext); + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.DAILY_DIGEST_PREFERENCE_EDIT}) + public void saveDailyDigestTimePreference(@Context SecurityContext sec, @NotNull LocalTime expectedTime) { + String orgId = getOrgId(sec); if (!ALLOWED_MINUTES.contains(expectedTime.getMinute())) { String errorMessage = "Accepted minute values are: " + ALLOWED_MINUTES.stream().map(min -> String.format("%02d", min)).collect(Collectors.joining(", ")) + "."; @@ -97,25 +68,9 @@ public void internalSaveDailyDigestTimePreference(final SecurityContext security @Path("/daily-digest/time-preference") @Produces(APPLICATION_JSON) @Operation(summary = "Retrieve the daily digest time", description = "Retrieves the daily digest time setting. Use this endpoint to check the time that daily emails are sent.") + @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS, workspacePermissions = {WorkspacePermission.DAILY_DIGEST_PREFERENCE_VIEW}) public Response getDailyDigestTimePreference(@Context SecurityContext sec) { - if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) { - final UUID workspaceId = this.workspaceUtils.getDefaultWorkspaceId(getOrgId(sec)); - - this.kesselAuthorization.hasPermissionOnWorkspace(sec, WorkspacePermission.DAILY_DIGEST_PREFERENCE_VIEW, workspaceId); - - return this.internalGetDailyDigestTimePreference(sec); - } else { - return this.legacyRBACGetDailyDigestTimePreference(sec); - } - } - - @RolesAllowed(ConsoleIdentityProvider.RBAC_READ_NOTIFICATIONS) - public Response legacyRBACGetDailyDigestTimePreference(final SecurityContext securityContext) { - return this.internalGetDailyDigestTimePreference(securityContext); - } - - public Response internalGetDailyDigestTimePreference(final SecurityContext securityContext) { - String orgId = getOrgId(securityContext); + String orgId = getOrgId(sec); Log.infof("Get daily digest time preference for orgId %s", orgId); AggregationOrgConfig storedParameters = aggregationOrgConfigRepository.findJobAggregationOrgConfig(orgId); if (null != storedParameters) { diff --git a/backend/src/test/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceTest.java b/backend/src/test/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceTest.java index f3924ec439..3de5002a02 100644 --- a/backend/src/test/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceTest.java +++ b/backend/src/test/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResourceTest.java @@ -1237,6 +1237,9 @@ void testEndpointUpdates(final boolean isKesselRelationsApiEnabled) { attrSingle.mapTo(WebhookProperties.class); attrSingle.put("secret_token", "not-so-secret-anymore"); + // Give the Kessel permissions to see the endpoint. + this.kesselTestHelper.mockKesselPermission(DEFAULT_USER, IntegrationPermission.EDIT, ResourceType.INTEGRATION, responsePointSingle.getString("id")); + // Update without payload given() .header(identityHeader) @@ -2832,7 +2835,7 @@ void testEndpointTestBlankMessageReturnsBadRequest(final boolean isKesselRelatio final JsonObject constraintViolation = constraintViolations.getJsonObject(0); - Assertions.assertEquals("internalTestEndpoint.requestBody.message", constraintViolation.getString("field"), "unexpected field validated when sending a blank test message"); + Assertions.assertEquals("testEndpoint.requestBody.message", constraintViolation.getString("field"), "unexpected field validated when sending a blank test message"); Assertions.assertEquals("must not be blank", constraintViolation.getString("message"), "unexpected error message received when sending a blank custom message for testing the endpoint"); } From de20e99dd3e87085bcb944ac3b639e7697d257ea Mon Sep 17 00:00:00 2001 From: Mikel Alejo Barcina Ribera Date: Wed, 19 Feb 2025 13:05:50 +0100 Subject: [PATCH 2/2] refactor: remove unnecessary annotations RHCLOUD-37536 --- .../routers/handlers/endpoint/EndpointResource.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java index b577f27072..1e5502e306 100644 --- a/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java +++ b/backend/src/main/java/com/redhat/cloud/notifications/routers/handlers/endpoint/EndpointResource.java @@ -314,8 +314,8 @@ protected EndpointPage internalGetEndpoints( }) @Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_WRITE_INTEGRATIONS_ENDPOINTS, workspacePermissions = {WorkspacePermission.INTEGRATIONS_CREATE}) public EndpointDTO createEndpoint( - @Context final SecurityContext sec, - @NotNull @Valid @RequestBody(required = true) final EndpointDTO endpointDTO + @Context final SecurityContext sec, + @NotNull @Valid @RequestBody final EndpointDTO endpointDTO ) { final Endpoint endpoint = this.endpointMapper.toEntity(endpointDTO); @@ -346,9 +346,10 @@ public EndpointDTO createEndpoint( */ @Transactional protected Endpoint internalCreateEndpoint( - @Context SecurityContext sec, - @RequestBody(required = true) @NotNull @Valid Endpoint endpoint, - Set eventTypes) { + final SecurityContext sec, + final Endpoint endpoint, + final Set eventTypes + ) { if (!isEndpointTypeAllowed(endpoint.getType())) { throw new BadRequestException(UNSUPPORTED_ENDPOINT_TYPE); }