diff --git a/web/src/interfaces/AdminInterface.ts b/web/src/interfaces/AdminInterface.ts index fd6e87426..8a25367ae 100644 --- a/web/src/interfaces/AdminInterface.ts +++ b/web/src/interfaces/AdminInterface.ts @@ -73,6 +73,12 @@ export class AdminInterface extends Interface { ${t`Policies`} + + ${t`Reputation policy - IPs`} + + + ${t`Reputation policy - Users`} + ${t`Property Mappings`} diff --git a/web/src/locales/en.po b/web/src/locales/en.po index c0d115e4a..3b6c448e6 100644 --- a/web/src/locales/en.po +++ b/web/src/locales/en.po @@ -985,6 +985,8 @@ msgstr "Define how notifications are sent to users, like Email or Webhook." #: src/pages/outposts/OutpostListPage.ts #: src/pages/outposts/ServiceConnectionListPage.ts #: src/pages/policies/PolicyListPage.ts +#: src/pages/policies/reputation/IPReputationListPage.ts +#: src/pages/policies/reputation/UserReputationListPage.ts #: src/pages/property-mappings/PropertyMappingListPage.ts #: src/pages/providers/ProviderListPage.ts #: src/pages/sources/SourcesListPage.ts @@ -1698,6 +1700,15 @@ msgstr "How many attempts a user has before the flow is canceled. To lock the us msgid "ID" msgstr "ID" +#: src/pages/policies/reputation/IPReputationListPage.ts +msgid "IP" +msgstr "IP" + +#: src/pages/policies/reputation/IPReputationListPage.ts +#: src/pages/policies/reputation/IPReputationListPage.ts +msgid "IP Reputation" +msgstr "IP Reputation" + #: src/pages/applications/ApplicationForm.ts msgid "Icon" msgstr "Icon" @@ -1796,6 +1807,10 @@ msgstr "Invalidation" msgid "Invalidation flow" msgstr "Invalidation flow" +#: src/pages/stages/invitation/InvitationListPage.ts +msgid "Invitation" +msgstr "Invitation" + #: src/interfaces/AdminInterface.ts #: src/pages/stages/invitation/InvitationListPage.ts msgid "Invitations" @@ -2619,7 +2634,6 @@ msgstr "Private key, acquired from https://www.google.com/recaptcha/intro/v3.htm msgid "Profile URL" msgstr "Profile URL" -#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/stages/prompt/PromptListPage.ts msgid "Prompt" msgstr "Prompt" @@ -2815,6 +2829,22 @@ msgstr "Reload" msgid "Remove the user from the current session." msgstr "Remove the user from the current session." +#: src/pages/policies/reputation/IPReputationListPage.ts +msgid "Reputation for IPs. Scores are decreased for each failed login and increased for each successful login." +msgstr "Reputation for IPs. Scores are decreased for each failed login and increased for each successful login." + +#: src/pages/policies/reputation/UserReputationListPage.ts +msgid "Reputation for usernames. Scores are decreased for each failed login and increased for each successful login." +msgstr "Reputation for usernames. Scores are decreased for each failed login and increased for each successful login." + +#: src/interfaces/AdminInterface.ts +msgid "Reputation policy - IPs" +msgstr "Reputation policy - IPs" + +#: src/interfaces/AdminInterface.ts +msgid "Reputation policy - Users" +msgstr "Reputation policy - Users" + #: src/pages/events/EventInfo.ts #: src/pages/events/EventInfo.ts msgid "Request" @@ -2942,6 +2972,11 @@ msgstr "Scope which the client can specify to access these properties." msgid "Scopes" msgstr "Scopes" +#: src/pages/policies/reputation/IPReputationListPage.ts +#: src/pages/policies/reputation/UserReputationListPage.ts +msgid "Score" +msgstr "Score" + #: src/elements/table/TableSearch.ts msgid "Search..." msgstr "Search..." @@ -4075,6 +4110,11 @@ msgstr "User Info" msgid "User Property Mappings" msgstr "User Property Mappings" +#: src/pages/policies/reputation/UserReputationListPage.ts +#: src/pages/policies/reputation/UserReputationListPage.ts +msgid "User Reputation" +msgstr "User Reputation" + #: src/pages/user-settings/UserSettingsPage.ts msgid "User Settings" msgstr "User Settings" @@ -4131,6 +4171,7 @@ msgid "Userinfo URL" msgstr "Userinfo URL" #: src/flows/stages/identification/IdentificationStage.ts +#: src/pages/policies/reputation/UserReputationListPage.ts #: src/pages/stages/identification/IdentificationStageForm.ts #: src/pages/user-settings/UserDetailsPage.ts #: src/pages/users/UserForm.ts diff --git a/web/src/locales/pseudo-LOCALE.po b/web/src/locales/pseudo-LOCALE.po index f57d337d2..b7c4710d6 100644 --- a/web/src/locales/pseudo-LOCALE.po +++ b/web/src/locales/pseudo-LOCALE.po @@ -990,6 +990,8 @@ msgstr "" #: #: #: +#: +#: msgid "Delete" msgstr "" @@ -1690,6 +1692,15 @@ msgstr "" msgid "ID" msgstr "" +#: +msgid "IP" +msgstr "" + +#: +#: +msgid "IP Reputation" +msgstr "" + #: msgid "Icon" msgstr "" @@ -1788,6 +1799,10 @@ msgstr "" msgid "Invalidation flow" msgstr "" +#: +msgid "Invitation" +msgstr "" + #: #: msgid "Invitations" @@ -2611,7 +2626,6 @@ msgstr "" msgid "Profile URL" msgstr "" -#: #: msgid "Prompt" msgstr "" @@ -2807,6 +2821,22 @@ msgstr "" msgid "Remove the user from the current session." msgstr "" +#: +msgid "Reputation for IPs. Scores are decreased for each failed login and increased for each successful login." +msgstr "" + +#: +msgid "Reputation for usernames. Scores are decreased for each failed login and increased for each successful login." +msgstr "" + +#: +msgid "Reputation policy - IPs" +msgstr "" + +#: +msgid "Reputation policy - Users" +msgstr "" + #: #: msgid "Request" @@ -2934,6 +2964,11 @@ msgstr "" msgid "Scopes" msgstr "" +#: +#: +msgid "Score" +msgstr "" + #: msgid "Search..." msgstr "" @@ -4063,6 +4098,11 @@ msgstr "" msgid "User Property Mappings" msgstr "" +#: +#: +msgid "User Reputation" +msgstr "" + #: msgid "User Settings" msgstr "" @@ -4123,6 +4163,7 @@ msgstr "" #: #: #: +#: msgid "Username" msgstr "" diff --git a/web/src/pages/policies/reputation/IPReputationListPage.ts b/web/src/pages/policies/reputation/IPReputationListPage.ts new file mode 100644 index 000000000..b621f225c --- /dev/null +++ b/web/src/pages/policies/reputation/IPReputationListPage.ts @@ -0,0 +1,70 @@ +import { t } from "@lingui/macro"; +import { customElement, html, property, TemplateResult } from "lit-element"; +import { AKResponse } from "../../../api/Client"; +import { TablePage } from "../../../elements/table/TablePage"; + +import "../../../elements/buttons/ModalButton"; +import "../../../elements/buttons/SpinnerButton"; +import "../../../elements/forms/DeleteForm"; +import "../../../elements/forms/ModalForm"; +import { TableColumn } from "../../../elements/table/Table"; +import { PAGE_SIZE } from "../../../constants"; +import { IPReputation, PoliciesApi } from "authentik-api"; +import { DEFAULT_CONFIG } from "../../../api/Config"; + +@customElement("ak-policy-reputation-ip-list") +export class IPReputationListPage extends TablePage { + searchEnabled(): boolean { + return true; + } + pageTitle(): string { + return t`IP Reputation`; + } + pageDescription(): string { + return t`Reputation for IPs. Scores are decreased for each failed login and increased for each successful login.`; + } + pageIcon(): string { + return "fa fa-ban"; + } + + @property() + order = "ip"; + + apiEndpoint(page: number): Promise> { + return new PoliciesApi(DEFAULT_CONFIG).policiesReputationIpsList({ + ordering: this.order, + page: page, + pageSize: PAGE_SIZE, + search: this.search || "", + }); + } + + columns(): TableColumn[] { + return [ + new TableColumn(t`IP`, "ip"), + new TableColumn(t`Score`, "score"), + new TableColumn(""), + ]; + } + + row(item: IPReputation): TemplateResult[] { + return [ + html`${item.ip}`, + html`${item.score}`, + html` + { + return new PoliciesApi(DEFAULT_CONFIG).policiesReputationIpsDestroy({ + id: item.pk, + }); + }}> + + `, + ]; + } + +} diff --git a/web/src/pages/policies/reputation/UserReputationListPage.ts b/web/src/pages/policies/reputation/UserReputationListPage.ts new file mode 100644 index 000000000..5daba84e7 --- /dev/null +++ b/web/src/pages/policies/reputation/UserReputationListPage.ts @@ -0,0 +1,70 @@ +import { t } from "@lingui/macro"; +import { customElement, html, property, TemplateResult } from "lit-element"; +import { AKResponse } from "../../../api/Client"; +import { TablePage } from "../../../elements/table/TablePage"; + +import "../../../elements/buttons/ModalButton"; +import "../../../elements/buttons/SpinnerButton"; +import "../../../elements/forms/DeleteForm"; +import "../../../elements/forms/ModalForm"; +import { TableColumn } from "../../../elements/table/Table"; +import { PAGE_SIZE } from "../../../constants"; +import { UserReputation, PoliciesApi } from "authentik-api"; +import { DEFAULT_CONFIG } from "../../../api/Config"; + +@customElement("ak-policy-reputation-user-list") +export class UserReputationListPage extends TablePage { + searchEnabled(): boolean { + return true; + } + pageTitle(): string { + return t`User Reputation`; + } + pageDescription(): string { + return t`Reputation for usernames. Scores are decreased for each failed login and increased for each successful login.`; + } + pageIcon(): string { + return "fa fa-ban"; + } + + @property() + order = "username"; + + apiEndpoint(page: number): Promise> { + return new PoliciesApi(DEFAULT_CONFIG).policiesReputationUsersList({ + ordering: this.order, + page: page, + pageSize: PAGE_SIZE, + search: this.search || "", + }); + } + + columns(): TableColumn[] { + return [ + new TableColumn(t`Username`, "username"), + new TableColumn(t`Score`, "score"), + new TableColumn(""), + ]; + } + + row(item: UserReputation): TemplateResult[] { + return [ + html`${item.username}`, + html`${item.score}`, + html` + { + return new PoliciesApi(DEFAULT_CONFIG).policiesReputationUsersDestroy({ + id: item.pk, + }); + }}> + + `, + ]; + } + +} diff --git a/web/src/pages/stages/invitation/InvitationListPage.ts b/web/src/pages/stages/invitation/InvitationListPage.ts index 788f03474..f30a1f9c3 100644 --- a/web/src/pages/stages/invitation/InvitationListPage.ts +++ b/web/src/pages/stages/invitation/InvitationListPage.ts @@ -57,7 +57,7 @@ export class InvitationListPage extends TablePage { html` { return new StagesApi(DEFAULT_CONFIG).stagesInvitationInvitationsDestroy({ inviteUuid: item.pk || "" diff --git a/web/src/pages/tenants/TenantForm.ts b/web/src/pages/tenants/TenantForm.ts index a6a094b1d..89976fae2 100644 --- a/web/src/pages/tenants/TenantForm.ts +++ b/web/src/pages/tenants/TenantForm.ts @@ -4,6 +4,7 @@ import { customElement } from "lit-element"; import { html, TemplateResult } from "lit-html"; import { DEFAULT_CONFIG } from "../../api/Config"; import "../../elements/forms/HorizontalFormElement"; +import "../../elements/forms/FormGroup"; import { first } from "../../utils"; import { ModelForm } from "../../elements/forms/ModelForm"; import { until } from "lit-html/directives/until"; diff --git a/web/src/routes.ts b/web/src/routes.ts index e159c6d47..e4cffc393 100644 --- a/web/src/routes.ts +++ b/web/src/routes.ts @@ -16,6 +16,8 @@ import "./pages/LibraryPage"; import "./pages/outposts/OutpostListPage"; import "./pages/outposts/ServiceConnectionListPage"; import "./pages/policies/PolicyListPage"; +import "./pages/policies/reputation/IPReputationListPage"; +import "./pages/policies/reputation/UserReputationListPage"; import "./pages/property-mappings/PropertyMappingListPage"; import "./pages/providers/ProviderListPage"; import "./pages/providers/ProviderViewPage"; @@ -54,6 +56,8 @@ export const ROUTES: Route[] = [ new Route(new RegExp("^/core/tokens$"), html``), new Route(new RegExp("^/core/tenants$"), html``), new Route(new RegExp("^/policy/policies$"), html``), + new Route(new RegExp("^/policy/reputation/ip$"), html``), + new Route(new RegExp("^/policy/reputation/user$"), html``), new Route(new RegExp("^/identity/groups$"), html``), new Route(new RegExp("^/identity/users$"), html``), new Route(new RegExp(`^/identity/users/(?${ID_REGEX})$`)).then((args) => { diff --git a/website/docs/releases/next.md b/website/docs/releases/next.md index c8d49c274..40d23dc25 100644 --- a/website/docs/releases/next.md +++ b/website/docs/releases/next.md @@ -25,6 +25,7 @@ title: Next ## Minor changes - You can now specify which sources should be shown on an Identification stage. +- Add UI for the reputation of IPs and usernames for reputation policies. ## Upgrading