Add federated user link (#3928)

This commit is contained in:
Erik Jan de Wit 2022-12-06 05:05:41 -05:00 committed by GitHub
parent 14beb87b6b
commit 14a7e49468
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 80 additions and 43 deletions

View file

@ -5,5 +5,6 @@
"requiredUserActions": "Require an action when the user logs in. 'Verify email' sends an email to the user to verify their email address. 'Update profile' requires user to enter in new personal information. 'Update password' requires user to enter in a new password. 'Configure OTP' requires setup of a mobile password generator.",
"groups": "Groups where the user has membership. To leave a group, select it and click Leave.",
"userIdHelperText": "Enter the unique ID of the user for this identity provider.",
"usernameHelperText": "Enter the username of the user for this identity provider."
"usernameHelperText": "Enter the username of the user for this identity provider.",
"federationLink": "UserStorageProvider this locally stored user was imported from."
}

View file

@ -45,6 +45,7 @@
"emailInvalid": "You must enter a valid email.",
"notVerified": "Not verified",
"requiredUserActions": "Required user actions",
"federationLink": "Federation link",
"addUser": "Add user",
"impersonate": "Impersonate",
"impersonateConfirm": "Impersonate user?",

View file

@ -0,0 +1,55 @@
import { Button } from "@patternfly/react-core";
import { useState } from "react";
import { Link } from "react-router-dom-v5-compat";
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import { useAccess } from "../context/access/Access";
import { useAdminClient, useFetch } from "../context/auth/AdminClient";
import { useRealm } from "../context/realm-context/RealmContext";
import { toUserFederationLdap } from "../user-federation/routes/UserFederationLdap";
type FederatedUserLinkProps = {
user: UserRepresentation;
};
export const FederatedUserLink = ({ user }: FederatedUserLinkProps) => {
const access = useAccess();
const { realm } = useRealm();
const { adminClient } = useAdminClient();
const [component, setComponent] = useState<ComponentRepresentation>();
useFetch(
() =>
access.hasAccess("view-realm")
? adminClient.components.findOne({
id: (user.federationLink || user.origin)!,
})
: adminClient.userStorageProvider.name({
id: (user.federationLink || user.origin)!,
}),
setComponent,
[]
);
if (!component) return null;
return (
<Button
variant="link"
isDisabled={!access.hasAccess("view-realm")}
component={(props) => (
<Link
{...props}
to={toUserFederationLdap({
id: component.id!,
realm,
})}
/>
)}
>
{component.name}
</Button>
);
};

View file

@ -31,6 +31,7 @@ import type RequiredActionProviderRepresentation from "@keycloak/keycloak-admin-
import { useAccess } from "../context/access/Access";
import useIsFeatureEnabled, { Feature } from "../utils/useIsFeatureEnabled";
import { UserProfileFields } from "./UserProfileFields";
import { FederatedUserLink } from "./FederatedUserLink";
export type BruteForced = {
isBruteForceProtected?: boolean;
@ -242,6 +243,19 @@ export const UserForm = ({
)}
/>
</FormGroup>
{(user?.federationLink || user?.origin) && (
<FormGroup
label={t("federationLink")}
labelIcon={
<HelpItem
helpText="users-help:federationLink"
fieldLabelId="users:federationLink"
/>
}
>
<FederatedUserLink user={user} />
</FormGroup>
)}
{isFeatureEnabled(Feature.DeclarativeUserProfile) &&
realm?.attributes?.userProfileEnabled === "true" ? (
<UserProfileFields />

View file

@ -1,5 +1,3 @@
import { useState } from "react";
import { useTranslation } from "react-i18next";
import {
Button,
PageSection,
@ -13,15 +11,13 @@ import {
Thead,
Tr,
} from "@patternfly/react-table";
import { useState } from "react";
import { useTranslation } from "react-i18next";
import type ComponentRepresentation from "@keycloak/keycloak-admin-client/lib/defs/componentRepresentation";
import type UserRepresentation from "@keycloak/keycloak-admin-client/lib/defs/userRepresentation";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { KeycloakSpinner } from "../../components/keycloak-spinner/KeycloakSpinner";
import { useAccess } from "../../context/access/Access";
import { toUserFederationLdap } from "../../user-federation/routes/UserFederationLdap";
import { useRealm } from "../../context/realm-context/RealmContext";
import { Link } from "react-router-dom";
import { useAdminClient, useFetch } from "../../context/auth/AdminClient";
import { FederatedUserLink } from "../FederatedUserLink";
type FederatedCredentialsProps = {
user: UserRepresentation;
@ -34,32 +30,16 @@ export const FederatedCredentials = ({
}: FederatedCredentialsProps) => {
const { t } = useTranslation("users");
const { adminClient } = useAdminClient();
const { realm } = useRealm();
const [credentialTypes, setCredentialTypes] = useState<string[]>();
const [component, setComponent] = useState<ComponentRepresentation>();
const access = useAccess();
useFetch(
() =>
Promise.all([
adminClient.users.getUserStorageCredentialTypes({ id: user.id! }),
access.hasAccess("view-realm")
? adminClient.components.findOne({
id: (user.federationLink || user.origin)!,
})
: adminClient.userStorageProvider.name({
id: (user.federationLink || user.origin)!,
}),
]),
([credentialTypes, component]) => {
setCredentialTypes(credentialTypes);
setComponent(component);
},
() => adminClient.users.getUserStorageCredentialTypes({ id: user.id! }),
setCredentialTypes,
[]
);
if (!credentialTypes || !component) {
if (!credentialTypes) {
return <KeycloakSpinner />;
}
@ -80,21 +60,7 @@ export const FederatedCredentials = ({
<b>{credential}</b>
</Td>
<Td>
<Button
variant="link"
isDisabled={!access.hasAccess("view-realm")}
component={(props) => (
<Link
{...props}
to={toUserFederationLdap({
id: component.id!,
realm,
})}
/>
)}
>
{component.name}
</Button>
<FederatedUserLink user={user} />
</Td>
{credential === "password" && (
<Td modifier="fitContent">