core: fix tokens not being viewable but superusers

Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
Jens Langhammer 2021-09-19 16:08:30 +02:00
parent 3f42067a8f
commit f6e0f0282d
20 changed files with 97 additions and 29 deletions

View File

@ -33,3 +33,12 @@ class OwnerPermissions(BasePermission):
if owner != request.user: if owner != request.user:
return False return False
return True return True
class OwnerSuperuserPermissions(OwnerPermissions):
"""Similar to OwnerPermissions, except always allow access for superusers"""
def has_object_permission(self, request: Request, view, obj: Model) -> bool:
if request.user.is_superuser:
return True
return super().has_object_permission(request, view, obj)

View File

@ -5,6 +5,9 @@ from typing import Callable, Optional
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from structlog.stdlib import get_logger
LOGGER = get_logger()
def permission_required(perm: Optional[str] = None, other_perms: Optional[list[str]] = None): def permission_required(perm: Optional[str] = None, other_perms: Optional[list[str]] = None):
@ -18,10 +21,12 @@ def permission_required(perm: Optional[str] = None, other_perms: Optional[list[s
if perm: if perm:
obj = self.get_object() obj = self.get_object()
if not request.user.has_perm(perm, obj): if not request.user.has_perm(perm, obj):
LOGGER.debug("denying access for object", user=request.user, perm=perm, obj=obj)
return self.permission_denied(request) return self.permission_denied(request)
if other_perms: if other_perms:
for other_perm in other_perms: for other_perm in other_perms:
if not request.user.has_perm(other_perm): if not request.user.has_perm(other_perm):
LOGGER.debug("denying access for other", user=request.user, perm=perm)
return self.permission_denied(request) return self.permission_denied(request)
return func(self, request, *args, **kwargs) return func(self, request, *args, **kwargs)

View File

@ -11,7 +11,7 @@ from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import GenericViewSet from rest_framework.viewsets import GenericViewSet
from ua_parser import user_agent_parser from ua_parser import user_agent_parser
from authentik.api.authorization import OwnerPermissions from authentik.api.authorization import OwnerSuperuserPermissions
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.models import AuthenticatedSession from authentik.core.models import AuthenticatedSession
from authentik.events.geo import GEOIP_READER, GeoIPDict from authentik.events.geo import GEOIP_READER, GeoIPDict
@ -103,7 +103,7 @@ class AuthenticatedSessionViewSet(
search_fields = ["user__username", "last_ip", "last_user_agent"] search_fields = ["user__username", "last_ip", "last_user_agent"]
filterset_fields = ["user__username", "last_ip", "last_user_agent"] filterset_fields = ["user__username", "last_ip", "last_user_agent"]
ordering = ["user__username"] ordering = ["user__username"]
permission_classes = [OwnerPermissions] permission_classes = [OwnerSuperuserPermissions]
filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter] filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter]
def get_queryset(self): def get_queryset(self):

View File

@ -14,7 +14,7 @@ from rest_framework.response import Response
from rest_framework.serializers import ModelSerializer from rest_framework.serializers import ModelSerializer
from rest_framework.viewsets import ModelViewSet from rest_framework.viewsets import ModelViewSet
from authentik.api.authorization import OwnerPermissions from authentik.api.authorization import OwnerSuperuserPermissions
from authentik.api.decorators import permission_required from authentik.api.decorators import permission_required
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.users import UserSerializer from authentik.core.api.users import UserSerializer
@ -84,7 +84,7 @@ class TokenViewSet(UsedByMixin, ModelViewSet):
"expiring", "expiring",
] ]
ordering = ["identifier", "expires"] ordering = ["identifier", "expires"]
permission_classes = [OwnerPermissions] permission_classes = [OwnerSuperuserPermissions]
filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter] filter_backends = [DjangoFilterBackend, OrderingFilter, SearchFilter]
def get_queryset(self): def get_queryset(self):

View File

@ -1,6 +1,6 @@
import { customElement, property } from "lit-element"; import { customElement, property } from "lit-element";
import { CoreApi } from "@goauthentik/api"; import { CoreApi } from "@goauthentik/api";
import { SECONDARY_CLASS, SUCCESS_CLASS } from "../../constants"; import { ERROR_CLASS, SECONDARY_CLASS, SUCCESS_CLASS } from "../../constants";
import { DEFAULT_CONFIG } from "../../api/Config"; import { DEFAULT_CONFIG } from "../../api/Config";
import { ActionButton } from "./ActionButton"; import { ActionButton } from "./ActionButton";
@ -33,8 +33,12 @@ export class TokenCopyButton extends ActionButton {
}); });
}) })
.catch((err: Response | undefined) => { .catch((err: Response | undefined) => {
this.buttonClass = ERROR_CLASS;
return err?.json().then((errResp) => { return err?.json().then((errResp) => {
throw new Error(errResp["detail"]); throw new Error(errResp["detail"]);
setTimeout(() => {
this.buttonClass = SECONDARY_CLASS;
}, 1500);
}); });
}); });
}; };

View File

@ -58,7 +58,7 @@ export class ObjectChangelog extends Table<Event> {
? html`<small> ${t`On behalf of ${item.user.on_behalf_of.username}`} </small>` ? html`<small> ${t`On behalf of ${item.user.on_behalf_of.username}`} </small>`
: html``}`, : html``}`,
html`<span>${item.created?.toLocaleString()}</span>`, html`<span>${item.created?.toLocaleString()}</span>`,
html`<span>${item.clientIp || "-"}</span>`, html`<span>${item.clientIp || t`-`}</span>`,
]; ];
} }

View File

@ -49,7 +49,7 @@ export class ObjectChangelog extends Table<Event> {
? html`<small> ${t`On behalf of ${item.user.on_behalf_of.username}`} </small>` ? html`<small> ${t`On behalf of ${item.user.on_behalf_of.username}`} </small>`
: html``}`, : html``}`,
html`<span>${item.created?.toLocaleString()}</span>`, html`<span>${item.created?.toLocaleString()}</span>`,
html`<span>${item.clientIp || "-"}</span>`, html`<span>${item.clientIp || t`-`}</span>`,
]; ];
} }

View File

@ -39,6 +39,12 @@ export class AuthenticatedSessionList extends Table<AuthenticatedSession> {
return html`<ak-forms-delete-bulk return html`<ak-forms-delete-bulk
objectLabel=${t`Session(s)`} objectLabel=${t`Session(s)`}
.objects=${this.selectedElements} .objects=${this.selectedElements}
.metadata=${(item: AuthenticatedSession) => {
return [
{ key: t`Last IP`, value: item.lastIp },
{ key: t`Expiry`, value: item.expires?.toLocaleString() || t`-` },
];
}}
.usedBy=${(item: AuthenticatedSession) => { .usedBy=${(item: AuthenticatedSession) => {
return new CoreApi(DEFAULT_CONFIG).coreAuthenticatedSessionsUsedByList({ return new CoreApi(DEFAULT_CONFIG).coreAuthenticatedSessionsUsedByList({
uuid: item.uuid || "", uuid: item.uuid || "",

View File

@ -21,7 +21,26 @@ msgstr ""
msgid "(Format: hours=-1;minutes=-2;seconds=-3)." msgid "(Format: hours=-1;minutes=-2;seconds=-3)."
msgstr "(Format: hours=-1;minutes=-2;seconds=-3)." msgstr "(Format: hours=-1;minutes=-2;seconds=-3)."
#: src/elements/events/ObjectChangelog.ts
#: src/elements/events/UserEvents.ts
#: src/elements/user/SessionList.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/events/EventListPage.ts
#: src/pages/events/EventListPage.ts
#: src/pages/groups/GroupListPage.ts
#: src/pages/groups/MemberSelectModal.ts
#: src/pages/policies/BoundPoliciesList.ts #: src/pages/policies/BoundPoliciesList.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/tokens/TokenListPage.ts
#: src/pages/users/UserListPage.ts
#: src/user/user-settings/stages/UserSettingsAuthenticatorWebAuthn.ts
#: src/user/user-settings/tokens/UserTokenList.ts
msgid "-" msgid "-"
msgstr "-" msgstr "-"
@ -267,6 +286,7 @@ msgid "Application"
msgstr "Application" msgstr "Application"
#: src/pages/applications/ApplicationListPage.ts #: src/pages/applications/ApplicationListPage.ts
#: src/user/LibraryApplication.ts
msgid "Application Icon" msgid "Application Icon"
msgstr "Application Icon" msgstr "Application Icon"
@ -1645,6 +1665,7 @@ msgstr "Expiring"
msgid "Expiring?" msgid "Expiring?"
msgstr "Expiring?" msgstr "Expiring?"
#: src/elements/user/SessionList.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts #: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/stages/invitation/InvitationListPage.ts
msgid "Expiry" msgid "Expiry"
@ -2262,6 +2283,7 @@ msgstr "Label"
msgid "Label shown next to/above the prompt." msgid "Label shown next to/above the prompt."
msgstr "Label shown next to/above the prompt." msgstr "Label shown next to/above the prompt."
#: src/elements/user/SessionList.ts
#: src/elements/user/SessionList.ts #: src/elements/user/SessionList.ts
msgid "Last IP" msgid "Last IP"
msgstr "Last IP" msgstr "Last IP"
@ -3464,9 +3486,9 @@ msgstr "Resources"
msgid "Result" msgid "Result"
msgstr "Result" msgstr "Result"
#: src/pages/system-tasks/SystemTaskListPage.ts #:
msgid "Retry Task" #~ msgid "Retry Task"
msgstr "Retry Task" #~ msgstr "Retry Task"
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts #: src/flows/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts
msgid "Retry authentication" msgid "Retry authentication"

View File

@ -21,7 +21,26 @@ msgstr ""
msgid "(Format: hours=-1;minutes=-2;seconds=-3)." msgid "(Format: hours=-1;minutes=-2;seconds=-3)."
msgstr "" msgstr ""
#: src/elements/events/ObjectChangelog.ts
#: src/elements/events/UserEvents.ts
#: src/elements/user/SessionList.ts
#: src/pages/applications/ApplicationListPage.ts
#: src/pages/events/EventListPage.ts
#: src/pages/events/EventListPage.ts
#: src/pages/groups/GroupListPage.ts
#: src/pages/groups/MemberSelectModal.ts
#: src/pages/policies/BoundPoliciesList.ts #: src/pages/policies/BoundPoliciesList.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/providers/oauth2/OAuth2ProviderViewPage.ts
#: src/pages/stages/invitation/InvitationListPage.ts
#: src/pages/tokens/TokenListPage.ts
#: src/pages/users/UserListPage.ts
#: src/user/user-settings/stages/UserSettingsAuthenticatorWebAuthn.ts
#: src/user/user-settings/tokens/UserTokenList.ts
msgid "-" msgid "-"
msgstr "" msgstr ""
@ -267,6 +286,7 @@ msgid "Application"
msgstr "" msgstr ""
#: src/pages/applications/ApplicationListPage.ts #: src/pages/applications/ApplicationListPage.ts
#: src/user/LibraryApplication.ts
msgid "Application Icon" msgid "Application Icon"
msgstr "" msgstr ""
@ -1637,6 +1657,7 @@ msgstr ""
msgid "Expiring?" msgid "Expiring?"
msgstr "" msgstr ""
#: src/elements/user/SessionList.ts
#: src/pages/crypto/CertificateKeyPairListPage.ts #: src/pages/crypto/CertificateKeyPairListPage.ts
#: src/pages/stages/invitation/InvitationListPage.ts #: src/pages/stages/invitation/InvitationListPage.ts
msgid "Expiry" msgid "Expiry"
@ -2254,6 +2275,7 @@ msgstr ""
msgid "Label shown next to/above the prompt." msgid "Label shown next to/above the prompt."
msgstr "" msgstr ""
#: src/elements/user/SessionList.ts
#: src/elements/user/SessionList.ts #: src/elements/user/SessionList.ts
msgid "Last IP" msgid "Last IP"
msgstr "" msgstr ""
@ -3456,9 +3478,9 @@ msgstr ""
msgid "Result" msgid "Result"
msgstr "" msgstr ""
#: src/pages/system-tasks/SystemTaskListPage.ts #:
msgid "Retry Task" #~ msgid "Retry Task"
msgstr "" #~ msgstr ""
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts #: src/flows/stages/authenticator_validate/AuthenticatorValidateStageWebAuthn.ts
msgid "Retry authentication" msgid "Retry authentication"

View File

@ -109,7 +109,7 @@ export class ApplicationListPage extends TablePage<Application> {
${item.providerObj?.name} ${item.providerObj?.name}
</a>` </a>`
: html`-`, : html`-`,
html`${item.providerObj?.verboseName || "-"}`, html`${item.providerObj?.verboseName || t`-`}`,
html` <ak-forms-modal> html` <ak-forms-modal>
<span slot="submit"> ${t`Update`} </span> <span slot="submit"> ${t`Update`} </span>
<span slot="header"> ${t`Update Application`} </span> <span slot="header"> ${t`Update Application`} </span>

View File

@ -63,8 +63,8 @@ export class EventListPage extends TablePage<Event> {
: html``}` : html``}`
: html`-`, : html`-`,
html`<span>${item.created?.toLocaleString()}</span>`, html`<span>${item.created?.toLocaleString()}</span>`,
html`<span>${item.clientIp || "-"}</span>`, html`<span>${item.clientIp || t`-`}</span>`,
html`<span>${item.tenant?.name || "-"}</span>`, html`<span>${item.tenant?.name || t`-`}</span>`,
html`<a href="#/events/log/${item.pk}"> html`<a href="#/events/log/${item.pk}">
<i class="fas fas fa-share-square"></i> <i class="fas fas fa-share-square"></i>
</a>`, </a>`,

View File

@ -75,7 +75,7 @@ export class GroupListPage extends TablePage<Group> {
row(item: Group): TemplateResult[] { row(item: Group): TemplateResult[] {
return [ return [
html`${item.name}`, html`${item.name}`,
html`${item.parent || "-"}`, html`${item.parent || t`-`}`,
html`${Array.from(item.users || []).length}`, html`${Array.from(item.users || []).length}`,
html`${item.isSuperuser ? t`Yes` : t`No`}`, html`${item.isSuperuser ? t`Yes` : t`No`}`,
html` <ak-forms-modal> html` <ak-forms-modal>

View File

@ -48,7 +48,7 @@ export class MemberSelectTable extends TableModal<User> {
<small>${item.name}</small> <small>${item.name}</small>
</div>`, </div>`,
html`${item.isActive ? t`Yes` : t`No`}`, html`${item.isActive ? t`Yes` : t`No`}`,
html`${first(item.lastLogin?.toLocaleString(), "-")}`, html`${first(item.lastLogin?.toLocaleString(), t`-`)}`,
]; ];
} }

View File

@ -211,7 +211,7 @@ export class OAuth2ProviderViewPage extends LitElement {
class="pf-c-form-control" class="pf-c-form-control"
readonly readonly
type="text" type="text"
value="${this.providerUrls?.providerInfo || "-"}" value="${this.providerUrls?.providerInfo || t`-`}"
/> />
</div> </div>
<div class="pf-c-form__group"> <div class="pf-c-form__group">
@ -227,7 +227,7 @@ export class OAuth2ProviderViewPage extends LitElement {
class="pf-c-form-control" class="pf-c-form-control"
readonly readonly
type="text" type="text"
value="${this.providerUrls?.issuer || "-"}" value="${this.providerUrls?.issuer || t`-`}"
/> />
</div> </div>
<hr /> <hr />
@ -244,7 +244,7 @@ export class OAuth2ProviderViewPage extends LitElement {
class="pf-c-form-control" class="pf-c-form-control"
readonly readonly
type="text" type="text"
value="${this.providerUrls?.authorize || "-"}" value="${this.providerUrls?.authorize || t`-`}"
/> />
</div> </div>
<div class="pf-c-form__group"> <div class="pf-c-form__group">
@ -260,7 +260,7 @@ export class OAuth2ProviderViewPage extends LitElement {
class="pf-c-form-control" class="pf-c-form-control"
readonly readonly
type="text" type="text"
value="${this.providerUrls?.token || "-"}" value="${this.providerUrls?.token || t`-`}"
/> />
</div> </div>
<div class="pf-c-form__group"> <div class="pf-c-form__group">
@ -276,7 +276,7 @@ export class OAuth2ProviderViewPage extends LitElement {
class="pf-c-form-control" class="pf-c-form-control"
readonly readonly
type="text" type="text"
value="${this.providerUrls?.userInfo || "-"}" value="${this.providerUrls?.userInfo || t`-`}"
/> />
</div> </div>
<div class="pf-c-form__group"> <div class="pf-c-form__group">
@ -292,7 +292,7 @@ export class OAuth2ProviderViewPage extends LitElement {
class="pf-c-form-control" class="pf-c-form-control"
readonly readonly
type="text" type="text"
value="${this.providerUrls?.logout || "-"}" value="${this.providerUrls?.logout || t`-`}"
/> />
</div> </div>
</form> </form>

View File

@ -79,7 +79,7 @@ export class InvitationListPage extends TablePage<Invitation> {
return [ return [
html`${item.pk}`, html`${item.pk}`,
html`${item.createdBy?.username}`, html`${item.createdBy?.username}`,
html`${item.expires?.toLocaleString() || "-"}`, html`${item.expires?.toLocaleString() || t`-`}`,
]; ];
} }

View File

@ -105,7 +105,7 @@ export class TokenListPage extends TablePage<Token> {
html`${item.identifier}`, html`${item.identifier}`,
html`<a href="#/identity/users/${item.userObj?.pk}">${item.userObj?.username}</a>`, html`<a href="#/identity/users/${item.userObj?.pk}">${item.userObj?.username}</a>`,
html`${item.expiring ? t`Yes` : t`No`}`, html`${item.expiring ? t`Yes` : t`No`}`,
html`${item.expiring ? item.expires?.toLocaleString() : "-"}`, html`${item.expiring ? item.expires?.toLocaleString() : t`-`}`,
html`${IntentToLabel(item.intent || IntentEnum.Api)}`, html`${IntentToLabel(item.intent || IntentEnum.Api)}`,
html` html`
<ak-forms-modal> <ak-forms-modal>

View File

@ -106,7 +106,7 @@ export class UserListPage extends TablePage<User> {
<small>${item.name}</small> <small>${item.name}</small>
</a>`, </a>`,
html`${item.isActive ? t`Yes` : t`No`}`, html`${item.isActive ? t`Yes` : t`No`}`,
html`${first(item.lastLogin?.toLocaleString(), "-")}`, html`${first(item.lastLogin?.toLocaleString(), t`-`)}`,
html` <ak-forms-modal> html` <ak-forms-modal>
<span slot="submit"> ${t`Update`} </span> <span slot="submit"> ${t`Update`} </span>
<span slot="header"> ${t`Update User`} </span> <span slot="header"> ${t`Update User`} </span>

View File

@ -94,7 +94,7 @@ export class UserSettingsAuthenticatorWebAuthn extends BaseUserSettings {
<div class="pf-c-data-list__item-row"> <div class="pf-c-data-list__item-row">
<div class="pf-c-data-list__item-content"> <div class="pf-c-data-list__item-content">
<div class="pf-c-data-list__cell"> <div class="pf-c-data-list__cell">
${device.name || "-"} ${device.name || t`-`}
</div> </div>
<div class="pf-c-data-list__cell"> <div class="pf-c-data-list__cell">
${t`Created ${device.createdOn?.toLocaleString()}`} ${t`Created ${device.createdOn?.toLocaleString()}`}

View File

@ -97,7 +97,7 @@ export class UserTokenList extends Table<Token> {
</dt> </dt>
<dd class="pf-c-description-list__description"> <dd class="pf-c-description-list__description">
<div class="pf-c-description-list__text"> <div class="pf-c-description-list__text">
${item.expiring ? item.expires?.toLocaleString() : "-"} ${item.expiring ? item.expires?.toLocaleString() : t`-`}
</div> </div>
</dd> </dd>
</div> </div>