Added permissions tab for idp (#2597)

This commit is contained in:
Erik Jan de Wit 2022-05-10 11:50:00 +02:00 committed by GitHub
parent 5427eaf6ff
commit e1639f3283
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 116 additions and 42 deletions

85
package-lock.json generated
View file

@ -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",

View file

@ -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",

View file

@ -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",

View file

@ -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 }) => {
</AlertContext.Provider>
);
};
function getErrorMessage(
error: Error | AxiosError<Record<string, unknown>> | 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;
}

View file

@ -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) => {
<CardBody>
<Trans i18nKey="common:permissionsListIntro">
{" "}
<strong>{{ realm: `${realm}-realm` }}</strong>.
<strong>
{{
realm:
realm === "master" ? "master-realm" : "realm-management",
}}
</strong>
.
</Trans>
</CardBody>
</Card>

View file

@ -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() {
]}
/>
</Tab>
<Tab
id="permissions"
data-testid="permissionsTab"
eventKey="permissions"
title={<TabTitleText>{t("common:permissions")}</TabTitleText>}
>
<PermissionsTab id={alias} type="identityProviders" />
</Tab>
</KeycloakTabs>
</FormProvider>
</PageSection>