From e1639f3283ceb03537674bcae074ac7b47ed6b0f Mon Sep 17 00:00:00 2001 From: Erik Jan de Wit Date: Tue, 10 May 2022 11:50:00 +0200 Subject: [PATCH] Added permissions tab for idp (#2597) --- package-lock.json | 85 ++++++++++++------- package.json | 2 +- public/resources/en/common.json | 4 + src/components/alert/Alerts.tsx | 34 ++++++-- .../permission-tab/PermissionTab.tsx | 24 +++++- src/identity-providers/add/DetailSettings.tsx | 9 ++ 6 files changed, 116 insertions(+), 42 deletions(-) diff --git a/package-lock.json b/package-lock.json index 45bdd67b70..7a529f66b1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -7,7 +7,7 @@ "name": "keycloak-admin-ui", "license": "Apache", "dependencies": { - "@keycloak/keycloak-admin-client": "^19.0.0-dev.0", + "@keycloak/keycloak-admin-client": "^19.0.0-dev.3", "@patternfly/patternfly": "^4.185.1", "@patternfly/react-code-editor": "^4.43.16", "@patternfly/react-core": "^4.202.16", @@ -3567,11 +3567,11 @@ } }, "node_modules/@keycloak/keycloak-admin-client": { - "version": "19.0.0-dev.0", - "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-19.0.0-dev.0.tgz", - "integrity": "sha512-QkCPuWUxf0rVw/V24VoaLC4luDLePGScyT12pVYaujZX9VaWQTNdZS3Ipm47W2+kNQQvL2NPWxKkWJmEWXyMiQ==", + "version": "19.0.0-dev.3", + "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-19.0.0-dev.3.tgz", + "integrity": "sha512-L484+2mDOYGhIXJqIS+zQ1LmJfawrf40nfjNOV9x8kThtpnf0te7zy7am8yDHJlDcTZv66PLu9DotF8t8kdKEw==", "dependencies": { - "axios": "^0.26.1", + "axios": "^0.27.2", "camelize-ts": "^1.0.8", "keycloak-js": "^18.0.0", "lodash": "^4.17.21", @@ -6255,8 +6255,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "node_modules/at-least-node": { "version": "1.0.0", @@ -6313,11 +6312,25 @@ "dev": true }, "node_modules/axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "dependencies": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/axios/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" } }, "node_modules/babel-jest": { @@ -7943,7 +7956,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -9154,7 +9166,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -10859,9 +10870,9 @@ } }, "node_modules/follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==", + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==", "funding": [ { "type": "individual", @@ -25452,11 +25463,11 @@ } }, "@keycloak/keycloak-admin-client": { - "version": "19.0.0-dev.0", - "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-19.0.0-dev.0.tgz", - "integrity": "sha512-QkCPuWUxf0rVw/V24VoaLC4luDLePGScyT12pVYaujZX9VaWQTNdZS3Ipm47W2+kNQQvL2NPWxKkWJmEWXyMiQ==", + "version": "19.0.0-dev.3", + "resolved": "https://registry.npmjs.org/@keycloak/keycloak-admin-client/-/keycloak-admin-client-19.0.0-dev.3.tgz", + "integrity": "sha512-L484+2mDOYGhIXJqIS+zQ1LmJfawrf40nfjNOV9x8kThtpnf0te7zy7am8yDHJlDcTZv66PLu9DotF8t8kdKEw==", "requires": { - "axios": "^0.26.1", + "axios": "^0.27.2", "camelize-ts": "^1.0.8", "keycloak-js": "^18.0.0", "lodash": "^4.17.21", @@ -27680,8 +27691,7 @@ "asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", - "dev": true + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=" }, "at-least-node": { "version": "1.0.0", @@ -27723,11 +27733,24 @@ "dev": true }, "axios": { - "version": "0.26.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", - "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", "requires": { - "follow-redirects": "^1.14.8" + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + }, + "dependencies": { + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + } } }, "babel-jest": { @@ -29017,7 +29040,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "requires": { "delayed-stream": "~1.0.0" } @@ -29976,8 +29998,7 @@ "delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", - "dev": true + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=" }, "delegates": { "version": "1.0.0", @@ -31302,9 +31323,9 @@ } }, "follow-redirects": { - "version": "1.14.9", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.14.9.tgz", - "integrity": "sha512-MQDfihBQYMcyy5dhRDJUHcw7lb2Pv/TuE6xP1vyraLukNDHKbDxDNaOE3NbCAdKQApno+GPRyo1YAp89yCjK4w==" + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.0.tgz", + "integrity": "sha512-aExlJShTV4qOUOL7yF1U5tvLCB0xQuudbf6toyYA0E/acBNw71mvjFTnLaRp50aQaYocMR0a/RMMBIHeZnGyjQ==" }, "for-in": { "version": "1.0.2", diff --git a/package.json b/package.json index cae41e3011..39d521ccd1 100644 --- a/package.json +++ b/package.json @@ -25,7 +25,7 @@ "server:import-client": "./scripts/import-client.mjs" }, "dependencies": { - "@keycloak/keycloak-admin-client": "^19.0.0-dev.0", + "@keycloak/keycloak-admin-client": "^19.0.0-dev.3", "@patternfly/patternfly": "^4.185.1", "@patternfly/react-code-editor": "^4.43.16", "@patternfly/react-core": "^4.202.16", diff --git a/public/resources/en/common.json b/public/resources/en/common.json index ba85ede758..8b6bac750c 100644 --- a/public/resources/en/common.json +++ b/public/resources/en/common.json @@ -93,6 +93,7 @@ "clientsPermissionsHint": "Fine grained permissions for administrators that want to manage this client or apply roles defined by this client.", "groupsPermissionsHint": "Determines if fine grained permissions are enabled for managing this role. Disabling will delete all current permissions that have been set up.", "rolesPermissionsHint": "Determines if fine grained permissions are enabled for managing this role. Disabling will delete all current permissions that have been set up.", + "identityProvidersPermissionsHint": "Determines if fine grained permissions are enabled for managing this role. Disabling will delete all current permissions that have been set up.", "permissionsScopeName": "Scope-name", "permissionsEnabled": "Permissions enabled", "permissionsDisable": "Disable permissions?", @@ -126,6 +127,9 @@ "map-role-description": "Policies that decide if an administrator can map this role to a user or group", "map-role-client-scope-description": "Policies that decide if an administrator can apply this role to the client scope of a client", "map-role-composite-description": "Policies that decide if an administrator can apply this role as a composite to another role" + }, + "identityProviders": { + "token-exchange-description": "Policies that decide which clients are allowed exchange tokens for an external token minted by this identity provider." } }, "configure": "Configure", diff --git a/src/components/alert/Alerts.tsx b/src/components/alert/Alerts.tsx index 1fb35a0deb..393d97713d 100644 --- a/src/components/alert/Alerts.tsx +++ b/src/components/alert/Alerts.tsx @@ -1,6 +1,7 @@ import React, { createContext, FunctionComponent, useState } from "react"; import { useTranslation } from "react-i18next"; import { AlertVariant } from "@patternfly/react-core"; +import axios from "axios"; import type { AxiosError } from "axios"; import useRequiredContext from "../../utils/useRequiredContext"; @@ -42,15 +43,10 @@ export const AlertProvider: FunctionComponent = ({ children }) => { setAlerts([{ key, message, variant, description }, ...alerts]); }; - const addError = (message: string, error: Error | AxiosError) => { + const addError = (message: string, error: Error | AxiosError | string) => { addAlert( t(message, { - error: - "response" in error - ? error.response?.data?.error_description || - error.response?.data?.errorMessage || - error.response?.data?.error - : error, + error: getErrorMessage(error), }), AlertVariant.danger ); @@ -63,3 +59,27 @@ export const AlertProvider: FunctionComponent = ({ children }) => { ); }; + +function getErrorMessage( + error: Error | AxiosError> | string +) { + if (typeof error === "string") { + return error; + } + + if (!axios.isAxiosError(error)) { + return error.message; + } + + const responseData = error.response?.data ?? {}; + + for (const key of ["error_description", "errorMessage", "error"]) { + const value = responseData[key]; + + if (typeof value === "string") { + return value; + } + } + + return error.message; +} diff --git a/src/components/permission-tab/PermissionTab.tsx b/src/components/permission-tab/PermissionTab.tsx index 3db1580a81..ca84cce3e7 100644 --- a/src/components/permission-tab/PermissionTab.tsx +++ b/src/components/permission-tab/PermissionTab.tsx @@ -31,7 +31,12 @@ import { useConfirmDialog } from "../confirm-dialog/ConfirmDialog"; import "./permissions-tab.css"; -type PermissionScreenType = "clients" | "users" | "groups" | "roles"; +type PermissionScreenType = + | "clients" + | "users" + | "groups" + | "roles" + | "identityProviders"; type PermissionsTabProps = { id?: string; @@ -63,6 +68,11 @@ export const PermissionsTab = ({ id, type }: PermissionsTabProps) => { return adminClient.groups.updatePermission({ id: id! }, { enabled }); case "roles": return adminClient.roles.updatePermission({ id: id! }, { enabled }); + case "identityProviders": + return adminClient.identityProviders.updatePermission( + { alias: id! }, + { enabled } + ); } }; @@ -85,6 +95,10 @@ export const PermissionsTab = ({ id, type }: PermissionsTabProps) => { return adminClient.groups.listPermissions({ id: id! }); case "roles": return adminClient.roles.listPermissions({ id: id! }); + case "identityProviders": + return adminClient.identityProviders.listPermissions({ + alias: id!, + }); } })(), ]), @@ -154,7 +168,13 @@ export const PermissionsTab = ({ id, type }: PermissionsTabProps) => { {" "} - {{ realm: `${realm}-realm` }}. + + {{ + realm: + realm === "master" ? "master-realm" : "realm-management", + }} + + . diff --git a/src/identity-providers/add/DetailSettings.tsx b/src/identity-providers/add/DetailSettings.tsx index 4a6baad89d..82d19c731c 100644 --- a/src/identity-providers/add/DetailSettings.tsx +++ b/src/identity-providers/add/DetailSettings.tsx @@ -47,6 +47,7 @@ import { IdentityProviderParams, toIdentityProvider, } from "../routes/IdentityProvider"; +import { PermissionsTab } from "../../components/permission-tab/PermissionTab"; type HeaderProps = { onChange: (value: boolean) => void; @@ -420,6 +421,14 @@ export default function DetailSettings() { ]} /> + {t("common:permissions")}} + > + +