Skip to content

Commit

Permalink
refactor: authorization in handlers
Browse files Browse the repository at this point in the history
The changes make use of the new "Authorization" annotation to simplify
the code and improve maintainability.

RHCLOUD-37536
  • Loading branch information
MikelAlejoBR committed Feb 18, 2025
1 parent ee7973e commit 828a88b
Show file tree
Hide file tree
Showing 6 changed files with 125 additions and 653 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down Expand Up @@ -68,33 +70,19 @@ public class EndpointResourceV2 extends EndpointResource {
)
}
)
@Authorization(legacyRBACRole = ConsoleIdentityProvider.RBAC_READ_INTEGRATIONS_ENDPOINTS, integrationPermissions = {IntegrationPermission.VIEW_HISTORY})
public Page<NotificationHistoryDTO> 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<NotificationHistoryDTO> 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<NotificationHistoryDTO> 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> notificationHistory = this.notificationRepository.getNotificationHistory(orgId, id, doDetail, query);
Expand All @@ -111,14 +99,9 @@ protected Page<NotificationHistoryDTO> 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
Expand Down Expand Up @@ -147,18 +130,23 @@ public EndpointPage getEndpoints(
@QueryParam("active") Boolean activeOnly,
@QueryParam("name") String name
) {
Set<UUID> authorizedIds = null;
if (this.backendConfig.isKesselRelationsEnabled(getOrgId(sec))) {
// Fetch the set of integration IDs the user is authorized to view.
final Set<UUID> 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);
}
}
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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;
Expand All @@ -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;

Expand All @@ -65,31 +65,14 @@ 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<EventLogEntry> getEvents(@Context SecurityContext securityContext, @Context UriInfo uriInfo,
@RestQuery Set<UUID> bundleIds, @RestQuery Set<UUID> appIds,
@RestQuery String eventTypeDisplayName, @RestQuery LocalDate startDate, @RestQuery LocalDate endDate,
@RestQuery Set<String> endpointTypes, @RestQuery Set<Boolean> invocationResults,
@RestQuery Set<EventLogEntryActionStatus> 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<EventLogEntry> getEventsLegacyRBACRoles(final SecurityContext securityContext, final UriInfo uriInfo, final Set<UUID> bundleIds, final Set<UUID> appIds, final String eventTypeDisplayName, final LocalDate startDate, final LocalDate endDate, final Set<String> endpointTypes, final Set<Boolean> invocationResults, final Set<EventLogEntryActionStatus> 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<EventLogEntry> getInternalEvents(final SecurityContext securityContext, final UriInfo uriInfo, final Set<UUID> bundleIds, final Set<UUID> appIds, final String eventTypeDisplayName, final LocalDate startDate, final LocalDate endDate, final Set<String> endpointTypes, final Set<Boolean> invocationResults, final Set<EventLogEntryActionStatus> status, final Query query, final boolean includeDetails, final boolean includePayload, final boolean includeActions) {
Set<EndpointType> basicTypes = Collections.emptySet();
Set<CompositeEndpointType> compositeTypes = Collections.emptySet();
Set<NotificationStatus> notificationStatusSet = status == null ? Set.of() : toNotificationStatus(status);
Expand Down
Loading

0 comments on commit 828a88b

Please sign in to comment.