Add federated user link (#3928)
This commit is contained in:
parent
14beb87b6b
commit
14a7e49468
5 changed files with 80 additions and 43 deletions
|
@ -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."
|
||||
}
|
|
@ -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?",
|
||||
|
|
55
apps/admin-ui/src/user/FederatedUserLink.tsx
Normal file
55
apps/admin-ui/src/user/FederatedUserLink.tsx
Normal 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>
|
||||
);
|
||||
};
|
|
@ -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 />
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in a new issue