providers/oauth2: show id_token issues for refresh token
Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
4d773274d4
commit
cec47c3cfc
|
@ -1,8 +1,11 @@
|
||||||
"""OAuth2Provider API Views"""
|
"""OAuth2Provider API Views"""
|
||||||
|
from dataclasses import asdict
|
||||||
|
from json import dumps
|
||||||
|
|
||||||
from django_filters.rest_framework import DjangoFilterBackend
|
from django_filters.rest_framework import DjangoFilterBackend
|
||||||
from guardian.utils import get_anonymous_user
|
from guardian.utils import get_anonymous_user
|
||||||
from rest_framework import mixins
|
from rest_framework import mixins
|
||||||
from rest_framework.fields import CharField, ListField
|
from rest_framework.fields import CharField, ListField, SerializerMethodField
|
||||||
from rest_framework.filters import OrderingFilter, SearchFilter
|
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
from rest_framework.viewsets import GenericViewSet
|
from rest_framework.viewsets import GenericViewSet
|
||||||
|
@ -27,6 +30,30 @@ class ExpiringBaseGrantModelSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
depth = 2
|
depth = 2
|
||||||
|
|
||||||
|
|
||||||
|
class RefreshTokenModelSerializer(ExpiringBaseGrantModelSerializer):
|
||||||
|
"""Serializer for BaseGrantModel and RefreshToken"""
|
||||||
|
|
||||||
|
id_token = SerializerMethodField()
|
||||||
|
|
||||||
|
def get_id_token(self, instance: RefreshToken) -> str:
|
||||||
|
"""Get the token's id_token as JSON String"""
|
||||||
|
return dumps(asdict(instance.id_token), indent=4)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = RefreshToken
|
||||||
|
fields = [
|
||||||
|
"pk",
|
||||||
|
"provider",
|
||||||
|
"user",
|
||||||
|
"is_expired",
|
||||||
|
"expires",
|
||||||
|
"scope",
|
||||||
|
"id_token",
|
||||||
|
]
|
||||||
|
depth = 2
|
||||||
|
|
||||||
|
|
||||||
class AuthorizationCodeViewSet(
|
class AuthorizationCodeViewSet(
|
||||||
mixins.RetrieveModelMixin,
|
mixins.RetrieveModelMixin,
|
||||||
mixins.DestroyModelMixin,
|
mixins.DestroyModelMixin,
|
||||||
|
@ -61,7 +88,7 @@ class RefreshTokenViewSet(
|
||||||
"""RefreshToken Viewset"""
|
"""RefreshToken Viewset"""
|
||||||
|
|
||||||
queryset = RefreshToken.objects.all()
|
queryset = RefreshToken.objects.all()
|
||||||
serializer_class = ExpiringBaseGrantModelSerializer
|
serializer_class = RefreshTokenModelSerializer
|
||||||
filterset_fields = ["user", "provider"]
|
filterset_fields = ["user", "provider"]
|
||||||
ordering = ["provider", "expires"]
|
ordering = ["provider", "expires"]
|
||||||
filter_backends = [
|
filter_backends = [
|
||||||
|
|
|
@ -6,13 +6,13 @@ from django.db import migrations, models
|
||||||
class Migration(migrations.Migration):
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
dependencies = [
|
dependencies = [
|
||||||
('authentik_tenants', '0002_default'),
|
("authentik_tenants", "0002_default"),
|
||||||
]
|
]
|
||||||
|
|
||||||
operations = [
|
operations = [
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='tenant',
|
model_name="tenant",
|
||||||
name='branding_favicon',
|
name="branding_favicon",
|
||||||
field=models.TextField(default='/static/dist/assets/icons/icon.png'),
|
field=models.TextField(default="/static/dist/assets/icons/icon.png"),
|
||||||
),
|
),
|
||||||
]
|
]
|
||||||
|
|
|
@ -25,9 +25,7 @@ class Tenant(models.Model):
|
||||||
branding_logo = models.TextField(
|
branding_logo = models.TextField(
|
||||||
default="/static/dist/assets/icons/icon_left_brand.svg"
|
default="/static/dist/assets/icons/icon_left_brand.svg"
|
||||||
)
|
)
|
||||||
branding_favicon = models.TextField(
|
branding_favicon = models.TextField(default="/static/dist/assets/icons/icon.png")
|
||||||
default="/static/dist/assets/icons/icon.png"
|
|
||||||
)
|
|
||||||
|
|
||||||
flow_authentication = models.ForeignKey(
|
flow_authentication = models.ForeignKey(
|
||||||
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_authentication"
|
Flow, null=True, on_delete=models.SET_NULL, related_name="tenant_authentication"
|
||||||
|
|
71
schema.yml
71
schema.yml
|
@ -4772,7 +4772,7 @@ paths:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/PaginatedExpiringBaseGrantModelList'
|
$ref: '#/components/schemas/PaginatedRefreshTokenModelList'
|
||||||
description: ''
|
description: ''
|
||||||
'400':
|
'400':
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
@ -4799,7 +4799,7 @@ paths:
|
||||||
content:
|
content:
|
||||||
application/json:
|
application/json:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/ExpiringBaseGrantModel'
|
$ref: '#/components/schemas/RefreshTokenModel'
|
||||||
description: ''
|
description: ''
|
||||||
'400':
|
'400':
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
@ -20827,6 +20827,41 @@ components:
|
||||||
required:
|
required:
|
||||||
- pagination
|
- pagination
|
||||||
- results
|
- results
|
||||||
|
PaginatedRefreshTokenModelList:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
pagination:
|
||||||
|
type: object
|
||||||
|
properties:
|
||||||
|
next:
|
||||||
|
type: number
|
||||||
|
previous:
|
||||||
|
type: number
|
||||||
|
count:
|
||||||
|
type: number
|
||||||
|
current:
|
||||||
|
type: number
|
||||||
|
total_pages:
|
||||||
|
type: number
|
||||||
|
start_index:
|
||||||
|
type: number
|
||||||
|
end_index:
|
||||||
|
type: number
|
||||||
|
required:
|
||||||
|
- next
|
||||||
|
- previous
|
||||||
|
- count
|
||||||
|
- current
|
||||||
|
- total_pages
|
||||||
|
- start_index
|
||||||
|
- end_index
|
||||||
|
results:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/RefreshTokenModel'
|
||||||
|
required:
|
||||||
|
- pagination
|
||||||
|
- results
|
||||||
PaginatedReputationPolicyList:
|
PaginatedReputationPolicyList:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -24150,6 +24185,38 @@ components:
|
||||||
required:
|
required:
|
||||||
- to
|
- to
|
||||||
- type
|
- type
|
||||||
|
RefreshTokenModel:
|
||||||
|
type: object
|
||||||
|
description: Serializer for BaseGrantModel and RefreshToken
|
||||||
|
properties:
|
||||||
|
pk:
|
||||||
|
type: integer
|
||||||
|
readOnly: true
|
||||||
|
title: ID
|
||||||
|
provider:
|
||||||
|
$ref: '#/components/schemas/OAuth2Provider'
|
||||||
|
user:
|
||||||
|
$ref: '#/components/schemas/User'
|
||||||
|
is_expired:
|
||||||
|
type: boolean
|
||||||
|
readOnly: true
|
||||||
|
expires:
|
||||||
|
type: string
|
||||||
|
format: date-time
|
||||||
|
scope:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
type: string
|
||||||
|
id_token:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
required:
|
||||||
|
- id_token
|
||||||
|
- is_expired
|
||||||
|
- pk
|
||||||
|
- provider
|
||||||
|
- scope
|
||||||
|
- user
|
||||||
ReputationPolicy:
|
ReputationPolicy:
|
||||||
type: object
|
type: object
|
||||||
description: Reputation Policy Serializer
|
description: Reputation Policy Serializer
|
||||||
|
|
|
@ -1,19 +1,26 @@
|
||||||
import { t } from "@lingui/macro";
|
import { t } from "@lingui/macro";
|
||||||
import { customElement, html, property, TemplateResult } from "lit-element";
|
import { CSSResult, customElement, html, property, TemplateResult } from "lit-element";
|
||||||
import { AKResponse } from "../../api/Client";
|
import { AKResponse } from "../../api/Client";
|
||||||
import { Table, TableColumn } from "../table/Table";
|
import { Table, TableColumn } from "../table/Table";
|
||||||
|
import PFFlex from "@patternfly/patternfly/layouts/Flex/flex.css";
|
||||||
|
|
||||||
import "../forms/DeleteForm";
|
import "../forms/DeleteForm";
|
||||||
import { PAGE_SIZE } from "../../constants";
|
import { PAGE_SIZE } from "../../constants";
|
||||||
import { ExpiringBaseGrantModel, Oauth2Api } from "authentik-api";
|
import { RefreshTokenModel, Oauth2Api } from "authentik-api";
|
||||||
import { DEFAULT_CONFIG } from "../../api/Config";
|
import { DEFAULT_CONFIG } from "../../api/Config";
|
||||||
|
|
||||||
@customElement("ak-user-oauth-refresh-list")
|
@customElement("ak-user-oauth-refresh-list")
|
||||||
export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
export class UserOAuthRefreshList extends Table<RefreshTokenModel> {
|
||||||
|
expandable = true;
|
||||||
|
|
||||||
@property({ type: Number })
|
@property({ type: Number })
|
||||||
userId?: number;
|
userId?: number;
|
||||||
|
|
||||||
apiEndpoint(page: number): Promise<AKResponse<ExpiringBaseGrantModel>> {
|
static get styles(): CSSResult[] {
|
||||||
|
return super.styles.concat(PFFlex);
|
||||||
|
}
|
||||||
|
|
||||||
|
apiEndpoint(page: number): Promise<AKResponse<RefreshTokenModel>> {
|
||||||
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensList({
|
return new Oauth2Api(DEFAULT_CONFIG).oauth2RefreshTokensList({
|
||||||
user: this.userId,
|
user: this.userId,
|
||||||
ordering: "expires",
|
ordering: "expires",
|
||||||
|
@ -33,7 +40,24 @@ export class UserOAuthRefreshList extends Table<ExpiringBaseGrantModel> {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
row(item: ExpiringBaseGrantModel): TemplateResult[] {
|
renderExpanded(item: RefreshTokenModel): TemplateResult {
|
||||||
|
return html`
|
||||||
|
<td role="cell" colspan="4">
|
||||||
|
<div class="pf-c-table__expandable-row-content">
|
||||||
|
<div class="pf-l-flex">
|
||||||
|
<div class="pf-l-flex__item">
|
||||||
|
<h3>${t`ID Token`}</h3>
|
||||||
|
<pre>${item.idToken}</pre>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
row(item: RefreshTokenModel): TemplateResult[] {
|
||||||
return [
|
return [
|
||||||
html`<a href="#/core/providers/${item.provider?.pk}">
|
html`<a href="#/core/providers/${item.provider?.pk}">
|
||||||
${item.provider?.name}
|
${item.provider?.name}
|
||||||
|
|
|
@ -1717,6 +1717,10 @@ msgstr "How many attempts a user has before the flow is canceled. To lock the us
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr "ID"
|
msgstr "ID"
|
||||||
|
|
||||||
|
#: src/elements/oauth/UserRefreshList.ts
|
||||||
|
msgid "ID Token"
|
||||||
|
msgstr "ID Token"
|
||||||
|
|
||||||
#: src/pages/policies/reputation/IPReputationListPage.ts
|
#: src/pages/policies/reputation/IPReputationListPage.ts
|
||||||
msgid "IP"
|
msgid "IP"
|
||||||
msgstr "IP"
|
msgstr "IP"
|
||||||
|
|
|
@ -1709,6 +1709,10 @@ msgstr ""
|
||||||
msgid "ID"
|
msgid "ID"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#:
|
||||||
|
msgid "ID Token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
msgid "IP"
|
msgid "IP"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
|
@ -197,7 +197,7 @@ export class UserViewPage extends LitElement {
|
||||||
<div class="pf-c-card">
|
<div class="pf-c-card">
|
||||||
<div class="pf-c-card__body">
|
<div class="pf-c-card__body">
|
||||||
<ak-object-changelog
|
<ak-object-changelog
|
||||||
targetModelPk=${this.user.pk || 0}
|
targetModelPk=${this.user.pk}
|
||||||
targetModelApp="authentik_core"
|
targetModelApp="authentik_core"
|
||||||
targetModelName="user">
|
targetModelName="user">
|
||||||
</ak-object-changelog>
|
</ak-object-changelog>
|
||||||
|
@ -207,7 +207,7 @@ export class UserViewPage extends LitElement {
|
||||||
<section slot="page-consent" data-tab-title="${t`Explicit Consent`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
<section slot="page-consent" data-tab-title="${t`Explicit Consent`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
<div class="pf-c-card">
|
<div class="pf-c-card">
|
||||||
<div class="pf-c-card__body">
|
<div class="pf-c-card__body">
|
||||||
<ak-user-consent-list userId=${(this.user.pk || 0)}>
|
<ak-user-consent-list userId=${(this.user.pk)}>
|
||||||
</ak-user-consent-list>
|
</ak-user-consent-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -215,7 +215,7 @@ export class UserViewPage extends LitElement {
|
||||||
<section slot="page-oauth-code" data-tab-title="${t`OAuth Authorization Codes`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
<section slot="page-oauth-code" data-tab-title="${t`OAuth Authorization Codes`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
<div class="pf-c-card">
|
<div class="pf-c-card">
|
||||||
<div class="pf-c-card__body">
|
<div class="pf-c-card__body">
|
||||||
<ak-user-oauth-code-list userId=${this.user.pk || 0}>
|
<ak-user-oauth-code-list userId=${this.user.pk}>
|
||||||
</ak-user-oauth-code-list>
|
</ak-user-oauth-code-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -223,7 +223,7 @@ export class UserViewPage extends LitElement {
|
||||||
<section slot="page-oauth-refresh" data-tab-title="${t`OAuth Refresh Codes`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
<section slot="page-oauth-refresh" data-tab-title="${t`OAuth Refresh Codes`}" class="pf-c-page__main-section pf-m-no-padding-mobile">
|
||||||
<div class="pf-c-card">
|
<div class="pf-c-card">
|
||||||
<div class="pf-c-card__body">
|
<div class="pf-c-card__body">
|
||||||
<ak-user-oauth-refresh-list userId=${this.user.pk || 0}>
|
<ak-user-oauth-refresh-list userId=${this.user.pk}>
|
||||||
</ak-user-oauth-refresh-list>
|
</ak-user-oauth-refresh-list>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Reference in a new issue