From 15686b209aa7bba936a4dd482d59458cb49ab462 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Feria Vila <2582866+carlosthe19916@users.noreply.github.com> Date: Mon, 1 Nov 2021 09:48:07 +0100 Subject: [PATCH 1/9] save changes --- README.md | 6 +- docker-compose.yml | 24 +-- konveyor-realm.json | 359 +++++++++++++++++++++++++++----------------- src/setupProxy.js | 6 +- 4 files changed, 242 insertions(+), 153 deletions(-) diff --git a/README.md b/README.md index 052c7b44..0411ea50 100644 --- a/README.md +++ b/README.md @@ -63,7 +63,7 @@ Start a database which will be used by `tackle-controls`: docker run -d -p 5432:5432 \ -e POSTGRES_USER=username \ -e POSTGRES_PASSWORD=password \ --e POSTGRES_DB=controls_db \ +-e POSTGRES_DB=db \ postgres:13.1 ``` @@ -76,8 +76,8 @@ Move your terminal to where you cloned `tackle-controls` and then: -Dquarkus.http.port=8080 \ -Dquarkus.datasource.username=username \ -Dquarkus.datasource.password=password \ --Dquarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/controls_db \ --Dquarkus.oidc.client-id=controls-api \ +-Dquarkus.datasource.jdbc.url=jdbc:postgresql://localhost:5432/db \ +-Dquarkus.oidc.client-id=tackle-api \ -Dquarkus.oidc.credentials.secret=secret \ -Dquarkus.oidc.auth-server-url=http://localhost:8180/auth/realms/konveyor ``` diff --git a/docker-compose.yml b/docker-compose.yml index be0727d4..df2b450d 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -23,11 +23,11 @@ services: ports: - 5433:5432 environment: - POSTGRES_DB: controls_db + POSTGRES_DB: db POSTGRES_USER: user POSTGRES_PASSWORD: password healthcheck: - test: ["CMD-SHELL", "pg_isready -U user -d controls_db"] + test: ["CMD-SHELL", "pg_isready -U user -d db"] interval: 10s timeout: 5s retries: 5 @@ -40,9 +40,9 @@ services: QUARKUS_HTTP_PORT: 8080 QUARKUS_DATASOURCE_USERNAME: user QUARKUS_DATASOURCE_PASSWORD: password - QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://controls-db:5432/controls_db + QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://controls-db:5432/db QUARKUS_OIDC_AUTH_SERVER_URL: http://keycloak:8080/auth/realms/konveyor - QUARKUS_OIDC_CLIENT_ID: controls-api + QUARKUS_OIDC_CLIENT_ID: tackle-api QUARKUS_OIDC_CREDENTIALS_SECRET: secret healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/controls/q/health"] @@ -60,11 +60,11 @@ services: ports: - 5434:5432 environment: - POSTGRES_DB: application_inventory_db + POSTGRES_DB: db POSTGRES_USER: user POSTGRES_PASSWORD: password healthcheck: - test: ["CMD-SHELL", "pg_isready -U user -d application_inventory_db"] + test: ["CMD-SHELL", "pg_isready -U user -d db"] interval: 10s timeout: 5s retries: 5 @@ -77,9 +77,9 @@ services: QUARKUS_HTTP_PORT: 8080 QUARKUS_DATASOURCE_USERNAME: user QUARKUS_DATASOURCE_PASSWORD: password - QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://application-inventory-db:5432/application_inventory_db + QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://application-inventory-db:5432/db QUARKUS_OIDC_AUTH_SERVER_URL: http://keycloak:8080/auth/realms/konveyor - QUARKUS_OIDC_CLIENT_ID: application-inventory-api + QUARKUS_OIDC_CLIENT_ID: tackle-api QUARKUS_OIDC_CREDENTIALS_SECRET: secret IO_TACKLE_APPLICATIONINVENTORY_SERVICES_CONTROLS_SERVICE: controls:8080 healthcheck: @@ -104,11 +104,11 @@ services: ports: - 5435:5432 environment: - POSTGRES_DB: pathfinder_db + POSTGRES_DB: db POSTGRES_USER: user POSTGRES_PASSWORD: password healthcheck: - test: ["CMD-SHELL", "pg_isready -U user -d pathfinder_db"] + test: ["CMD-SHELL", "pg_isready -U user -d db"] interval: 10s timeout: 5s retries: 5 @@ -121,9 +121,9 @@ services: QUARKUS_HTTP_PORT: 8080 QUARKUS_DATASOURCE_USERNAME: user QUARKUS_DATASOURCE_PASSWORD: password - QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://pathfinder-db:5432/pathfinder_db + QUARKUS_DATASOURCE_JDBC_URL: jdbc:postgresql://pathfinder-db:5432/db QUARKUS_OIDC_AUTH_SERVER_URL: http://keycloak:8080/auth/realms/konveyor - QUARKUS_OIDC_CLIENT_ID: pathfinder-api + QUARKUS_OIDC_CLIENT_ID: tackle-api QUARKUS_OIDC_CREDENTIALS_SECRET: secret healthcheck: test: ["CMD", "curl", "-f", "http://localhost:8080/pathfinder/q/health"] diff --git a/konveyor-realm.json b/konveyor-realm.json index 171d99f6..8c8b3620 100644 --- a/konveyor-realm.json +++ b/konveyor-realm.json @@ -45,15 +45,81 @@ { "id": "d723b5ff-6c33-4152-b0ac-3ad9c1b79e6c", "name": "admin", - "composite": false, + "description": "Admins of Tackle", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "tag:write", + "business-metadata:write", + "application:write", + "application-import:write", + "application-assessment:write", + "application-dependency:write" + ] + } + }, + "clientRole": false, + "containerId": "konveyor", + "attributes": {} + }, + { + "id": "f777a295-e6bc-45d5-8d84-e476a9021242", + "name": "architect", + "description": "Architects of Tackle", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "tag:write", + "business-metadata:write", + "application:write", + "application-import:write", + "application-assessment:write", + "application-dependency:write" + ] + } + }, + "clientRole": false, + "containerId": "konveyor", + "attributes": {} + }, + { + "id": "014309e1-d2cf-496f-9cc3-fb156c86e360", + "name": "migrator", + "description": "Migrators of Tackle", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "tag:read", + "business-metadata:read", + "application-import:read", + "application-assessment:write", + "application:read" + ] + } + }, "clientRole": false, "containerId": "konveyor", "attributes": {} }, { - "id": "88607edb-72b0-46fb-8d76-1a75a51a50f0", + "id": "74c6b736-7934-44de-88c0-435c927ada01", "name": "user", - "composite": false, + "description": "User of Tackle", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "tag:read", + "application-import:read", + "application-assessment:read", + "business-metadata:read", + "application:read" + ] + } + }, "clientRole": false, "containerId": "konveyor", "attributes": {} @@ -291,7 +357,7 @@ } ], "security-admin-console": [], - "controls-api": [ + "tackle-api": [ { "id": "d056105b-2d60-4415-addb-9639ac3bfd74", "name": "uma_protection", @@ -299,6 +365,153 @@ "clientRole": true, "containerId": "5cda179e-8443-4467-a488-292976d25bf1", "attributes": {} + }, + { + "id": "f89d033f-1d90-4061-bfff-bf380aaa844a", + "name": "application:write", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "application:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "67082935-a948-4395-a0c8-a851773ca1ba", + "name": "application-import:write", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "application-import:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "caf1d234-b5e4-4cbe-8915-24a9a7cc7ab1", + "name": "application-assessment:read", + "composite": false, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "691daa33-980e-419a-a63f-c86d07a03dae", + "name": "tag:read", + "composite": false, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "f0eb63c2-033f-447a-85bd-55c83f1e3619", + "name": "application-import:read", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "application:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "1045e9bb-130f-4bc9-bf35-f50d8e46722e", + "name": "application-assessment:write", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "application-assessment:read", + "application:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "5cf0b4ca-7e26-4f86-a3d3-6dab69243d33", + "name": "application:read", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "tag:read", + "application-assessment:read", + "business-metadata:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "3ed86dfd-d354-4d70-9467-a0b8270bb37c", + "name": "business-metadata:read", + "composite": false, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "574e82d1-9fc3-4166-bccd-f227afe02982", + "name": "tag:write", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "tag:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "d8a18018-8ce5-497f-b7e3-de7b1112ac39", + "name": "application-dependency:write", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "application:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "703d2149-4c71-47e9-922e-8643ffbff834", + "name": "business-metadata:write", + "composite": true, + "composites": { + "client": { + "tackle-api": [ + "business-metadata:read" + ] + } + }, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} } ], "admin-cli": [], @@ -389,7 +602,8 @@ "groups": [], "defaultRoles": [ "uma_authorization", - "offline_access" + "offline_access", + "user" ], "requiredCredentials": [ "password" @@ -454,8 +668,7 @@ ], "requiredActions": [], "realmRoles": [ - "admin", - "user" + "admin" ], "notBefore": 0, "groups": [] @@ -493,11 +706,11 @@ { "id": "f2f78ee5-b6f9-4e7b-a837-8301a30a6d73", "createdTimestamp": 1602936578977, - "username": "service-account-controls-api", + "username": "service-account-tackle-api", "enabled": true, "totp": false, "emailVerified": false, - "serviceAccountClientId": "controls-api", + "serviceAccountClientId": "tackle-api", "disableableCredentialTypes": [], "requiredActions": [], "realmRoles": [ @@ -505,7 +718,7 @@ "offline_access" ], "clientRoles": { - "controls-api": [ + "tackle-api": [ "uma_protection" ], "account": [ @@ -821,7 +1034,7 @@ }, { "id": "5cda179e-8443-4467-a488-292976d25bf1", - "clientId": "controls-api", + "clientId": "tackle-api", "surrogateAuthRequired": false, "enabled": true, "alwaysDisplayInConsole": false, @@ -881,130 +1094,6 @@ "manage": true } }, - { - "id": "065c4bcf-379e-4a83-99d7-5491176185e2", - "clientId": "application-inventory-api", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "secret", - "redirectUris": [ - "/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "backchannel.logout.revoke.offline.tokens": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "backchannel.logout.session.required": "true", - "client_credentials.use_refresh_token": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ], - "access": { - "view": true, - "configure": true, - "manage": true - } - }, - { - "id": "7f4a9ed7-3554-4aef-955a-a5737fb942f3", - "clientId": "pathfinder-api", - "surrogateAuthRequired": false, - "enabled": true, - "alwaysDisplayInConsole": false, - "clientAuthenticatorType": "client-secret", - "secret": "secret", - "redirectUris": [ - "/*" - ], - "webOrigins": [], - "notBefore": 0, - "bearerOnly": false, - "consentRequired": false, - "standardFlowEnabled": true, - "implicitFlowEnabled": false, - "directAccessGrantsEnabled": true, - "serviceAccountsEnabled": false, - "publicClient": false, - "frontchannelLogout": false, - "protocol": "openid-connect", - "attributes": { - "saml.assertion.signature": "false", - "saml.force.post.binding": "false", - "saml.multivalued.roles": "false", - "saml.encrypt": "false", - "backchannel.logout.revoke.offline.tokens": "false", - "saml.server.signature": "false", - "saml.server.signature.keyinfo.ext": "false", - "exclude.session.state.from.auth.response": "false", - "backchannel.logout.session.required": "true", - "client_credentials.use_refresh_token": "false", - "saml_force_name_id_format": "false", - "saml.client.signature": "false", - "tls.client.certificate.bound.access.tokens": "false", - "saml.authnstatement": "false", - "display.on.consent.screen": "false", - "saml.onetimeuse.condition": "false" - }, - "authenticationFlowBindingOverrides": {}, - "fullScopeAllowed": true, - "nodeReRegistrationTimeout": -1, - "defaultClientScopes": [ - "web-origins", - "role_list", - "roles", - "profile", - "email" - ], - "optionalClientScopes": [ - "address", - "phone", - "offline_access", - "microprofile-jwt" - ], - "access": { - "view": true, - "configure": true, - "manage": true - } - }, { "id": "695da74e-39ca-4e46-a2b6-6a673f92d4e2", "clientId": "tackle-ui", diff --git a/src/setupProxy.js b/src/setupProxy.js index 76f4730f..e403b9ad 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -4,7 +4,7 @@ module.exports = function (app) { app.use( "/api/controls", createProxyMiddleware({ - target: "http://localhost:8081", + target: "http://localhost:8087", changeOrigin: true, pathRewrite: { "^/api/controls": "/controls", @@ -15,7 +15,7 @@ module.exports = function (app) { app.use( "/api/application-inventory", createProxyMiddleware({ - target: "http://localhost:8082", + target: "http://localhost:8088", changeOrigin: true, pathRewrite: { "^/api/application-inventory": "/application-inventory", @@ -26,7 +26,7 @@ module.exports = function (app) { app.use( "/api/pathfinder", createProxyMiddleware({ - target: "http://localhost:8083", + target: "http://localhost:8089", changeOrigin: true, pathRewrite: { "^/api/pathfinder": "/pathfinder", From 5e2821622a785a87a08ec0a1366c714f53fea045 Mon Sep 17 00:00:00 2001 From: Carlos Esteban Feria Vila <2582866+carlosthe19916@users.noreply.github.com> Date: Mon, 1 Nov 2021 14:53:06 +0100 Subject: [PATCH 2/9] Set RBAC for showing and hidding elements --- konveyor-realm.json | 138 ++++++------- src/Constants.ts | 16 ++ src/layout/SidebarApp/SidebarApp.tsx | 54 +++-- .../application-list/application-list.tsx | 185 +++++++++++------- .../business-services/business-services.tsx | 51 +++-- .../controls/job-functions/job-functions.tsx | 53 +++-- .../stakeholder-groups/stakeholder-groups.tsx | 51 +++-- .../controls/stakeholders/stakeholders.tsx | 51 +++-- .../tags/components/tag-table/tag-table.tsx | 10 +- src/pages/controls/tags/tags.tsx | 80 +++++--- src/shared/components/index.ts | 1 + .../visibility-by-permission/index.ts | 1 + .../visibility-by-permission.tsx | 15 ++ src/shared/hooks/index.ts | 1 + src/shared/hooks/useKcPermission/index.ts | 1 + .../hooks/useKcPermission/useKcPermission.ts | 27 +++ src/utils/utils.ts | 6 + 17 files changed, 473 insertions(+), 268 deletions(-) create mode 100644 src/shared/components/visibility-by-permission/index.ts create mode 100644 src/shared/components/visibility-by-permission/visibility-by-permission.tsx create mode 100644 src/shared/hooks/useKcPermission/index.ts create mode 100644 src/shared/hooks/useKcPermission/useKcPermission.ts diff --git a/konveyor-realm.json b/konveyor-realm.json index 8c8b3620..70bd99f0 100644 --- a/konveyor-realm.json +++ b/konveyor-realm.json @@ -50,19 +50,19 @@ "composites": { "client": { "tackle-api": [ - "tag:write", - "business-metadata:write", - "application:write", - "application-import:write", - "application-assessment:write", - "application-dependency:write" + "controls:write", + "inventory:application:write", + "inventory:application-import:write", + "inventory:application-dependency:write", + "inventory:application-review:write", + "pathfinder:assessment:write" ] } }, "clientRole": false, "containerId": "konveyor", "attributes": {} - }, + }, { "id": "f777a295-e6bc-45d5-8d84-e476a9021242", "name": "architect", @@ -71,12 +71,12 @@ "composites": { "client": { "tackle-api": [ - "tag:write", - "business-metadata:write", - "application:write", - "application-import:write", - "application-assessment:write", - "application-dependency:write" + "controls:write", + "inventory:application:write", + "inventory:application-import:write", + "inventory:application-dependency:write", + "inventory:application-review:write", + "pathfinder:assessment:write" ] } }, @@ -92,11 +92,10 @@ "composites": { "client": { "tackle-api": [ - "tag:read", - "business-metadata:read", - "application-import:read", - "application-assessment:write", - "application:read" + "controls:read", + "inventory:application:read", + "inventory:application-import:read", + "pathfinder:assessment:write" ] } }, @@ -112,11 +111,10 @@ "composites": { "client": { "tackle-api": [ - "tag:read", - "application-import:read", - "application-assessment:read", - "business-metadata:read", - "application:read" + "controls:read", + "inventory:application:read", + "inventory:application-import:read", + "pathfinder:assessment:read" ] } }, @@ -367,13 +365,21 @@ "attributes": {} }, { - "id": "f89d033f-1d90-4061-bfff-bf380aaa844a", - "name": "application:write", + "id": "691daa33-980e-419a-a63f-c86d07a03dae", + "name": "controls:read", + "composite": false, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "574e82d1-9fc3-4166-bccd-f227afe02982", + "name": "controls:write", "composite": true, "composites": { "client": { "tackle-api": [ - "application:read" + "controls:read" ] } }, @@ -382,13 +388,14 @@ "attributes": {} }, { - "id": "67082935-a948-4395-a0c8-a851773ca1ba", - "name": "application-import:write", + "id": "5cf0b4ca-7e26-4f86-a3d3-6dab69243d33", + "name": "inventory:application:read", "composite": true, "composites": { "client": { "tackle-api": [ - "application-import:read" + "controls:read", + "pathfinder:assessment:read" ] } }, @@ -397,29 +404,13 @@ "attributes": {} }, { - "id": "caf1d234-b5e4-4cbe-8915-24a9a7cc7ab1", - "name": "application-assessment:read", - "composite": false, - "clientRole": true, - "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", - "attributes": {} - }, - { - "id": "691daa33-980e-419a-a63f-c86d07a03dae", - "name": "tag:read", - "composite": false, - "clientRole": true, - "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", - "attributes": {} - }, - { - "id": "f0eb63c2-033f-447a-85bd-55c83f1e3619", - "name": "application-import:read", + "id": "f89d033f-1d90-4061-bfff-bf380aaa844a", + "name": "inventory:application:write", "composite": true, "composites": { "client": { "tackle-api": [ - "application:read" + "inventory:application:read" ] } }, @@ -428,14 +419,13 @@ "attributes": {} }, { - "id": "1045e9bb-130f-4bc9-bf35-f50d8e46722e", - "name": "application-assessment:write", + "id": "f0eb63c2-033f-447a-85bd-55c83f1e3619", + "name": "inventory:application-import:read", "composite": true, "composites": { "client": { "tackle-api": [ - "application-assessment:read", - "application:read" + "inventory:application:read" ] } }, @@ -444,15 +434,13 @@ "attributes": {} }, { - "id": "5cf0b4ca-7e26-4f86-a3d3-6dab69243d33", - "name": "application:read", + "id": "67082935-a948-4395-a0c8-a851773ca1ba", + "name": "inventory:application-import:write", "composite": true, "composites": { "client": { "tackle-api": [ - "tag:read", - "application-assessment:read", - "business-metadata:read" + "inventory:application-import:read" ] } }, @@ -461,21 +449,13 @@ "attributes": {} }, { - "id": "3ed86dfd-d354-4d70-9467-a0b8270bb37c", - "name": "business-metadata:read", - "composite": false, - "clientRole": true, - "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", - "attributes": {} - }, - { - "id": "574e82d1-9fc3-4166-bccd-f227afe02982", - "name": "tag:write", + "id": "d8a18018-8ce5-497f-b7e3-de7b1112ac39", + "name": "inventory:application-dependency:write", "composite": true, "composites": { "client": { "tackle-api": [ - "tag:read" + "inventory:application:read" ] } }, @@ -484,13 +464,14 @@ "attributes": {} }, { - "id": "d8a18018-8ce5-497f-b7e3-de7b1112ac39", - "name": "application-dependency:write", + "id": "3ed86dfd-d354-4d70-9467-a0b8270bb37c", + "name": "inventory:application-review:write", "composite": true, "composites": { "client": { "tackle-api": [ - "application:read" + "inventory:application:read", + "pathfinder:assessment:write" ] } }, @@ -499,13 +480,22 @@ "attributes": {} }, { - "id": "703d2149-4c71-47e9-922e-8643ffbff834", - "name": "business-metadata:write", + "id": "caf1d234-b5e4-4cbe-8915-24a9a7cc7ab1", + "name": "pathfinder:assessment:read", + "composite": false, + "clientRole": true, + "containerId": "a19ae9a3-c9c1-4f4a-b39a-1bd5851eee90", + "attributes": {} + }, + { + "id": "03f48fd4-de69-4baa-8177-cdab92d76209", + "name": "pathfinder:assessment:write", "composite": true, "composites": { "client": { "tackle-api": [ - "business-metadata:read" + "inventory:application:read", + "pathfinder:assessment:read" ] } }, diff --git a/src/Constants.ts b/src/Constants.ts index 15f6d256..c45369ac 100644 --- a/src/Constants.ts +++ b/src/Constants.ts @@ -194,3 +194,19 @@ export enum ApplicationFilterKey { BUSINESS_SERVICE = "business_service", TAG = "tag", } + +// Keycloak RBAC + +export const KC_API_CLIENT = "tackle-api"; + +export type KcPermission = + | "controls:read" + | "controls:write" + | "inventory:application:read" + | "inventory:application:write" + | "inventory:application-import:read" + | "inventory:application-import:write" + | "inventory:application-dependency:write" + | "inventory:application-review:write" + | "pathfinder:assessment:read" + | "pathfinder:assessment:write"; diff --git a/src/layout/SidebarApp/SidebarApp.tsx b/src/layout/SidebarApp/SidebarApp.tsx index 02d63419..0b5f7c44 100644 --- a/src/layout/SidebarApp/SidebarApp.tsx +++ b/src/layout/SidebarApp/SidebarApp.tsx @@ -5,33 +5,51 @@ import { Nav, NavItem, PageSidebar, NavList } from "@patternfly/react-core"; import { Paths } from "Paths"; import { LayoutTheme } from "../LayoutUtils"; +import { useKcPermission } from "shared/hooks"; +import { VisibilityByPermission } from "shared/components"; export const SidebarApp: React.FC = () => { + // i18 const { t } = useTranslation(); + + // Location const { search } = useLocation(); const renderPageNav = () => { return ( ); diff --git a/src/pages/application-inventory/application-list/application-list.tsx b/src/pages/application-inventory/application-list/application-list.tsx index 2265ed82..d9056bf6 100644 --- a/src/pages/application-inventory/application-list/application-list.tsx +++ b/src/pages/application-inventory/application-list/application-list.tsx @@ -45,6 +45,7 @@ import { NoDataEmptyState, StatusIconAssessment, KebabDropdown, + VisibilityByPermission, } from "shared/components"; import { useTableControls, @@ -54,6 +55,7 @@ import { useEntityModal, useDelete, useApplicationToolbarFilter, + useKcPermission, } from "shared/hooks"; import { ApplicationDependenciesFormContainer } from "shared/containers"; @@ -76,7 +78,7 @@ import { getAssessments, } from "api/rest"; import { applicationPageMapper } from "api/apiUtils"; -import { getAxiosErrorMessage } from "utils/utils"; +import { getAxiosErrorMessage, wrapInArrayWhen } from "utils/utils"; import { ApplicationForm } from "./components/application-form"; @@ -139,6 +141,17 @@ export const ApplicationList: React.FC = () => { // Router const history = useHistory(); + // RBAC + const { isAllowed: isAllowedToWriteApp } = useKcPermission({ + permissionsAllowed: ["inventory:application:write"], + }); + const { isAllowed: isAllowedToWriteAssessmentAndReview } = useKcPermission({ + permissionsAllowed: ["inventory:application-review:write"], + }); + const { isAllowed: isAllowedToWriteAppDependencies } = useKcPermission({ + permissionsAllowed: ["inventory:application-dependency:write"], + }); + // Toolbar filters const { filters: filtersValue, @@ -291,12 +304,12 @@ export const ApplicationList: React.FC = () => { { title: t("terms.assessment"), transforms: [cellWidth(10)] }, { title: t("terms.review"), transforms: [sortable, cellWidth(10)] }, { title: t("terms.tagCount"), transforms: [sortable, cellWidth(10)] }, - { + ...wrapInArrayWhen(isAllowedToWriteApp, { title: "", props: { className: "pf-c-table__inline-edit-action", }, - }, + }), ]; const rows: IRow[] = []; @@ -353,7 +366,7 @@ export const ApplicationList: React.FC = () => { ), }, - { + ...wrapInArrayWhen(isAllowedToWriteApp, { title: (
), - }, + }), ], }); @@ -388,7 +401,10 @@ export const ApplicationList: React.FC = () => { const actions: (IAction | ISeparator)[] = []; - if (getApplicationAssessment(row.id!)) { + if ( + isAllowedToWriteAssessmentAndReview && + getApplicationAssessment(row.id!) + ) { actions.push({ title: t("actions.discardAssessment"), onClick: ( @@ -402,8 +418,8 @@ export const ApplicationList: React.FC = () => { }); } - actions.push( - { + if (isAllowedToWriteAppDependencies) { + actions.push({ title: t("actions.manageDependencies"), onClick: ( event: React.MouseEvent, @@ -413,8 +429,11 @@ export const ApplicationList: React.FC = () => { const row: Application = getRow(rowData); openDependenciesModal(row); }, - }, - { + }); + } + + if (isAllowedToWriteApp) { + actions.push({ title: t("actions.delete"), onClick: ( event: React.MouseEvent, @@ -424,8 +443,8 @@ export const ApplicationList: React.FC = () => { const row: Application = getRow(rowData); deleteRow(row); }, - } - ); + }); + } return actions; }; @@ -653,68 +672,86 @@ export const ApplicationList: React.FC = () => { toolbar={ <> - - - - - - - - - - - setIsApplicationImportModalOpen(true)} - > - {t("actions.import")} - , - { - history.push( - Paths.applicationInventory_manageImports - ); - }} - > - {t("actions.manageImports")} - , - ]} - /> - + + + + + + + + + + + + + + + + + + + setIsApplicationImportModalOpen(true) + } + > + {t("actions.import")} + , + { + history.push( + Paths.applicationInventory_manageImports + ); + }} + > + {t("actions.manageImports")} + , + ]} + /> + + } diff --git a/src/pages/controls/business-services/business-services.tsx b/src/pages/controls/business-services/business-services.tsx index c314814d..1f03fa6f 100644 --- a/src/pages/controls/business-services/business-services.tsx +++ b/src/pages/controls/business-services/business-services.tsx @@ -29,11 +29,13 @@ import { AppTableActionButtons, AppTableToolbarToggleGroup, NoDataEmptyState, + VisibilityByPermission, } from "shared/components"; import { useTableControls, useFetchBusinessServices, useDelete, + useKcPermission, } from "shared/hooks"; import { BusinessService, SortByQuery } from "api/models"; @@ -42,7 +44,7 @@ import { BusinessServiceSortByQuery, deleteBusinessService, } from "api/rest"; -import { getAxiosErrorMessage } from "utils/utils"; +import { getAxiosErrorMessage, wrapInArrayWhen } from "utils/utils"; import { NewBusinessServiceModal } from "./components/new-business-service-modal"; import { UpdateBusinessServiceModal } from "./components/update-business-service-modal"; @@ -85,9 +87,18 @@ const ENTITY_FIELD = "entity"; // }; export const BusinessServices: React.FC = () => { + // i18 const { t } = useTranslation(); + + // Redux const dispatch = useDispatch(); + // RBAC + const { isAllowed: isAllowedToWrite } = useKcPermission({ + permissionsAllowed: ["controls:write"], + }); + + // Filters const filters = [ { key: FilterKey.NAME, @@ -106,15 +117,18 @@ export const BusinessServices: React.FC = () => { new Map([]) ); + // Create and update modal states const [isNewModalOpen, setIsNewModalOpen] = useState(false); const [rowToUpdate, setRowToUpdate] = useState(); + // Delete state const { requestDelete: requestDeleteBusinessService, } = useDelete({ onDelete: (t: BusinessService) => deleteBusinessService(t.id!), }); + // Table data const { businessServices, isFetching, @@ -155,16 +169,17 @@ export const BusinessServices: React.FC = () => { ); }, [filtersValue, paginationQuery, sortByQuery, fetchBusinessServices]); + // Table's rows and columns const columns: ICell[] = [ { title: t("terms.name"), transforms: [sortable, cellWidth(25)] }, { title: t("terms.description"), transforms: [cellWidth(40)] }, { title: t("terms.owner"), transforms: [sortable] }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: "", props: { className: "pf-u-text-align-right", }, - }, + }), ]; const rows: IRow[] = []; @@ -187,14 +202,14 @@ export const BusinessServices: React.FC = () => { ), }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: ( editRow(item)} onDelete={() => deleteRow(item)} /> ), - }, + }), ], }); }); @@ -371,18 +386,20 @@ export const BusinessServices: React.FC = () => { } toolbar={ - - - - - + + + + + + + } noDataState={ { + // i18 const { t } = useTranslation(); + + // Redux const dispatch = useDispatch(); + // RBAC + const { isAllowed: isAllowedToWrite } = useKcPermission({ + permissionsAllowed: ["controls:write"], + }); + + // Filters const filters = [ { key: FilterKey.NAME, @@ -89,13 +100,16 @@ export const JobFunctions: React.FC = () => { new Map([]) ); + // Create and update modal states const [isNewModalOpen, setIsNewModalOpen] = useState(false); const [rowToUpdate, setRowToUpdate] = useState(); + // Delete state const { requestDelete: requestDeleteJobFunction } = useDelete({ onDelete: (t: JobFunction) => deleteJobFunction(t.id!), }); + // Table data const { jobFunctions, isFetching, @@ -132,20 +146,19 @@ export const JobFunctions: React.FC = () => { ); }, [filtersValue, paginationQuery, sortByQuery, fetchJobFunctions]); - // - + // Table's rows and columns const columns: ICell[] = [ { title: t("terms.name"), transforms: [sortable, cellWidth(70)], cellFormatters: [], }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: "", props: { className: "pf-u-text-align-right", }, - }, + }), ]; const rows: IRow[] = []; @@ -156,14 +169,14 @@ export const JobFunctions: React.FC = () => { { title: {item.role}, }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: ( setRowToUpdate(item)} onDelete={() => deleteRow(item)} /> ), - }, + }), ], }); }); @@ -308,18 +321,20 @@ export const JobFunctions: React.FC = () => { } toolbar={ - - - - - + + + + + + + } noDataState={ { }; export const StakeholderGroups: React.FC = () => { + // i18 const { t } = useTranslation(); + + // Redux const dispatch = useDispatch(); + // RBAC + const { isAllowed: isAllowedToWrite } = useKcPermission({ + permissionsAllowed: ["controls:write"], + }); + + // Filters const filters = [ { key: FilterKey.NAME, @@ -114,15 +125,18 @@ export const StakeholderGroups: React.FC = () => { new Map([]) ); + // Create and update modal states const [isNewModalOpen, setIsNewModalOpen] = useState(false); const [rowToUpdate, setRowToUpdate] = useState(); + // Delete state const { requestDelete: requestDeleteStakeholderGroup, } = useDelete({ onDelete: (t: StakeholderGroup) => deleteStakeholderGroup(t.id!), }); + // Table data const { stakeholderGroups, isFetching, @@ -171,6 +185,7 @@ export const StakeholderGroups: React.FC = () => { ); }, [filtersValue, paginationQuery, sortByQuery, fetchStakeholderGroups]); + // Table's rows and columns const columns: ICell[] = [ { title: t("terms.name"), @@ -182,12 +197,12 @@ export const StakeholderGroups: React.FC = () => { title: t("terms.memberCount"), transforms: [sortable], }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: "", props: { className: "pf-u-text-align-right", }, - }, + }), ]; const rows: IRow[] = []; @@ -208,14 +223,14 @@ export const StakeholderGroups: React.FC = () => { { title: item.stakeholders ? item.stakeholders.length : 0, }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: ( editRow(item)} onDelete={() => deleteRow(item)} /> ), - }, + }), ], }); @@ -398,18 +413,20 @@ export const StakeholderGroups: React.FC = () => { } toolbar={ - - - - - + + + + + + + } noDataState={ { }; export const Stakeholders: React.FC = () => { + // i18 const { t } = useTranslation(); + + // Redux const dispatch = useDispatch(); + // RBAC + const { isAllowed: isAllowedToWrite } = useKcPermission({ + permissionsAllowed: ["controls:write"], + }); + + // Filters const filters = [ { key: FilterKey.EMAIL, @@ -125,13 +136,16 @@ export const Stakeholders: React.FC = () => { new Map([]) ); + // Create and update modal states const [isNewModalOpen, setIsNewModalOpen] = useState(false); const [rowToUpdate, setRowToUpdate] = useState(); + // Delete state const { requestDelete: requestDeleteStakeholder } = useDelete({ onDelete: (t: Stakeholder) => deleteStakeholder(t.id!), }); + // Table data const { stakeholders, isFetching, @@ -182,6 +196,7 @@ export const Stakeholders: React.FC = () => { ); }, [filtersValue, paginationQuery, sortByQuery, fetchStakeholders]); + // Table's rows and columns const columns: ICell[] = [ { title: t("terms.email"), @@ -194,12 +209,12 @@ export const Stakeholders: React.FC = () => { title: t("terms.groupCount"), transforms: [sortable], }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: "", props: { className: "pf-u-text-align-right", }, - }, + }), ]; const rows: IRow[] = []; @@ -227,14 +242,14 @@ export const Stakeholders: React.FC = () => { { title: item.stakeholderGroups ? item.stakeholderGroups.length : 0, }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: ( editRow(item)} onDelete={() => deleteRow(item)} /> ), - }, + }), ], }); @@ -415,18 +430,20 @@ export const Stakeholders: React.FC = () => { } toolbar={ - - - - - + + + + + + + } noDataState={ = ({ onEdit, onDelete, }) => { + // i18 const { t } = useTranslation(); + // RBAC + const { isAllowed: isAllowedToWrite } = useKcPermission({ + permissionsAllowed: ["controls:write"], + }); + + // Table's rows and columns const columns: ICell[] = [ { title: t("terms.tagName"), @@ -102,7 +110,7 @@ export const TagTable: React.FC = ({ aria-label="tag-table" cells={columns} rows={rows} - actions={actions} + actions={isAllowedToWrite ? actions : []} className={styles.actionColumnPadding} > diff --git a/src/pages/controls/tags/tags.tsx b/src/pages/controls/tags/tags.tsx index d1b5a847..e4e6a945 100644 --- a/src/pages/controls/tags/tags.tsx +++ b/src/pages/controls/tags/tags.tsx @@ -32,10 +32,16 @@ import { NoDataEmptyState, SearchFilter, Color, + VisibilityByPermission, } from "shared/components"; -import { useTableControls, useFetchTagTypes, useDelete } from "shared/hooks"; +import { + useTableControls, + useFetchTagTypes, + useDelete, + useKcPermission, +} from "shared/hooks"; -import { getAxiosErrorMessage } from "utils/utils"; +import { getAxiosErrorMessage, wrapInArrayWhen } from "utils/utils"; import { deleteTag, deleteTagType, @@ -93,9 +99,18 @@ const getRow = (rowData: IRowData): TagType => { }; export const Tags: React.FC = () => { + // i18 const { t } = useTranslation(); + + // Redux const dispatch = useDispatch(); + // RBAC + const { isAllowed: isAllowedToWrite } = useKcPermission({ + permissionsAllowed: ["controls:write"], + }); + + // Filters const filters = [ { key: FilterKey.TAG_TYPE, @@ -110,12 +125,14 @@ export const Tags: React.FC = () => { new Map([]) ); + // Create and update modal states const [isNewTagTypeModalOpen, setIsNewTagTypeModalOpen] = useState(false); const [rowToUpdate, setRowToUpdate] = useState(); const [isNewTagModalOpen, setIsNewTagModalOpen] = useState(false); const [tagToUpdate, setTagToUpdate] = useState(); + // Delete state const { requestDelete: requestDeleteTagType } = useDelete({ onDelete: (t: TagType) => deleteTagType(t.id!), }); @@ -123,6 +140,7 @@ export const Tags: React.FC = () => { onDelete: (t: Tag) => deleteTag(t.id!), }); + // Table data const { tagTypes, isFetching, fetchError, fetchTagTypes } = useFetchTagTypes( true ); @@ -196,8 +214,7 @@ export const Tags: React.FC = () => { ); }; - // - + // Table's rows and columns const columns: ICell[] = [ { title: t("terms.tagType"), @@ -213,12 +230,12 @@ export const Tags: React.FC = () => { title: t("terms.tagCount"), transforms: [sortable], }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: "", props: { className: "pf-u-text-align-right", }, - }, + }), ]; const rows: IRow[] = []; @@ -240,14 +257,14 @@ export const Tags: React.FC = () => { { title: item.tags ? item.tags.length : 0, }, - { + ...wrapInArrayWhen(isAllowedToWrite, { title: ( setRowToUpdate(item)} onDelete={() => deleteRow(item)} /> ), - }, + }), ], }); @@ -427,7 +444,6 @@ export const Tags: React.FC = () => { onCollapse={collapseRow} cells={columns} rows={rows} - // actions={actions} isLoading={isFetching} loadingVariant="skeleton" fetchError={fetchError} @@ -451,28 +467,30 @@ export const Tags: React.FC = () => { } toolbar={ - - - - - - - - + + + + + + + + + + } noDataState={ = ({ + permissionsAllowed, + children, +}) => { + const { isAllowed } = useKcPermission({ permissionsAllowed }); + return <>{isAllowed && children}; +}; diff --git a/src/shared/hooks/index.ts b/src/shared/hooks/index.ts index b9ba6bec..1f8415d9 100644 --- a/src/shared/hooks/index.ts +++ b/src/shared/hooks/index.ts @@ -10,6 +10,7 @@ export { useFetchJobFunctions } from "./useFetchJobFunctions"; export { useFetchStakeholderGroups } from "./useFetchStakeholderGroups"; export { useFetchStakeholders } from "./useFetchStakeholders"; export { useFetchTagTypes } from "./useFetchTagTypes"; +export { useKcPermission } from "./useKcPermission"; export { useMultipleFetch } from "./useMultipleFetch"; export { useQueryString } from "./useRouteAsState"; export { useToolbarFilter } from "./useToolbarFilter"; diff --git a/src/shared/hooks/useKcPermission/index.ts b/src/shared/hooks/useKcPermission/index.ts new file mode 100644 index 00000000..ced1aafc --- /dev/null +++ b/src/shared/hooks/useKcPermission/index.ts @@ -0,0 +1 @@ +export { useKcPermission } from "./useKcPermission"; diff --git a/src/shared/hooks/useKcPermission/useKcPermission.ts b/src/shared/hooks/useKcPermission/useKcPermission.ts new file mode 100644 index 00000000..be562355 --- /dev/null +++ b/src/shared/hooks/useKcPermission/useKcPermission.ts @@ -0,0 +1,27 @@ +import { useKeycloak } from "@react-keycloak/web"; +import { KcPermission, KC_API_CLIENT } from "Constants"; + +export interface IArgs { + permissionsAllowed: KcPermission[]; +} + +export interface IState { + isAllowed: boolean; +} + +export const useKcPermission = ({ permissionsAllowed }: IArgs): IState => { + const { keycloak } = useKeycloak(); + + const isAllowed = permissionsAllowed.some((permission) => { + return ( + keycloak.hasRealmRole(permission) || + keycloak.hasResourceRole(permission, KC_API_CLIENT) + ); + }); + + return { + isAllowed, + }; +}; + +export default useKcPermission; diff --git a/src/utils/utils.ts b/src/utils/utils.ts index 98b172e4..15f74768 100644 --- a/src/utils/utils.ts +++ b/src/utils/utils.ts @@ -61,3 +61,9 @@ export const formatDate = (value: Date, includeTime = true) => { return value.toLocaleDateString("en", options); }; + +// Util functions + +export const wrapInArrayWhen = (when: boolean, obj: any) => { + return when ? [obj] : []; +}; From 20bd850d1fcf26e4a900f9cf32ec8f6cf52e1d0d Mon Sep 17 00:00:00 2001 From: Carlos Esteban Feria Vila <2582866+carlosthe19916@users.noreply.github.com> Date: Mon, 1 Nov 2021 16:31:39 +0100 Subject: [PATCH 3/9] Add route validation --- src/ProtectedRoute.tsx | 47 +++++++++++++++++++ src/Routes.tsx | 29 +++++++++--- src/layout/SidebarApp/SidebarApp.tsx | 1 - .../application-inventory.tsx | 16 +++++-- .../manage-imports/manage-imports.tsx | 25 ++++++---- 5 files changed, 96 insertions(+), 22 deletions(-) create mode 100644 src/ProtectedRoute.tsx diff --git a/src/ProtectedRoute.tsx b/src/ProtectedRoute.tsx new file mode 100644 index 00000000..6a4c4f7c --- /dev/null +++ b/src/ProtectedRoute.tsx @@ -0,0 +1,47 @@ +import React from "react"; +import { Route, RouteProps } from "react-router-dom"; + +import { + Bullseye, + EmptyState, + EmptyStateBody, + EmptyStateIcon, + EmptyStateVariant, + Title, +} from "@patternfly/react-core"; +import { WarningTriangleIcon } from "@patternfly/react-icons"; + +import { useKcPermission } from "shared/hooks"; + +import { KcPermission } from "Constants"; + +export interface IProtectedRouteProps extends RouteProps { + permissionsAllowed: KcPermission[]; +} + +export const ProtectedRoute: React.FC = ({ + permissionsAllowed, + ...rest +}) => { + const { isAllowed } = useKcPermission({ + permissionsAllowed, + }); + + const notAuthorizedState = ( + + + + + 403 Forbidden + + You are not allowed to access this page + + + ); + + if (!isAllowed) { + return notAuthorizedState}>; + } + + return ; +}; diff --git a/src/Routes.tsx b/src/Routes.tsx index 23911f7a..0678f5a9 100644 --- a/src/Routes.tsx +++ b/src/Routes.tsx @@ -1,7 +1,8 @@ -import React, { lazy, Suspense } from "react"; -import { Route, Switch, Redirect } from "react-router-dom"; +import { lazy, Suspense } from "react"; +import { Switch, Redirect } from "react-router-dom"; import { AppPlaceholder } from "shared/components"; +import { ProtectedRoute, IProtectedRouteProps } from "./ProtectedRoute"; import { Paths } from "./Paths"; const ApplicationInventory = lazy( @@ -11,21 +12,37 @@ const Reports = lazy(() => import("./pages/reports")); const Controls = lazy(() => import("./pages/controls")); export const AppRoutes = () => { - const routes = [ + const routes: IProtectedRouteProps[] = [ { component: ApplicationInventory, path: Paths.applicationInventory, exact: false, + permissionsAllowed: ["inventory:application:read"], + }, + { + component: Reports, + path: Paths.reports, + exact: false, + permissionsAllowed: ["inventory:application:read"], + }, + { + component: Controls, + path: Paths.controls, + exact: false, + permissionsAllowed: ["controls:read"], }, - { component: Reports, path: Paths.reports, exact: false }, - { component: Controls, path: Paths.controls, exact: false }, ]; return ( }> {routes.map(({ path, component, ...rest }, index) => ( - + ))} diff --git a/src/layout/SidebarApp/SidebarApp.tsx b/src/layout/SidebarApp/SidebarApp.tsx index 0b5f7c44..2d0ec62c 100644 --- a/src/layout/SidebarApp/SidebarApp.tsx +++ b/src/layout/SidebarApp/SidebarApp.tsx @@ -5,7 +5,6 @@ import { Nav, NavItem, PageSidebar, NavList } from "@patternfly/react-core"; import { Paths } from "Paths"; import { LayoutTheme } from "../LayoutUtils"; -import { useKcPermission } from "shared/hooks"; import { VisibilityByPermission } from "shared/components"; export const SidebarApp: React.FC = () => { diff --git a/src/pages/application-inventory/application-inventory.tsx b/src/pages/application-inventory/application-inventory.tsx index d7d17e64..00ecbd0d 100644 --- a/src/pages/application-inventory/application-inventory.tsx +++ b/src/pages/application-inventory/application-inventory.tsx @@ -3,6 +3,7 @@ import { Redirect, Route, Switch, useLocation } from "react-router-dom"; import { Paths } from "Paths"; import { AppPlaceholder } from "shared/components"; +import { ProtectedRoute } from "ProtectedRoute"; const ApplicationList = lazy(() => import("./application-list")); const ApplicationAssessment = lazy(() => import("./application-assessment")); @@ -16,26 +17,31 @@ export const ApplicationInventory: React.FC = () => { return ( }> - - - - - { toolbar={ <> - - - + + + + + Date: Tue, 2 Nov 2021 09:29:49 +0100 Subject: [PATCH 4/9] Restore proxy settings --- src/setupProxy.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/setupProxy.js b/src/setupProxy.js index e403b9ad..76f4730f 100644 --- a/src/setupProxy.js +++ b/src/setupProxy.js @@ -4,7 +4,7 @@ module.exports = function (app) { app.use( "/api/controls", createProxyMiddleware({ - target: "http://localhost:8087", + target: "http://localhost:8081", changeOrigin: true, pathRewrite: { "^/api/controls": "/controls", @@ -15,7 +15,7 @@ module.exports = function (app) { app.use( "/api/application-inventory", createProxyMiddleware({ - target: "http://localhost:8088", + target: "http://localhost:8082", changeOrigin: true, pathRewrite: { "^/api/application-inventory": "/application-inventory", @@ -26,7 +26,7 @@ module.exports = function (app) { app.use( "/api/pathfinder", createProxyMiddleware({ - target: "http://localhost:8089", + target: "http://localhost:8083", changeOrigin: true, pathRewrite: { "^/api/pathfinder": "/pathfinder", From 872d053ae4e26a6e8d40b3b050458c546ee7a9ab Mon Sep 17 00:00:00 2001 From: Carlos Esteban Feria Vila <2582866+carlosthe19916@users.noreply.github.com> Date: Tue, 2 Nov 2021 10:03:24 +0100 Subject: [PATCH 5/9] Save changes --- konveyor-realm.json | 23 ++----------------- .../application-assessment-page-header.tsx | 12 ++++++---- .../custom-wizard-footer.tsx | 19 +++++++++------ .../application-inventory.tsx | 2 +- 4 files changed, 23 insertions(+), 33 deletions(-) diff --git a/konveyor-realm.json b/konveyor-realm.json index 70bd99f0..4cc13ee5 100644 --- a/konveyor-realm.json +++ b/konveyor-realm.json @@ -103,25 +103,6 @@ "containerId": "konveyor", "attributes": {} }, - { - "id": "74c6b736-7934-44de-88c0-435c927ada01", - "name": "user", - "description": "User of Tackle", - "composite": true, - "composites": { - "client": { - "tackle-api": [ - "controls:read", - "inventory:application:read", - "inventory:application-import:read", - "pathfinder:assessment:read" - ] - } - }, - "clientRole": false, - "containerId": "konveyor", - "attributes": {} - }, { "id": "85aa1467-987b-4a71-a7e1-92dffc90323b", "name": "uma_authorization", @@ -593,7 +574,7 @@ "defaultRoles": [ "uma_authorization", "offline_access", - "user" + "migrator" ], "requiredCredentials": [ "password" @@ -688,7 +669,7 @@ ], "requiredActions": [], "realmRoles": [ - "user" + "migrator" ], "notBefore": 0, "groups": [] diff --git a/src/pages/application-inventory/application-assessment/components/application-assessment-page/application-assessment-page-header.tsx b/src/pages/application-inventory/application-assessment/components/application-assessment-page/application-assessment-page-header.tsx index 7cfadc66..0638a2f5 100644 --- a/src/pages/application-inventory/application-assessment/components/application-assessment-page/application-assessment-page-header.tsx +++ b/src/pages/application-inventory/application-assessment/components/application-assessment-page/application-assessment-page-header.tsx @@ -7,7 +7,7 @@ import { Button, ButtonVariant, Modal, Text } from "@patternfly/react-core"; import { useDispatch } from "react-redux"; import { confirmDialogActions } from "store/confirmDialog"; -import { PageHeader } from "shared/components"; +import { PageHeader, VisibilityByPermission } from "shared/components"; import { useEntityModal } from "shared/hooks"; import { ApplicationDependenciesFormContainer } from "shared/containers"; @@ -76,9 +76,13 @@ export const ApplicationAssessmentPageHeader: React.FC {application && ( - + + + )} } diff --git a/src/pages/application-inventory/application-assessment/components/custom-wizard-footer/custom-wizard-footer.tsx b/src/pages/application-inventory/application-assessment/components/custom-wizard-footer/custom-wizard-footer.tsx index 19d32498..c5384c65 100644 --- a/src/pages/application-inventory/application-assessment/components/custom-wizard-footer/custom-wizard-footer.tsx +++ b/src/pages/application-inventory/application-assessment/components/custom-wizard-footer/custom-wizard-footer.tsx @@ -6,6 +6,7 @@ import { WizardContextConsumer, WizardFooter, } from "@patternfly/react-core"; +import { VisibilityByPermission } from "shared/components"; export interface CustomWizardFooterProps { isFirstStep: boolean; @@ -47,14 +48,18 @@ export const CustomWizardFooter: React.FC = ({ > {t("actions.save")} - + + ) : ( - + {showSaveAndReviewBtn && ( - + )} ) : (