Skip to content

Commit

Permalink
Add 'Unlock' option
Browse files Browse the repository at this point in the history
The 'Unlock' option should
unlock a specific account
when a user has exceeded
the maximum amount of login
attempts (6 according the
global policy).

Signed-off-by: Carla Martinez <carlmart@redhat.com>
  • Loading branch information
carma12 committed Jan 8, 2024
1 parent 9d4b7cf commit 5798ab3
Show file tree
Hide file tree
Showing 3 changed files with 168 additions and 1 deletion.
39 changes: 38 additions & 1 deletion src/components/UserSettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import useAlerts from "src/hooks/useAlerts";
import DisableEnableUsers from "./modals/DisableEnableUsers";
import DeleteUsers from "./modals/DeleteUsers";
import RebuildAutoMembership from "./modals/RebuildAutoMembership";
import UnlockUser from "./modals/UnlockUser";

export interface PropsToUserSettings {
originalUser: Partial<User>;
Expand Down Expand Up @@ -133,6 +134,33 @@ const UserSettings = (props: PropsToUserSettings) => {
};
const userToRebuild = props.user.uid ? [props.user.uid] : [];

// 'Unlock' option
const [isUnlockModalOpen, setIsUnlockModalOpen] = React.useState(false);
const onCloseUnlockModal = () => {
setIsUnlockModalOpen(false);
};

// Get the status of the 'Unlock' option
// - locked: true | unlocked: false
const getUnlockStatus = (): boolean => {
let isLocked = false;
if (
props.user.krbloginfailedcount &&
props.pwPolicyData.krbpwdmaxfailure !== undefined
) {
// In case there is no permission to check password policy we
// allow to unlock user even if he has only one failed login.
const max_failure = props.pwPolicyData
? props.pwPolicyData.krbpwdmaxfailure[0]
: 1;

if (props.user.krbloginfailedcount[0] >= max_failure) {
isLocked = true;
}
}
return isLocked;
};

// Kebab
const [isKebabOpen, setIsKebabOpen] = useState(false);

Expand All @@ -155,7 +183,11 @@ const UserSettings = (props: PropsToUserSettings) => {
<DropdownItem key="delete" onClick={() => setIsDeleteModalOpen(true)}>
Delete
</DropdownItem>,
<DropdownItem key="unlock" isDisabled>
<DropdownItem
key="unlock"
isDisabled={!getUnlockStatus()}
onClick={() => setIsUnlockModalOpen(true)}
>
Unlock
</DropdownItem>,
<DropdownItem key="add otp token">Add OTP token</DropdownItem>,
Expand Down Expand Up @@ -437,6 +469,11 @@ const UserSettings = (props: PropsToUserSettings) => {
optionSelected={optionSelected}
selectedUsersData={selectedUsersData}
singleUser={true}
/>
<UnlockUser
uid={props.user.uid}
isOpen={isUnlockModalOpen}
onClose={onCloseUnlockModal}
onRefresh={props.onRefresh}
/>
<DeleteUsers
Expand Down
114 changes: 114 additions & 0 deletions src/components/modals/UnlockUser.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import React from "react";
// PatternFly
import {
Button,
TextContent,
Text,
TextVariants,
} from "@patternfly/react-core";
// Modals
import ModalWithFormLayout from "../layouts/ModalWithFormLayout";
// RPC
import { ErrorResult, useUnlockUserMutation } from "src/services/rpc";
// Hooks
import useAlerts from "src/hooks/useAlerts";

interface propsToUnlockUser {
uid: string | undefined;
isOpen: boolean;
onClose: () => void;
onRefresh: () => void;
}

const UnlockUser = (props: propsToUnlockUser) => {
// Alerts to show in the UI
const alerts = useAlerts();

// RPC hooks
const [unlockUser] = useUnlockUserMutation();

// List of fields
const fields = [
{
id: "question-text",
pfComponent: (
<TextContent>
<Text component={TextVariants.p}>
{"Are you sure you want to unlock user '" + props.uid + "'?"}
</Text>
</TextContent>
),
},
];

// on unlock user
const onUnlockUser = () => {
// API call to reset password
if (props.uid === undefined) {
// Alert error: no uid
alerts.addAlert(
"undefined-uid-error",
"No user selected to unlock",
"danger"
);
} else {
unlockUser(props.uid).then((response) => {
if ("data" in response) {
if (response.data.result) {
// Close modal
props.onClose();
// Set alert: success
alerts.addAlert(
"unlock-user-success",
"Unlocked account '" + props.uid + "'",
"success"
);
// Refresh data
props.onRefresh();
} else if (response.data.error) {
// Set alert: error
const errorMessage = response.data.error as ErrorResult;
alerts.addAlert(
"unlock-user-error",
errorMessage.message,
"danger"
);
}
}
});
}
};

// Actions
const actions: JSX.Element[] = [
<Button
key="unlock-user"
variant="primary"
onClick={onUnlockUser}
form="unlock-user-modal"
>
Ok
</Button>,
<Button key="cancel-unlock-user" variant="link" onClick={props.onClose}>
Cancel
</Button>,
];

return (
<>
<alerts.ManagedAlerts />
<ModalWithFormLayout
variantType="small"
modalPosition="top"
title="Unlock user"
formId="unlock-user-form"
fields={fields}
show={props.isOpen}
onClose={props.onClose}
actions={actions}
/>
</>
);
};

export default UnlockUser;
16 changes: 16 additions & 0 deletions src/services/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -700,6 +700,21 @@ export const api = createApi({
});
},
}),
unlockUser: build.mutation<FindRPCResponse, string>({
query: (uid) => {
const params = [
[uid],
{
version: API_VERSION_BACKUP,
},
];

return getCommand({
method: "user_unlock",
params: params,
});
},
}),
}),
});

Expand Down Expand Up @@ -767,4 +782,5 @@ export const {
useAutoMemberRebuildUsersMutation,
useEnableUserMutation,
useDisableUserMutation,
useUnlockUserMutation,
} = api;

0 comments on commit 5798ab3

Please sign in to comment.