added remove all temporary locks (#1082)

This commit is contained in:
Erik Jan de Wit 2021-09-02 22:16:32 +02:00 committed by GitHub
parent 2416d25c38
commit e5e07eb1bc
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 81 additions and 12 deletions

View file

@ -2,6 +2,9 @@ import {
AlertVariant, AlertVariant,
Button, Button,
ButtonVariant, ButtonVariant,
Dropdown,
DropdownItem,
KebabToggle,
Label, Label,
PageSection, PageSection,
Text, Text,
@ -28,6 +31,7 @@ import { useRealm } from "../context/realm-context/RealmContext";
import { emptyFormatter } from "../util"; import { emptyFormatter } from "../util";
import { toUser } from "./routes/User"; import { toUser } from "./routes/User";
import "./user-section.css"; import "./user-section.css";
import type RealmRepresentation from "@keycloak/keycloak-admin-client/lib/defs/realmRepresentation";
type BruteUser = UserRepresentation & { type BruteUser = UserRepresentation & {
brute?: Record<string, object>; brute?: Record<string, object>;
@ -41,6 +45,8 @@ export const UsersSection = () => {
const history = useHistory(); const history = useHistory();
const { url } = useRouteMatch(); const { url } = useRouteMatch();
const [listUsers, setListUsers] = useState(false); const [listUsers, setListUsers] = useState(false);
const [realm, setRealm] = useState<RealmRepresentation>();
const [kebabOpen, setKebabOpen] = useState(false);
const [selectedRows, setSelectedRows] = useState<UserRepresentation[]>([]); const [selectedRows, setSelectedRows] = useState<UserRepresentation[]>([]);
const [key, setKey] = useState(""); const [key, setKey] = useState("");
@ -52,11 +58,15 @@ export const UsersSection = () => {
type: "org.keycloak.storage.UserStorageProvider", type: "org.keycloak.storage.UserStorageProvider",
}; };
return adminClient.components.find(testParams); return Promise.all([
adminClient.components.find(testParams),
adminClient.realms.findOne({ realm: realmName }),
]);
}, },
(response) => { ([storageProviders, realm]) => {
//should *only* list users when no user federation is configured //should *only* list users when no user federation is configured
setListUsers(!(response.length > 0)); setListUsers(!(storageProviders.length > 0));
setRealm(realm);
refresh(); refresh();
}, },
[] []
@ -88,7 +98,6 @@ export const UsersSection = () => {
try { try {
const users = await adminClient.users.find({ ...params }); const users = await adminClient.users.find({ ...params });
const realm = await adminClient.realms.findOne({ realm: realmName });
if (realm?.bruteForceProtected) { if (realm?.bruteForceProtected) {
const brutes = await Promise.all( const brutes = await Promise.all(
users.map((user: BruteUser) => users.map((user: BruteUser) =>
@ -109,6 +118,21 @@ export const UsersSection = () => {
} }
}; };
const [toggleUnlockUsersDialog, UnlockUsersConfirm] = useConfirmDialog({
titleKey: "users:unlockAllUsers",
messageKey: "users:unlockUsersConfirm",
continueButtonLabel: "users:unlock",
onConfirm: async () => {
try {
await adminClient.attackDetection.delAll();
refresh();
addAlert(t("unlockUsersSuccess"), AlertVariant.success);
} catch (error) {
addError("users:unlockUsersError", error);
}
},
});
const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({ const [toggleDeleteDialog, DeleteConfirm] = useConfirmDialog({
titleKey: "users:deleteConfirm", titleKey: "users:deleteConfirm",
messageKey: t("deleteConfirmDialog", { count: selectedRows.length }), messageKey: t("deleteConfirmDialog", { count: selectedRows.length }),
@ -167,6 +191,7 @@ export const UsersSection = () => {
return ( return (
<> <>
<DeleteConfirm /> <DeleteConfirm />
<UnlockUsersConfirm />
<ViewHeader titleKey="users:title" /> <ViewHeader titleKey="users:title" />
<PageSection <PageSection
data-testid="users-page" data-testid="users-page"
@ -202,14 +227,52 @@ export const UsersSection = () => {
{t("addUser")} {t("addUser")}
</Button> </Button>
</ToolbarItem> </ToolbarItem>
<ToolbarItem> {!realm?.bruteForceProtected && (
<Button <ToolbarItem>
variant={ButtonVariant.plain} <Button
onClick={toggleDeleteDialog} variant={ButtonVariant.plain}
> onClick={toggleDeleteDialog}
{t("deleteUser")} isDisabled={selectedRows.length === 0}
</Button> >
</ToolbarItem> {t("deleteUser")}
</Button>
</ToolbarItem>
)}
{realm?.bruteForceProtected && (
<ToolbarItem>
<Dropdown
toggle={
<KebabToggle onToggle={() => setKebabOpen(!kebabOpen)} />
}
isOpen={kebabOpen}
isPlain
dropdownItems={[
<DropdownItem
key="deleteUser"
component="button"
isDisabled={selectedRows.length === 0}
onClick={() => {
toggleDeleteDialog();
setKebabOpen(false);
}}
>
{t("deleteUser")}
</DropdownItem>,
<DropdownItem
key="unlock"
component="button"
onClick={() => {
toggleUnlockUsersDialog();
setKebabOpen(false);
}}
>
{t("unlockAllUsers")}
</DropdownItem>,
]}
/>
</ToolbarItem>
)}
</> </>
} }
actions={[ actions={[

View file

@ -98,5 +98,11 @@ export default {
"Are you sure you want to revoke all granted client scopes for {{clientId}}?", "Are you sure you want to revoke all granted client scopes for {{clientId}}?",
deleteGrantsSuccess: "Grants successfully revoked.", deleteGrantsSuccess: "Grants successfully revoked.",
deleteGrantsError: "Error deleting grants.", deleteGrantsError: "Error deleting grants.",
unlockAllUsers: "Unlock all users",
unlockUsersConfirm:
"All the users that are temporarily locked will be unlocked.",
unlock: "Unlock",
unlockUsersSuccess: "Any temporarily locked users are now unlocked",
unlockUsersError: "Could not unlock all users {{error}}",
}, },
}; };