added remove all temporary locks (#1082)
This commit is contained in:
parent
2416d25c38
commit
e5e07eb1bc
2 changed files with 81 additions and 12 deletions
|
@ -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>
|
||||||
|
{!realm?.bruteForceProtected && (
|
||||||
<ToolbarItem>
|
<ToolbarItem>
|
||||||
<Button
|
<Button
|
||||||
variant={ButtonVariant.plain}
|
variant={ButtonVariant.plain}
|
||||||
onClick={toggleDeleteDialog}
|
onClick={toggleDeleteDialog}
|
||||||
|
isDisabled={selectedRows.length === 0}
|
||||||
>
|
>
|
||||||
{t("deleteUser")}
|
{t("deleteUser")}
|
||||||
</Button>
|
</Button>
|
||||||
</ToolbarItem>
|
</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={[
|
||||||
|
|
|
@ -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}}",
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue