core: add flag to globally disable impersonation

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2022-04-17 16:52:55 +02:00
parent 70794d79dd
commit 778065f468
8 changed files with 66 additions and 21 deletions

View file

@ -27,6 +27,7 @@ class Capabilities(models.TextChoices):
CAN_SAVE_MEDIA = "can_save_media" CAN_SAVE_MEDIA = "can_save_media"
CAN_GEO_IP = "can_geo_ip" CAN_GEO_IP = "can_geo_ip"
CAN_IMPERSONATE = "can_impersonate"
class ErrorReportingConfigSerializer(PassiveSerializer): class ErrorReportingConfigSerializer(PassiveSerializer):
@ -63,6 +64,8 @@ class ConfigView(APIView):
caps.append(Capabilities.CAN_SAVE_MEDIA) caps.append(Capabilities.CAN_SAVE_MEDIA)
if GEOIP_READER.enabled: if GEOIP_READER.enabled:
caps.append(Capabilities.CAN_GEO_IP) caps.append(Capabilities.CAN_GEO_IP)
if CONFIG.y_bool("impersonation"):
caps.append(Capabilities.CAN_IMPERSONATE)
return caps return caps
@extend_schema(responses={200: ConfigSerializer(many=False)}) @extend_schema(responses={200: ConfigSerializer(many=False)})

View file

@ -4,7 +4,7 @@ from django.http import HttpRequest, HttpResponse
from django.shortcuts import get_object_or_404, redirect from django.shortcuts import get_object_or_404, redirect
from django.views import View from django.views import View
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from authentik.lib.config import CONFIG
from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER from authentik.core.middleware import SESSION_IMPERSONATE_ORIGINAL_USER, SESSION_IMPERSONATE_USER
from authentik.core.models import User from authentik.core.models import User
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
@ -17,6 +17,9 @@ class ImpersonateInitView(View):
def get(self, request: HttpRequest, user_id: int) -> HttpResponse: def get(self, request: HttpRequest, user_id: int) -> HttpResponse:
"""Impersonation handler, checks permissions""" """Impersonation handler, checks permissions"""
if not CONFIG.y_bool("impersonation"):
LOGGER.debug("User attempted to impersonate", user=request.user)
return HttpResponse("Unauthorized", status=401)
if not request.user.has_perm("impersonate"): if not request.user.has_perm("impersonate"):
LOGGER.debug("User attempted to impersonate without permissions", user=request.user) LOGGER.debug("User attempted to impersonate without permissions", user=request.user)
return HttpResponse("Unauthorized", status=401) return HttpResponse("Unauthorized", status=401)

View file

@ -72,3 +72,4 @@ default_user_change_username: true
gdpr_compliance: true gdpr_compliance: true
cert_discovery_dir: /certs cert_discovery_dir: /certs
default_token_length: 128 default_token_length: 128
impersonation: true

View file

@ -20087,6 +20087,7 @@ components:
enum: enum:
- can_save_media - can_save_media
- can_geo_ip - can_geo_ip
- can_impersonate
type: string type: string
CaptchaChallenge: CaptchaChallenge:
type: object type: object

View file

@ -7,10 +7,10 @@ import { until } from "lit/directives/until.js";
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import { CoreApi, User } from "@goauthentik/api"; import { CapabilitiesEnum, CoreApi, User } from "@goauthentik/api";
import { AKResponse } from "../../api/Client"; import { AKResponse } from "../../api/Client";
import { DEFAULT_CONFIG, tenant } from "../../api/Config"; import { DEFAULT_CONFIG, config, tenant } from "../../api/Config";
import { me } from "../../api/Users"; import { me } from "../../api/Users";
import { uiConfig } from "../../common/config"; import { uiConfig } from "../../common/config";
import { PFColor } from "../../elements/Label"; import { PFColor } from "../../elements/Label";
@ -143,9 +143,19 @@ export class RelatedUserList extends Table<User> {
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</button> </button>
</ak-forms-modal> </ak-forms-modal>
<a class="pf-c-button pf-m-tertiary" href="${`/-/impersonation/${item.pk}/`}"> ${until(
${t`Impersonate`} config().then((config) => {
</a>`, if (config.capabilities.includes(CapabilitiesEnum.Impersonate)) {
return html`<a
class="pf-c-button pf-m-tertiary"
href="${`/-/impersonation/${item.pk}/`}"
>
${t`Impersonate`}
</a>`;
}
return html``;
}),
)}`,
]; ];
} }

View file

@ -7,10 +7,10 @@ import { until } from "lit/directives/until.js";
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css"; import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css"; import PFDescriptionList from "@patternfly/patternfly/components/DescriptionList/description-list.css";
import { CoreApi, User } from "@goauthentik/api"; import { CapabilitiesEnum, CoreApi, User } from "@goauthentik/api";
import { AKResponse } from "../../api/Client"; import { AKResponse } from "../../api/Client";
import { DEFAULT_CONFIG, tenant } from "../../api/Config"; import { DEFAULT_CONFIG, config, tenant } from "../../api/Config";
import { me } from "../../api/Users"; import { me } from "../../api/Users";
import { uiConfig } from "../../common/config"; import { uiConfig } from "../../common/config";
import { PFColor } from "../../elements/Label"; import { PFColor } from "../../elements/Label";
@ -149,9 +149,19 @@ export class UserListPage extends TablePage<User> {
<i class="fas fa-edit"></i> <i class="fas fa-edit"></i>
</button> </button>
</ak-forms-modal> </ak-forms-modal>
<a class="pf-c-button pf-m-tertiary" href="${`/-/impersonation/${item.pk}/`}"> ${until(
${t`Impersonate`} config().then((config) => {
</a>`, if (config.capabilities.includes(CapabilitiesEnum.Impersonate)) {
return html`<a
class="pf-c-button pf-m-tertiary"
href="${`/-/impersonation/${item.pk}/`}"
>
${t`Impersonate`}
</a>`;
}
return html``;
}),
)}`,
]; ];
} }

View file

@ -2,6 +2,7 @@ import { t } from "@lingui/macro";
import { CSSResult, LitElement, TemplateResult, html } from "lit"; import { CSSResult, LitElement, TemplateResult, html } from "lit";
import { customElement, property } from "lit/decorators.js"; import { customElement, property } from "lit/decorators.js";
import { until } from "lit/directives/until.js";
import AKGlobal from "../../authentik.css"; import AKGlobal from "../../authentik.css";
import PFButton from "@patternfly/patternfly/components/Button/button.css"; import PFButton from "@patternfly/patternfly/components/Button/button.css";
@ -15,9 +16,9 @@ import PFDisplay from "@patternfly/patternfly/utilities/Display/display.css";
import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css"; import PFFlex from "@patternfly/patternfly/utilities/Flex/flex.css";
import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css"; import PFSizing from "@patternfly/patternfly/utilities/Sizing/sizing.css";
import { CoreApi, User } from "@goauthentik/api"; import { CapabilitiesEnum, CoreApi, User } from "@goauthentik/api";
import { DEFAULT_CONFIG } from "../../api/Config"; import { DEFAULT_CONFIG, config } from "../../api/Config";
import { EVENT_REFRESH } from "../../constants"; import { EVENT_REFRESH } from "../../constants";
import "../../elements/CodeMirror"; import "../../elements/CodeMirror";
import { PFColor } from "../../elements/Label"; import { PFColor } from "../../elements/Label";
@ -239,14 +240,22 @@ export class UserViewPage extends LitElement {
${t`Reset Password`} ${t`Reset Password`}
</ak-action-button> </ak-action-button>
</div> </div>
<div class="pf-c-card__footer">
<a ${until(
class="pf-c-button pf-m-tertiary" config().then((config) => {
href="${`/-/impersonation/${this.user.pk}/`}" if (config.capabilities.includes(CapabilitiesEnum.Impersonate)) {
> return html` <div class="pf-c-card__footer">
${t`Impersonate`} <a
</a> class="pf-c-button pf-m-tertiary"
</div> href="${`/-/impersonation/${this.user?.pk}/`}"
>
${t`Impersonate`}
</a>
</div>`;
}
return html``;
}),
)}
</div> </div>
<div <div
class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-9-col-on-xl pf-m-9-col-on-2xl" class="pf-c-card pf-l-grid__item pf-m-12-col pf-m-9-col-on-xl pf-m-9-col-on-2xl"

View file

@ -188,6 +188,14 @@ Requires authentik 2022.4.1
Configure the length of generated tokens. Defaults to 128. Configure the length of generated tokens. Defaults to 128.
### AUTHENTIK_IMPERSONATION
:::info
Requires authentik 2022.4.2
:::
Globally enable/disable impersonation. Defaults to `true`.
### AUTHENTIK_FOOTER_LINKS ### AUTHENTIK_FOOTER_LINKS
:::info :::info