2021-03-19 12:43:32 +00:00
|
|
|
import React, { useContext, useState } from "react";
|
2020-12-07 18:37:36 +00:00
|
|
|
import { useTranslation } from "react-i18next";
|
2021-04-20 12:10:00 +00:00
|
|
|
import { AlertVariant } from "@patternfly/react-core";
|
2020-12-07 18:37:36 +00:00
|
|
|
|
2021-05-04 17:58:18 +00:00
|
|
|
import type RoleRepresentation from "keycloak-admin/lib/defs/roleRepresentation";
|
|
|
|
import type { RoleMappingPayload } from "keycloak-admin/lib/defs/roleRepresentation";
|
2020-12-07 18:37:36 +00:00
|
|
|
import { useAdminClient } from "../../context/auth/AdminClient";
|
|
|
|
import { RealmContext } from "../../context/realm-context/RealmContext";
|
2021-04-01 14:14:19 +00:00
|
|
|
import { useAlerts } from "../../components/alert/Alerts";
|
2021-04-20 12:10:00 +00:00
|
|
|
import {
|
|
|
|
CompositeRole,
|
|
|
|
RoleMapping,
|
|
|
|
Row,
|
|
|
|
} from "../../components/role-mapping/RoleMapping";
|
2020-12-07 18:37:36 +00:00
|
|
|
|
|
|
|
type ServiceAccountProps = {
|
|
|
|
clientId: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
export const ServiceAccount = ({ clientId }: ServiceAccountProps) => {
|
|
|
|
const { t } = useTranslation("clients");
|
|
|
|
const adminClient = useAdminClient();
|
|
|
|
const { realm } = useContext(RealmContext);
|
2021-04-01 14:14:19 +00:00
|
|
|
const { addAlert } = useAlerts();
|
|
|
|
|
2020-12-07 18:37:36 +00:00
|
|
|
const [hide, setHide] = useState(false);
|
2021-04-01 14:14:19 +00:00
|
|
|
const [serviceAccountId, setServiceAccountId] = useState("");
|
2021-04-20 12:10:00 +00:00
|
|
|
const [name, setName] = useState("");
|
2020-12-07 18:37:36 +00:00
|
|
|
|
|
|
|
const loader = async () => {
|
|
|
|
const serviceAccount = await adminClient.clients.getServiceAccountUser({
|
|
|
|
id: clientId,
|
|
|
|
});
|
2021-04-01 14:14:19 +00:00
|
|
|
setServiceAccountId(serviceAccount.id!);
|
2020-12-07 18:37:36 +00:00
|
|
|
const effectiveRoles = await adminClient.users.listCompositeRealmRoleMappings(
|
|
|
|
{ id: serviceAccount.id! }
|
|
|
|
);
|
|
|
|
const assignedRoles = await adminClient.users.listRealmRoleMappings({
|
|
|
|
id: serviceAccount.id!,
|
|
|
|
});
|
|
|
|
|
|
|
|
const clients = await adminClient.clients.find();
|
2021-04-20 12:10:00 +00:00
|
|
|
setName(clients.find((c) => c.id === clientId)?.clientId!);
|
2020-12-07 18:37:36 +00:00
|
|
|
const clientRoles = (
|
|
|
|
await Promise.all(
|
|
|
|
clients.map(async (client) => {
|
|
|
|
return {
|
|
|
|
client,
|
|
|
|
roles: await adminClient.users.listClientRoleMappings({
|
|
|
|
id: serviceAccount.id!,
|
|
|
|
clientUniqueId: client.id!,
|
|
|
|
}),
|
|
|
|
};
|
|
|
|
})
|
|
|
|
)
|
|
|
|
).filter((rows) => rows.roles.length > 0);
|
|
|
|
|
|
|
|
const findClient = (role: RoleRepresentation) => {
|
|
|
|
const row = clientRoles.filter((row) =>
|
|
|
|
row.roles.find((r) => r.id === role.id)
|
|
|
|
)[0];
|
|
|
|
return row ? row.client : undefined;
|
|
|
|
};
|
|
|
|
|
|
|
|
const clientRolesFlat = clientRoles.map((row) => row.roles).flat();
|
|
|
|
|
|
|
|
const addInherentData = await (async () =>
|
|
|
|
Promise.all(
|
|
|
|
effectiveRoles.map(async (role) => {
|
|
|
|
const compositeRoles = await adminClient.roles.getCompositeRolesForRealm(
|
|
|
|
{ realm, id: role.id! }
|
|
|
|
);
|
|
|
|
return compositeRoles.length > 0
|
|
|
|
? compositeRoles.map((r) => {
|
|
|
|
return { ...r, parent: role };
|
|
|
|
})
|
|
|
|
: { ...role, parent: undefined };
|
|
|
|
})
|
|
|
|
))();
|
|
|
|
const uniqueRolesWithParent = addInherentData
|
|
|
|
.flat()
|
|
|
|
.filter(
|
|
|
|
(role, index, array) =>
|
|
|
|
array.findIndex((r) => r.id === role.id) === index
|
|
|
|
);
|
|
|
|
return ([
|
|
|
|
...(hide ? assignedRoles : uniqueRolesWithParent),
|
|
|
|
...clientRolesFlat,
|
|
|
|
] as CompositeRole[])
|
|
|
|
.sort((r1, r2) => r1.name!.localeCompare(r2.name!))
|
|
|
|
.map((role) => {
|
|
|
|
return {
|
2021-03-19 12:43:32 +00:00
|
|
|
client: findClient(role),
|
|
|
|
role,
|
|
|
|
} as Row;
|
2020-12-07 18:37:36 +00:00
|
|
|
});
|
|
|
|
};
|
|
|
|
|
2021-04-01 14:14:19 +00:00
|
|
|
const assignRoles = async (rows: Row[]) => {
|
|
|
|
try {
|
|
|
|
const realmRoles = rows
|
|
|
|
.filter((row) => row.client === undefined)
|
|
|
|
.map((row) => row.role as RoleMappingPayload)
|
|
|
|
.flat();
|
|
|
|
adminClient.users.addRealmRoleMappings({
|
|
|
|
id: serviceAccountId,
|
|
|
|
roles: realmRoles,
|
|
|
|
});
|
|
|
|
await Promise.all(
|
|
|
|
rows
|
|
|
|
.filter((row) => row.client !== undefined)
|
|
|
|
.map((row) =>
|
|
|
|
adminClient.users.addClientRoleMappings({
|
|
|
|
id: serviceAccountId,
|
|
|
|
clientUniqueId: row.client!.id!,
|
|
|
|
roles: [row.role as RoleMappingPayload],
|
|
|
|
})
|
|
|
|
)
|
|
|
|
);
|
|
|
|
addAlert(t("roleMappingUpdatedSuccess"), AlertVariant.success);
|
|
|
|
} catch (error) {
|
|
|
|
addAlert(
|
|
|
|
t("roleMappingUpdatedError", {
|
|
|
|
error: error.response?.data?.errorMessage || error,
|
|
|
|
}),
|
|
|
|
AlertVariant.danger
|
|
|
|
);
|
|
|
|
}
|
|
|
|
};
|
|
|
|
return (
|
2021-04-20 12:10:00 +00:00
|
|
|
<RoleMapping
|
|
|
|
name={name}
|
|
|
|
id={serviceAccountId}
|
|
|
|
type={"service-account"}
|
|
|
|
loader={loader}
|
|
|
|
save={assignRoles}
|
|
|
|
onHideRolesToggle={() => setHide(!hide)}
|
|
|
|
/>
|
2021-03-19 12:43:32 +00:00
|
|
|
);
|
2020-12-07 18:37:36 +00:00
|
|
|
};
|