diff --git a/package.json b/package.json index 9f7d363faa..48a31cf9ec 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,7 @@ "@patternfly/react-table": "4.19.24", "file-saver": "^2.0.2", "i18next": "^19.6.2", - "keycloak-admin": "1.14.2", + "keycloak-admin": "1.14.4", "lodash": "^4.17.20", "moment": "^2.29.1", "react": "^16.8.5", diff --git a/src/user/UsersSection.tsx b/src/user/UsersSection.tsx index 2584cddc0d..f35f534553 100644 --- a/src/user/UsersSection.tsx +++ b/src/user/UsersSection.tsx @@ -1,4 +1,4 @@ -import React, { useState } from "react"; +import React, { useContext, useState } from "react"; import { useTranslation } from "react-i18next"; import { AlertVariant, @@ -8,18 +8,25 @@ import { PageSection, ToolbarItem, } from "@patternfly/react-core"; -import { InfoCircleIcon } from "@patternfly/react-icons"; +import { InfoCircleIcon, WarningTriangleIcon } from "@patternfly/react-icons"; import UserRepresentation from "keycloak-admin/lib/defs/userRepresentation"; import { useAdminClient } from "../context/auth/AdminClient"; import { ViewHeader } from "../components/view-header/ViewHeader"; import { KeycloakDataTable } from "../components/table-toolbar/KeycloakDataTable"; import { useAlerts } from "../components/alert/Alerts"; +import { RealmContext } from "../context/realm-context/RealmContext"; + +type BruteUser = UserRepresentation & { + brute?: Record; +}; export const UsersSection = () => { const { t } = useTranslation("users"); const adminClient = useAdminClient(); const { addAlert } = useAlerts(); + const { realm: realmName } = useContext(RealmContext); + const [key, setKey] = useState(""); const refresh = () => setKey(`${new Date().getTime()}`); @@ -31,7 +38,24 @@ export const UsersSection = () => { if (search) { params.search = search; } - return await adminClient.users.find({ ...params }); + + const users = await adminClient.users.find({ ...params }); + const realm = await adminClient.realms.findOne({ realm: realmName }); + if (realm?.bruteForceProtected) { + const brutes = await Promise.all( + users.map((user: BruteUser) => + adminClient.attackDetection.findOne({ + id: user.id!, + }) + ) + ); + for (let index = 0; index < users.length; index++) { + const user: BruteUser = users[index]; + user.brute = brutes[index]; + } + } + + return users; }; const deleteUser = async (user: UserRepresentation) => { @@ -44,14 +68,19 @@ export const UsersSection = () => { } }; - const StatusRow = (user: UserRepresentation) => { + const StatusRow = (user: BruteUser) => { return ( <> {!user.enabled && ( -