Skip to content

Commit

Permalink
Merge pull request wso2#4388 from SujanSanjula96/fix-api-resource-ui-1
Browse files Browse the repository at this point in the history
Fix API Resource UI access control to support system APIs
  • Loading branch information
Achintha Isuru authored Oct 27, 2023
2 parents b716c4c + 003ca93 commit f0975e7
Show file tree
Hide file tree
Showing 7 changed files with 144 additions and 25 deletions.
5 changes: 5 additions & 0 deletions .changeset/metal-clouds-flash.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@wso2is/console": patch
---

Fix API Resource UI access control to support system APIs
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ export const PermissionAPIResource: FunctionComponent<PermissionAPIResourceInter
</Grid>
<Grid xs={ 4 } alignItems="flex-end">
{
permissionList?.length !== 0
permissionList?.length !== 0 && !isReadOnly
&& (<PrimaryButton
data-componentid={ `${componentId}-add-permission-button` }
size="medium"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* under the License.
*/

import { hasRequiredScopes } from "@wso2is/core/helpers";
import { AlertInterface, AlertLevels, IdentifiableComponentInterface, SBACInterface } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import {
Expand All @@ -38,6 +37,7 @@ import { AppState, FeatureConfigInterface, UIConstants, getEmptyPlaceholderIllus
import { deleteAPIResource } from "../api";
import { APIResourcesConstants } from "../constants";
import { APIResourceInterface } from "../models";
import { APIResourceUtils } from "../utils/api-resource-utils";

/**
* Prop types for the API resources list component.
Expand Down Expand Up @@ -206,38 +206,42 @@ export const APIResourcesList: FunctionComponent<APIResourcesListProps> = (
{
"data-componentid": `${componentId}-item-edit-button`,
hidden: () => {
const hasScopesRead: boolean = !hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.read, allowedScopes);
const readForbidden: boolean = !APIResourceUtils.isAPIResourceReadAllowed(
featureConfig, allowedScopes);
const updateForbidden: boolean = !APIResourceUtils.isAPIResourceUpdateAllowed(
featureConfig, allowedScopes);

const hasScopesUpdate: boolean = !hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.update, allowedScopes);

return hasScopesUpdate || hasScopesRead;
return readForbidden && updateForbidden;
},
icon: (): SemanticICONS => {
return !hasRequiredScopes(featureConfig?.applications,
featureConfig?.applications?.scopes?.update, allowedScopes)
? "eye"
: "pencil alternate";
icon: (apiResource: APIResourceInterface): SemanticICONS => {
const updateAllowed: boolean = APIResourceUtils.isAPIResourceUpdateAllowed(
featureConfig, allowedScopes);
const isSystemAPIResource: boolean = APIResourceUtils.isSystemAPI(apiResource?.type);
const canUpdate: boolean = !isSystemAPIResource && updateAllowed;

return canUpdate ? "pencil alternate" : "eye";
},
onClick: (e: SyntheticEvent, apiResource: APIResourceInterface): void => {
handleAPIResourceEdit(apiResource, e);
},
popupText: (): string => {
return !hasRequiredScopes(featureConfig?.applications,
featureConfig?.applications?.scopes?.update, allowedScopes)
? t("common:view")
: t("common:edit");
popupText: (apiResource: APIResourceInterface): string => {
const updateAllowed: boolean = APIResourceUtils.isAPIResourceUpdateAllowed(
featureConfig, allowedScopes);
const isSystemAPIResource: boolean = APIResourceUtils.isSystemAPI(apiResource?.type);
const canUpdate: boolean = !isSystemAPIResource && updateAllowed;

return canUpdate ? t("common:edit") : t("common:view");
},
renderer: "semantic-icon"
},
{
"data-componentid": `${componentId}-item-delete-button`,
hidden: () => {
const hasScopes: boolean = !hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.delete, allowedScopes);
hidden: (apiResource: APIResourceInterface) => {
const deleteForbidden: boolean = !APIResourceUtils.isAPIResourceDeleteAllowed(
featureConfig, allowedScopes);
const isSystemAPIResource: boolean = APIResourceUtils.isSystemAPI(apiResource?.type);

return hasScopes;
return deleteForbidden || isSystemAPIResource;
},
icon: (): SemanticICONS => "trash alternate",
onClick: (e: SyntheticEvent, apiResource: APIResourceInterface): void => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export class APIResourcesConstants {
public static readonly DEFAULT_TOTAL_PAGES: number = 10;
public static readonly API_RESOURCE_DIR: string = "api-resources";

// API Resource types.
public static readonly SYSTEM: string = "SYSTEM";
public static readonly SYSTEM_ORG: string = "SYSTEM_ORG";
public static readonly SYSTEM_FEATURE: string = "SYSTEM_FEATURE";

/**
* Get the API resource paths as a map.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@ export interface APIResourceInterface {
* Required authorization.
*/
requiresAuthorization?: boolean;
/**
* Type of the API resource.
*/
type?: string;
/**
* List of scopes associate with the API resource.
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
* under the License.
*/

import { hasRequiredScopes } from "@wso2is/core/helpers";
import { AlertInterface, AlertLevels, IdentifiableComponentInterface } from "@wso2is/core/models";
import { addAlert } from "@wso2is/core/store";
import { EmptyPlaceholder, TabPageLayout } from "@wso2is/react-components";
Expand All @@ -28,6 +27,7 @@ import { AppState, FeatureConfigInterface,getEmptyPlaceholderIllustrations, hist
import { useAPIResourceDetails } from "../api";
import { EditAPIResource } from "../components";
import { APIResourcesConstants } from "../constants";
import { APIResourceUtils } from "../utils/api-resource-utils";

/**
* Prop-types for the API resources page component.
Expand Down Expand Up @@ -75,8 +75,10 @@ const APIResourcesEditPage: FunctionComponent<APIResourcesEditPageInterface> = (
* The following useEffect is used to handle if the user has the required scopes to update the API resource
*/
useEffect(() => {
if (!hasRequiredScopes(
featureConfig?.apiResources, featureConfig?.apiResources?.scopes?.update, allowedScopes)) {
const updateForbidden: boolean = !APIResourceUtils.isAPIResourceUpdateAllowed(featureConfig, allowedScopes);
const isSytemAPIResource: boolean = APIResourceUtils.isSystemAPI(apiResourceData?.type);

if (updateForbidden || isSytemAPIResource) {
setReadOnly(true);
}
}, [ apiResourceData ]);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/**
* Copyright (c) 2023, WSO2 LLC. (https://www.wso2.com).
*
* WSO2 LLC. licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file except
* in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

import { hasRequiredScopes } from "@wso2is/core/helpers";
import { FeatureConfigInterface } from "../../core";
import { APIResourcesConstants } from "../constants/api-resources-constants";

export class APIResourceUtils {

/**
* Private constructor to avoid object instantiation from outside
* the class.
*/
private constructor() { }

/**
* Check whether the API resource read is allowed.
*
* @param featureConfig - Feature config.
* @param allowedScopes - Allowed scopes.
* @returns True if the API resource read is allowed.
*/
public static isAPIResourceReadAllowed(featureConfig: FeatureConfigInterface,
allowedScopes: string): boolean {

return hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.read, allowedScopes);
}

/**
* Check whether the API resource update is allowed.
*
* @param featureConfig - Feature config.
* @param allowedScopes - Allowed scopes.
* @returns True if the API resource update is allowed.
*/
public static isAPIResourceUpdateAllowed(featureConfig: FeatureConfigInterface,
allowedScopes: string): boolean {

return hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.update, allowedScopes);
}

/**
* Check whether the API resource create is allowed.
*
* @param featureConfig - Feature config.
* @param allowedScopes - Allowed scopes.
* @returns True if the API resource create is allowed.
*/
public static isAPIResourceCreateAllowed(featureConfig: FeatureConfigInterface,
allowedScopes: string): boolean {

return hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.create, allowedScopes);
}

/**
* Check whether the API resource delete is allowed.
*
* @param featureConfig - Feature config.
* @param allowedScopes - Allowed scopes.
* @returns True if the API resource delete is allowed.
*/
public static isAPIResourceDeleteAllowed(featureConfig: FeatureConfigInterface,
allowedScopes: string): boolean {

return hasRequiredScopes(featureConfig?.apiResources,
featureConfig?.apiResources?.scopes?.delete, allowedScopes);
}

/**
* Check whether the API resource is a system API.
*
* @param type - API Resource type.
* @returns True if the API resource is a system API.
*/
public static isSystemAPI(type: string): boolean {

return type === APIResourcesConstants.SYSTEM
|| type === APIResourcesConstants.SYSTEM_ORG
|| type === APIResourcesConstants.SYSTEM_FEATURE;
}
}

0 comments on commit f0975e7

Please sign in to comment.