Fix access for IDP links tab. (#29428)

* Fix access for IDP links tab.

Signed-off-by: Stan Silvert <ssilvert@redhat.com>

* Fix tests.

Signed-off-by: Stan Silvert <ssilvert@redhat.com>

---------

Signed-off-by: Stan Silvert <ssilvert@redhat.com>
This commit is contained in:
Stan Silvert 2024-05-14 08:49:47 -04:00 committed by GitHub
parent b4d231fd40
commit f14f4805d6
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 116 additions and 93 deletions

View file

@ -60,7 +60,7 @@ export default class IdentityProviderLinksTab {
public assertNoIdentityProvidersLinkedMessageExist(exist: boolean) {
cy.get(this.#linkedProvidersSection).should(
(exist ? "" : "not.") + "contain.text",
"No identity providers linked. Choose one from the list below.",
"No identity providers linked.",
);
return this;

View file

@ -2105,7 +2105,7 @@ duplicateEmailsHelpText=Allow multiple users to have the same email address. Cha
importOverwritten_zero=No records overwritten.
usermodel.realmRoleMapping.rolePrefix.label=Realm Role prefix
eventTypes.GRANT_CONSENT.name=Grant consent
noProvidersLinked=No identity providers linked. Choose one from the list below.
noProvidersLinked=No identity providers linked.
testConnectionSuccess=Success\! SMTP connection successful. E-mail was sent\!
samlSettings=SAML settings
userFedDisableConfirm=If you disable this user federation provider, it will not be considered for queries and imported users will be disabled and read-only until the provider is enabled again.

View file

@ -368,17 +368,15 @@ export default function EditUser() {
>
<UserConsents />
</Tab>
{hasAccess("view-identity-providers") && (
<Tab
data-testid="identity-provider-links-tab"
title={
<TabTitleText>{t("identityProviderLinks")}</TabTitleText>
}
{...identityProviderLinksTab}
>
<UserIdentityProviderLinks userId={user.id!} />
</Tab>
)}
<Tab
data-testid="identity-provider-links-tab"
title={
<TabTitleText>{t("identityProviderLinks")}</TabTitleText>
}
{...identityProviderLinksTab}
>
<UserIdentityProviderLinks userId={user.id!} />
</Tab>
<Tab
data-testid="user-sessions-tab"
title={<TabTitleText>{t("sessions")}</TabTitleText>}

View file

@ -24,6 +24,7 @@ import { useServerInfo } from "../context/server-info/ServerInfoProvider";
import { toIdentityProvider } from "../identity-providers/routes/IdentityProvider";
import { emptyFormatter, upperCaseFormatter } from "../util";
import { UserIdpModal } from "./UserIdPModal";
import { useAccess } from "../context/access/Access";
type UserIdentityProviderLinksProps = {
userId: string;
@ -41,6 +42,12 @@ export const UserIdentityProviderLinks = ({
const { realm } = useRealm();
const { addAlert, addError } = useAlerts();
const { t } = useTranslation();
const { hasAccess, hasSomeAccess } = useAccess();
const canQueryIDPDetails = hasSomeAccess(
"manage-identity-providers",
"view-identity-providers",
);
const refresh = () => setKey(new Date().getTime());
@ -51,15 +58,17 @@ export const UserIdentityProviderLinks = ({
const identityProviders = useServerInfo().identityProviders;
const getFederatedIdentities = async () => {
const allProviders = await adminClient.identityProviders.find();
const allFedIds = (await adminClient.users.listFederatedIdentities({
id: userId,
})) as WithProviderId[];
for (const element of allFedIds) {
element.providerId = allProviders.find(
(item) => item.alias === element.identityProvider,
)?.providerId!;
if (canQueryIDPDetails) {
const allProviders = await adminClient.identityProviders.find();
for (const element of allFedIds) {
element.providerId = allProviders.find(
(item) => item.alias === element.identityProvider,
)?.providerId!;
}
}
return allFedIds;
@ -107,6 +116,9 @@ export const UserIdentityProviderLinks = ({
});
const idpLinkRenderer = (idp: WithProviderId) => {
if (!canQueryIDPDetails)
return <span>{capitalize(idp.identityProvider)}</span>;
return (
<Link
to={toIdentityProvider({
@ -148,6 +160,8 @@ export const UserIdentityProviderLinks = ({
};
const unlinkRenderer = (fedIdentity: FederatedIdentityRepresentation) => {
if (!hasAccess("manage-users")) return <span />;
return (
<Button
variant="link"
@ -175,6 +189,48 @@ export const UserIdentityProviderLinks = ({
);
};
const linkedIdpColumns = () => {
const columns = [
{
name: "identityProvider",
displayKey: "name",
cellFormatters: [emptyFormatter()],
cellRenderer: idpLinkRenderer,
transforms: [cellWidth(20)],
},
{
name: "userId",
displayKey: "userID",
cellFormatters: [emptyFormatter()],
transforms: [cellWidth(30)],
},
{
name: "userName",
displayKey: "username",
cellFormatters: [emptyFormatter()],
transforms: [cellWidth(20)],
},
{
name: "",
cellFormatters: [emptyFormatter()],
cellRenderer: unlinkRenderer,
transforms: [cellWidth(20)],
},
];
if (canQueryIDPDetails)
columns.splice(1, 0, {
name: "type",
displayKey: "type",
cellFormatters: [emptyFormatter()],
cellRenderer: badgeRenderer1,
transforms: [cellWidth(10)],
});
return columns;
};
return (
<>
{isLinkIdPModalOpen && (
@ -199,40 +255,7 @@ export const UserIdentityProviderLinks = ({
isPaginated={false}
ariaLabelKey="LinkedIdPs"
className="kc-linked-IdPs-table"
columns={[
{
name: "identityProvider",
displayKey: "name",
cellFormatters: [emptyFormatter()],
cellRenderer: idpLinkRenderer,
transforms: [cellWidth(20)],
},
{
name: "type",
displayKey: "type",
cellFormatters: [emptyFormatter()],
cellRenderer: badgeRenderer1,
transforms: [cellWidth(10)],
},
{
name: "userId",
displayKey: "userID",
cellFormatters: [emptyFormatter()],
transforms: [cellWidth(30)],
},
{
name: "userName",
displayKey: "username",
cellFormatters: [emptyFormatter()],
transforms: [cellWidth(20)],
},
{
name: "",
cellFormatters: [emptyFormatter()],
cellRenderer: unlinkRenderer,
transforms: [cellWidth(20)],
},
]}
columns={linkedIdpColumns()}
emptyState={
<TextContent className="kc-no-providers-text">
<Text>{t("noProvidersLinked")}</Text>
@ -240,45 +263,47 @@ export const UserIdentityProviderLinks = ({
}
/>
</FormPanel>
<FormPanel className="kc-available-idps" title={t("availableIdPs")}>
<TextContent>
<Text className="kc-available-idps-text">
{t("availableIdPsText")}
</Text>
</TextContent>
<KeycloakDataTable
loader={availableIdPsLoader}
key={key}
isPaginated={false}
ariaLabelKey="LinkedIdPs"
className="kc-linked-IdPs-table"
columns={[
{
name: "alias",
displayKey: "name",
cellFormatters: [emptyFormatter(), upperCaseFormatter()],
transforms: [cellWidth(20)],
},
{
name: "type",
displayKey: "type",
cellFormatters: [emptyFormatter()],
cellRenderer: badgeRenderer2,
transforms: [cellWidth(60)],
},
{
name: "",
cellFormatters: [emptyFormatter()],
cellRenderer: linkRenderer,
},
]}
emptyState={
<TextContent className="kc-no-providers-text">
<Text>{t("noAvailableIdentityProviders")}</Text>
</TextContent>
}
/>
</FormPanel>
{hasAccess("manage-users") && canQueryIDPDetails && (
<FormPanel className="kc-available-idps" title={t("availableIdPs")}>
<TextContent>
<Text className="kc-available-idps-text">
{t("availableIdPsText")}
</Text>
</TextContent>
<KeycloakDataTable
loader={availableIdPsLoader}
key={key}
isPaginated={false}
ariaLabelKey="LinkedIdPs"
className="kc-linked-IdPs-table"
columns={[
{
name: "alias",
displayKey: "name",
cellFormatters: [emptyFormatter(), upperCaseFormatter()],
transforms: [cellWidth(20)],
},
{
name: "type",
displayKey: "type",
cellFormatters: [emptyFormatter()],
cellRenderer: badgeRenderer2,
transforms: [cellWidth(60)],
},
{
name: "",
cellFormatters: [emptyFormatter()],
cellRenderer: linkRenderer,
},
]}
emptyState={
<TextContent className="kc-no-providers-text">
<Text>{t("noAvailableIdentityProviders")}</Text>
</TextContent>
}
/>
</FormPanel>
)}
</PageSection>
</>
);