Compare commits

...

17 Commits

Author SHA1 Message Date
d420719649 release: 2021.3.1-rc2 2021-03-02 21:41:30 +01:00
0018fbacd3 Merge branch 'master' into version-2021.3
# Conflicts:
#	web/src/constants.ts
2021-03-02 21:39:30 +01:00
8c41d2f4cb stages/authenticator_webauthn: add views to update and delete devices 2021-03-02 21:26:31 +01:00
3941590d0c web: fix missing create buttons on user token list 2021-03-02 21:16:14 +01:00
dc4a7c35da core: fix errors on user token views 2021-03-02 21:16:03 +01:00
e8c9b70ae8 sources/ldap: check pwdLastSet when syncing Users 2021-03-02 21:05:02 +01:00
74d240dfd4 admin: use spinner-button for modal forms 2021-03-02 20:37:23 +01:00
7d296b2119 root: align image on readme 2021-03-02 17:00:36 +01:00
373793ce9a policies: show more information when provider fails to resolve application 2021-03-02 16:58:55 +01:00
5c0ec7554b web: fix lists not being paginated 2021-03-02 15:12:26 +01:00
792fa45dca providers/oauth2: add logout URL to Setup URLs API 2021-03-02 15:11:18 +01:00
743aaea15e policies: improve logging 2021-03-02 15:04:31 +01:00
de03ed0aec web: fix background for shell without flow executor 2021-03-02 15:04:14 +01:00
e68ec16a34 web: improve display of notification age 2021-03-02 15:03:58 +01:00
68a0219d0f docs: update debug screenshot 2021-03-02 13:29:09 +01:00
38d9533afd root: update screenshots 2021-03-02 12:15:32 +01:00
7538af5e09 docs: fix download links for compose 2021-03-02 10:07:46 +01:00
69 changed files with 329 additions and 81 deletions

View File

@ -1,5 +1,5 @@
[bumpversion]
current_version = 2021.3.1-rc1
current_version = 2021.3.1-rc2
tag = True
commit = True
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)

View File

@ -18,11 +18,11 @@ jobs:
- name: Building Docker Image
run: docker build
--no-cache
-t beryju/authentik:2021.3.1-rc1
-t beryju/authentik:2021.3.1-rc2
-t beryju/authentik:latest
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/authentik:2021.3.1-rc1
run: docker push beryju/authentik:2021.3.1-rc2
- name: Push Docker Container to Registry (latest)
run: docker push beryju/authentik:latest
build-proxy:
@ -48,11 +48,11 @@ jobs:
cd outpost/
docker build \
--no-cache \
-t beryju/authentik-proxy:2021.3.1-rc1 \
-t beryju/authentik-proxy:2021.3.1-rc2 \
-t beryju/authentik-proxy:latest \
-f proxy.Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/authentik-proxy:2021.3.1-rc1
run: docker push beryju/authentik-proxy:2021.3.1-rc2
- name: Push Docker Container to Registry (latest)
run: docker push beryju/authentik-proxy:latest
build-static:
@ -69,11 +69,11 @@ jobs:
cd web/
docker build \
--no-cache \
-t beryju/authentik-static:2021.3.1-rc1 \
-t beryju/authentik-static:2021.3.1-rc2 \
-t beryju/authentik-static:latest \
-f Dockerfile .
- name: Push Docker Container to Registry (versioned)
run: docker push beryju/authentik-static:2021.3.1-rc1
run: docker push beryju/authentik-static:2021.3.1-rc2
- name: Push Docker Container to Registry (latest)
run: docker push beryju/authentik-static:latest
test-release:
@ -107,5 +107,5 @@ jobs:
SENTRY_PROJECT: authentik
SENTRY_URL: https://sentry.beryju.org
with:
tagName: 2021.3.1-rc1
tagName: 2021.3.1-rc2
environment: beryjuorg-prod

View File

@ -1,4 +1,6 @@
<img src="https://goauthentik.io/img/icon_top_brand_colour.svg" height="250" alt="authentik logo">
<p align="center">
<img src="https://goauthentik.io/img/icon_top_brand_colour.svg" height="150" alt="authentik logo">
</p>
---
@ -22,8 +24,10 @@ For bigger setups, there is a Helm Chart in the `helm/` directory. This is docum
## Screenshots
![](https://goauthentik.io/img/screen_apps.png)
![](https://goauthentik.io/img/screen_admin.png)
Light | Dark
--- | ---
![](https://goauthentik.io/img/screen_apps_light.png) | ![](https://goauthentik.io/img/screen_apps_dark.png)
![](https://goauthentik.io/img/screen_admin_light.png) | ![](https://goauthentik.io/img/screen_admin_dark.png)
## Development

View File

@ -4,9 +4,9 @@
| Version | Supported |
| ---------- | ------------------ |
| 0.13.x | :white_check_mark: |
| 0.14.x | :white_check_mark: |
| 2021.1.x | :white_check_mark: |
| 2021.2.x | :white_check_mark: |
| 2021.3.x | :white_check_mark: |
## Reporting a Vulnerability

View File

@ -1,2 +1,2 @@
"""authentik"""
__version__ = "2021.3.1-rc1"
__version__ = "2021.3.1-rc2"

View File

@ -27,7 +27,9 @@
</div>
</section>
<footer class="pf-c-modal-box__footer">
<input class="pf-c-button pf-m-primary" type="submit" form="main-form" value="{% block action %}{% endblock %}" />
<ak-spinner-button form="main-form">
{% block action %}{% endblock %}
</ak-spinner-button>&nbsp;
<a class="pf-c-button pf-m-secondary" href="{% back %}">{% trans "Cancel" %}</a>
</footer>
{% endblock %}

View File

@ -6,6 +6,7 @@ from rest_framework.response import Response
class Pagination(pagination.PageNumberPagination):
"""Pagination which includes total pages and current page"""
page_query_param = "page"
page_size_query_param = "page_size"
def get_paginated_response(self, data):

View File

@ -90,7 +90,7 @@ class UserManager(DjangoUserManager):
class User(GuardianUserMixin, AbstractUser):
"""Custom User model to allow easier adding o f user-based settings"""
"""Custom User model to allow easier adding of user-based settings"""
uuid = models.UUIDField(default=uuid4, editable=False)
name = models.TextField(help_text=_("User's display name."))

View File

@ -1,12 +0,0 @@
{% extends "base/skeleton.html" %}
{% load i18n %}
{% block body %}
<ak-message-container></ak-message-container>
<div class="pf-c-page">
<a class="pf-c-skip-to-content pf-c-button pf-m-primary" href="#main-content">{% trans 'Skip to content' %}</a>
{% block page_content %}
{% endblock %}
</div>
{% endblock %}

View File

@ -1,4 +1,4 @@
{% extends 'base/page.html' %}
{% extends 'base/skeleton.html' %}
{% load i18n %}
{% load authentik_utils %}

View File

@ -7,7 +7,6 @@ from django.contrib.auth.mixins import (
)
from django.contrib.messages.views import SuccessMessageMixin
from django.http.response import HttpResponse
from django.urls import reverse_lazy
from django.utils.translation import gettext as _
from django.views.generic import UpdateView
from django.views.generic.base import TemplateView
@ -35,7 +34,7 @@ class UserDetailsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
form_class = UserDetailForm
success_message = _("Successfully updated user.")
success_url = reverse_lazy("authentik_core:user-details")
success_url = "/"
def get_object(self):
return self.request.user
@ -62,7 +61,7 @@ class TokenCreateView(
permission_required = "authentik_core.add_token"
template_name = "generic/create.html"
success_url = reverse_lazy("authentik_core:user-tokens")
success_url = "/"
success_message = _("Successfully created Token")
def form_valid(self, form: UserTokenForm) -> HttpResponse:
@ -80,7 +79,7 @@ class TokenUpdateView(
form_class = UserTokenForm
permission_required = "authentik_core.change_token"
template_name = "generic/update.html"
success_url = reverse_lazy("authentik_core:user-tokens")
success_url = "/"
success_message = _("Successfully updated Token")
def get_object(self) -> Token:
@ -100,7 +99,7 @@ class TokenDeleteView(LoginRequiredMixin, PermissionRequiredMixin, DeleteMessage
model = Token
permission_required = "authentik_core.delete_token"
template_name = "generic/delete.html"
success_url = reverse_lazy("authentik_core:user-tokens")
success_url = "/"
success_message = _("Successfully deleted Token")
def get_object(self) -> Token:

View File

@ -2,8 +2,8 @@
from urllib.parse import urlparse
from django.http import HttpResponse
from django.shortcuts import redirect, reverse
from django.urls import NoReverseMatch
from django.shortcuts import redirect
from django.urls import NoReverseMatch, reverse
from django.utils.http import urlencode
from structlog.stdlib import get_logger

View File

@ -0,0 +1,87 @@
# Generated by Django 3.1.7 on 2021-03-02 08:56
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_policies_event_matcher", "0010_auto_20210222_1821"),
]
operations = [
migrations.AlterField(
model_name="eventmatcherpolicy",
name="app",
field=models.TextField(
blank=True,
choices=[
("authentik.admin", "authentik Admin"),
("authentik.api", "authentik API"),
("authentik.events", "authentik Events"),
("authentik.crypto", "authentik Crypto"),
("authentik.flows", "authentik Flows"),
("authentik.outposts", "authentik Outpost"),
("authentik.lib", "authentik lib"),
("authentik.policies", "authentik Policies"),
("authentik.policies.dummy", "authentik Policies.Dummy"),
(
"authentik.policies.event_matcher",
"authentik Policies.Event Matcher",
),
("authentik.policies.expiry", "authentik Policies.Expiry"),
("authentik.policies.expression", "authentik Policies.Expression"),
(
"authentik.policies.group_membership",
"authentik Policies.Group Membership",
),
("authentik.policies.hibp", "authentik Policies.HaveIBeenPwned"),
("authentik.policies.password", "authentik Policies.Password"),
("authentik.policies.reputation", "authentik Policies.Reputation"),
("authentik.providers.proxy", "authentik Providers.Proxy"),
("authentik.providers.oauth2", "authentik Providers.OAuth2"),
("authentik.providers.saml", "authentik Providers.SAML"),
("authentik.recovery", "authentik Recovery"),
("authentik.sources.ldap", "authentik Sources.LDAP"),
("authentik.sources.oauth", "authentik Sources.OAuth"),
("authentik.sources.saml", "authentik Sources.SAML"),
(
"authentik.stages.authenticator_static",
"authentik Stages.Authenticator.Static",
),
(
"authentik.stages.authenticator_totp",
"authentik Stages.Authenticator.TOTP",
),
(
"authentik.stages.authenticator_validate",
"authentik Stages.Authenticator.Validate",
),
(
"authentik.stages.authenticator_webauthn",
"authentik Stages.Authenticator.WebAuthn",
),
("authentik.stages.captcha", "authentik Stages.Captcha"),
("authentik.stages.consent", "authentik Stages.Consent"),
("authentik.stages.deny", "authentik Stages.Deny"),
("authentik.stages.dummy", "authentik Stages.Dummy"),
("authentik.stages.email", "authentik Stages.Email"),
(
"authentik.stages.identification",
"authentik Stages.Identification",
),
("authentik.stages.invitation", "authentik Stages.User Invitation"),
("authentik.stages.password", "authentik Stages.Password"),
("authentik.stages.prompt", "authentik Stages.Prompt"),
("authentik.stages.user_delete", "authentik Stages.User Delete"),
("authentik.stages.user_login", "authentik Stages.User Login"),
("authentik.stages.user_logout", "authentik Stages.User Logout"),
("authentik.stages.user_write", "authentik Stages.User Write"),
("authentik.managed", "authentik Managed"),
("authentik.core", "authentik Core"),
],
default="",
help_text="Match events created by selected application. When left empty, all applications are matched.",
),
),
]

View File

@ -62,11 +62,15 @@ class PolicyAccessView(AccessMixin, View):
return self.handle_no_permission()
try:
self.resolve_provider_application()
except (Application.DoesNotExist, Provider.DoesNotExist):
return self.handle_no_permission_authenticated()
except (Application.DoesNotExist, Provider.DoesNotExist) as exc:
LOGGER.warning("failed to resolve application", exc=exc)
return self.handle_no_permission_authenticated(
PolicyResult(False, _("Failed to resolve application"))
)
# Check if user is unauthenticated, so we pass the application
# for the identification stage
if not request.user.is_authenticated:
LOGGER.warning("user not authenticated")
return self.handle_no_permission()
# Check permissions
result = self.user_has_access()

View File

@ -45,6 +45,7 @@ class OAuth2ProviderSetupURLs(Serializer):
token = ReadOnlyField()
user_info = ReadOnlyField()
provider_info = ReadOnlyField()
logout = ReadOnlyField()
def create(self, request: Request) -> Response:
raise NotImplementedError
@ -83,6 +84,7 @@ class OAuth2ProviderViewSet(ModelViewSet):
)
),
"provider_info": None,
"logout": None,
}
try:
data["provider_info"] = request.build_absolute_uri(
@ -91,6 +93,12 @@ class OAuth2ProviderViewSet(ModelViewSet):
kwargs={"application_slug": provider.application.slug},
)
)
data["logout"] = request.build_absolute_uri(
reverse(
"authentik_providers_oauth2:end-session",
kwargs={"application_slug": provider.application.slug},
)
)
except Provider.application.RelatedObjectDoesNotExist: # pylint: disable=no-member
pass
return Response(data)

View File

@ -1,7 +1,10 @@
"""Sync LDAP Users into authentik"""
from datetime import datetime
import ldap3
import ldap3.core.exceptions
from django.db.utils import IntegrityError
from pytz import UTC
from authentik.core.models import User
from authentik.sources.ldap.sync.base import LDAP_UNIQUENESS, BaseLDAPSynchronizer
@ -53,11 +56,21 @@ class UserLDAPSynchronizer(BaseLDAPSynchronizer):
)
)
else:
if created:
ak_user.set_unusable_password()
ak_user.save()
self._logger.debug(
"Synced User", user=ak_user.username, created=created
)
user_count += 1
# pylint: disable=no-value-for-parameter
pwd_last_set = UTC.localize(
attributes.get("pwdLastSet", datetime.now())
)
if created or pwd_last_set >= ak_user.password_change_date:
self._logger.debug(
"Reset user's password",
user=ak_user.username,
created=created,
pwd_last_set=pwd_last_set,
)
ak_user.set_unusable_password()
ak_user.save()
return user_count

View File

@ -1,7 +1,10 @@
"""Webauthn stage forms"""
from django import forms
from authentik.stages.authenticator_webauthn.models import AuthenticateWebAuthnStage
from authentik.stages.authenticator_webauthn.models import (
AuthenticateWebAuthnStage,
WebAuthnDevice,
)
class AuthenticateWebAuthnStageForm(forms.ModelForm):
@ -15,3 +18,16 @@ class AuthenticateWebAuthnStageForm(forms.ModelForm):
widgets = {
"name": forms.TextInput(),
}
class DeviceEditForm(forms.ModelForm):
"""Form to edit webauthn device"""
class Meta:
model = WebAuthnDevice
fields = ["name"]
widgets = {
"name": forms.TextInput(),
}

View File

@ -79,3 +79,8 @@ class WebAuthnDevice(Device):
def __str__(self):
return self.name or str(self.user)
class Meta:
verbose_name = _("WebAuthn Device")
verbose_name_plural = _("WebAuthn Devices")

View File

@ -17,6 +17,20 @@
Created {{ created_on }}
{% endblocktrans %}
</div>
<div class="pf-c-data-list__cell">
<ak-modal-button href="{% url 'authentik_stages_authenticator_webauthn:device-update' pk=device.pk %}">
<ak-spinner-button slot="trigger" class="pf-m-primary">
{% trans 'Update' %}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
<ak-modal-button href="{% url 'authentik_stages_authenticator_webauthn:device-delete' pk=device.pk %}">
<ak-spinner-button slot="trigger" class="pf-m-danger">
{% trans 'Delete' %}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
</div>
</div>
</div>
</li>

View File

@ -1,10 +1,16 @@
"""WebAuthn urls"""
from django.urls import path
from authentik.stages.authenticator_webauthn.views import UserSettingsView
from authentik.stages.authenticator_webauthn.views import (
DeviceDeleteView,
DeviceUpdateView,
UserSettingsView,
)
urlpatterns = [
path(
"<uuid:stage_uuid>/settings/", UserSettingsView.as_view(), name="user-settings"
),
path("devices/<int:pk>/delete/", DeviceDeleteView.as_view(), name="device-delete"),
path("devices/<int:pk>/update/", DeviceUpdateView.as_view(), name="device-update"),
]

View File

@ -1,8 +1,13 @@
"""webauthn views"""
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.messages.views import SuccessMessageMixin
from django.http.response import Http404
from django.shortcuts import get_object_or_404
from django.views.generic import TemplateView
from django.utils.translation import gettext as _
from django.views.generic import TemplateView, UpdateView
from authentik.admin.views.utils import DeleteMessageView
from authentik.stages.authenticator_webauthn.forms import DeviceEditForm
from authentik.stages.authenticator_webauthn.models import (
AuthenticateWebAuthnStage,
WebAuthnDevice,
@ -22,3 +27,34 @@ class UserSettingsView(LoginRequiredMixin, TemplateView):
)
kwargs["stage"] = stage
return kwargs
class DeviceUpdateView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
"""Update device"""
model = WebAuthnDevice
form_class = DeviceEditForm
template_name = "generic/update.html"
success_url = "/"
success_message = _("Successfully updated Device")
def get_object(self) -> WebAuthnDevice:
device: WebAuthnDevice = super().get_object()
if device.user != self.request.user:
raise Http404
return device
class DeviceDeleteView(LoginRequiredMixin, DeleteMessageView):
"""Delete device"""
model = WebAuthnDevice
template_name = "generic/delete.html"
success_url = "/"
success_message = _("Successfully deleted Device")
def get_object(self) -> WebAuthnDevice:
device: WebAuthnDevice = super().get_object()
if device.user != self.request.user:
raise Http404
return device

View File

@ -1,9 +1,6 @@
{% extends "base/page.html" %}
{% load i18n %}
{% load authentik_utils %}
{% block body %}
<div class="pf-c-card">
<div class="pf-c-card__header pf-c-title pf-m-md">
{% trans 'Reset your password' %}
@ -14,4 +11,3 @@
</a>
</div>
</div>
{% endblock %}

View File

@ -19,7 +19,7 @@ services:
networks:
- internal
server:
image: beryju/authentik:${AUTHENTIK_TAG:-2021.3.1-rc1}
image: beryju/authentik:${AUTHENTIK_TAG:-2021.3.1-rc2}
command: server
environment:
AUTHENTIK_REDIS__HOST: redis
@ -45,7 +45,7 @@ services:
env_file:
- .env
worker:
image: beryju/authentik:${AUTHENTIK_TAG:-2021.3.1-rc1}
image: beryju/authentik:${AUTHENTIK_TAG:-2021.3.1-rc2}
command: worker
networks:
- internal
@ -62,7 +62,7 @@ services:
env_file:
- .env
static:
image: beryju/authentik-static:${AUTHENTIK_TAG:-2021.3.1-rc1}
image: beryju/authentik-static:${AUTHENTIK_TAG:-2021.3.1-rc2}
networks:
- internal
labels:

View File

@ -4,7 +4,7 @@ name: authentik
home: https://goauthentik.io
sources:
- https://github.com/BeryJu/authentik
version: "2021.3.1-rc1"
version: "2021.3.1-rc2"
icon: https://raw.githubusercontent.com/BeryJu/authentik/master/web/icons/icon.svg
dependencies:
- name: postgresql

View File

@ -4,7 +4,7 @@
|-----------------------------------|-------------------------|-------------|
| image.name | beryju/authentik | Image used to run the authentik server and worker |
| image.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) |
| image.tag | 2021.3.1-rc1 | Image tag |
| image.tag | 2021.3.1-rc2 | Image tag |
| image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments |
| serverReplicas | 1 | Replicas for the Server deployment |
| workerReplicas | 1 | Replicas for the Worker deployment |

View File

@ -5,7 +5,7 @@ image:
name: beryju/authentik
name_static: beryju/authentik-static
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
tag: 2021.3.1-rc1
tag: 2021.3.1-rc2
pullPolicy: IfNotPresent
serverReplicas: 1

View File

@ -1,3 +1,3 @@
package pkg
const VERSION = "2021.3.1-rc1"
const VERSION = "2021.3.1-rc2"

View File

@ -9657,7 +9657,7 @@ definitions:
readOnly: true
readOnly: true
user:
description: Custom User model to allow easier adding o f user-based settings
description: Custom User model to allow easier adding of user-based settings
required:
- password
- username
@ -10684,6 +10684,10 @@ definitions:
title: Provider info
type: string
readOnly: true
logout:
title: Logout
type: string
readOnly: true
ProxyProvider:
description: ProxyProvider Serializer
required:
@ -11867,7 +11871,7 @@ definitions:
description: Optional fixed data to enforce on user enrollment.
type: object
created_by:
description: Custom User model to allow easier adding o f user-based settings
description: Custom User model to allow easier adding of user-based settings
required:
- password
- username

View File

@ -4,7 +4,9 @@ import { NotFoundError, RequestError } from "./Error";
export const VERSION = "v2beta";
export interface QueryArguments {
[key: string]: number | string | boolean | null;
page?: number;
page_size?: number;
[key: string]: number | string | boolean | undefined | null;
}
export interface BaseInheritanceModel {

View File

@ -8,6 +8,7 @@ export interface OAuth2SetupURLs {
token: string;
user_info: string;
provider_info?: string;
logout?: string;
}

View File

@ -61,11 +61,6 @@ select[multiple] {
font-family: monospace;
}
/* Fix pre elements within alerts */
.pf-c-alert pre {
white-space: pre-wrap;
}
.pf-c-content h1 {
display: flex;
align-items: flex-start;
@ -85,6 +80,12 @@ select[multiple] {
z-index: auto !important;
}
/* ensure background on non-flow pages match */
.pf-c-background-image::before {
background-image: url("dist/assets/images/flow_background.jpg");
background-position: center;
}
/* Fix spacing between messages */
ak-message {
display: block;

View File

@ -3,4 +3,5 @@ export const SUCCESS_CLASS = "pf-m-success";
export const ERROR_CLASS = "pf-m-danger";
export const PROGRESS_CLASS = "pf-m-in-progress";
export const CURRENT_CLASS = "pf-m-current";
export const VERSION = "2021.3.1-rc1";
export const VERSION = "2021.3.1-rc2";
export const PAGE_SIZE = 20;

View File

@ -59,9 +59,9 @@ export class SpinnerButton extends LitElement {
return;
}
if (this.form) {
// Because safari we can't just extend HTMLButtonElement, hence I have to implement
// these attributes by myself here, sigh...
document.querySelector<HTMLFormElement>(`#${this.form}`)?.submit();
// Since the form= attribute is only used within a modal button,
// we can assume the form is always two levels up
this.parentElement?.parentElement?.querySelector < HTMLFormElement>(`#${this.form}`)?.dispatchEvent(new Event("submit"));
}
this.setLoading();
}

View File

@ -40,9 +40,7 @@ export class NotificationDrawer extends LitElement {
}
renderItem(item: Notification): TemplateResult {
const delta = Date.now() - (parseInt(item.created, 10) * 1000);
// TODO: more flexible display, minutes and seconds
const age = `${Math.round(delta / 1000 / 3600)} Hours ago`;
const created = new Date(parseInt(item.created, 10) * 1000);
let level = "";
switch (item.severity) {
case "notice":
@ -76,7 +74,7 @@ export class NotificationDrawer extends LitElement {
</button>
</div>
<p class="pf-c-notification-drawer__list-item-description">${item.body}</p>
<small class="pf-c-notification-drawer__list-item-timestamp">${age}</small>
<small class="pf-c-notification-drawer__list-item-timestamp">${created.toLocaleString()}</small>
</li>`;
}

View File

@ -11,6 +11,7 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import { Policy } from "../../api/Policies";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-bound-policies-list")
export class BoundPoliciesList extends Table<PolicyBinding> {
@ -22,6 +23,7 @@ export class BoundPoliciesList extends Table<PolicyBinding> {
target: this.target || "",
ordering: "order",
page: page,
page_size: PAGE_SIZE,
});
}

View File

@ -7,6 +7,7 @@ import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-application-list")
export class ApplicationListPage extends TablePage<Application> {
@ -30,6 +31,7 @@ export class ApplicationListPage extends TablePage<Application> {
return Application.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -7,6 +7,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { CertificateKeyPair } from "../../api/CertificateKeyPair";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-crypto-certificatekeypair-list")
export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
@ -32,6 +33,7 @@ export class CertificateKeyPairListPage extends TablePage<CertificateKeyPair> {
return CertificateKeyPair.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -2,6 +2,7 @@ import { gettext } from "django";
import { customElement, html, property, TemplateResult } from "lit-element";
import { AKResponse } from "../../api/Client";
import { Event } from "../../api/Events";
import { PAGE_SIZE } from "../../constants";
import { TableColumn } from "../../elements/table/Table";
import { TablePage } from "../../elements/table/TablePage";
import { time } from "../../utils";
@ -31,6 +32,7 @@ export class EventListPage extends TablePage<Event> {
return Event.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE * 3,
search: this.search || "",
});
}

View File

@ -8,6 +8,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Rule } from "../../api/EventRules";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-event-rule-list")
export class RuleListPage extends TablePage<Rule> {
@ -33,6 +34,7 @@ export class RuleListPage extends TablePage<Rule> {
return Rule.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -8,6 +8,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Transport } from "../../api/EventTransports";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-event-transport-list")
export class TransportListPage extends TablePage<Transport> {
@ -31,6 +32,7 @@ export class TransportListPage extends TablePage<Transport> {
return Transport.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -11,6 +11,7 @@ import "../../elements/buttons/Dropdown";
import "../../elements/policies/BoundPoliciesList";
import { FlowStageBinding, Stage } from "../../api/Flows";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-bound-stages-list")
export class BoundStagesList extends Table<FlowStageBinding> {
@ -24,6 +25,7 @@ export class BoundStagesList extends Table<FlowStageBinding> {
target: this.target || "",
ordering: "order",
page: page,
page_size: PAGE_SIZE,
});
}

View File

@ -7,6 +7,7 @@ import { TablePage } from "../../elements/table/TablePage";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-flow-list")
export class FlowListPage extends TablePage<Flow> {
@ -30,6 +31,7 @@ export class FlowListPage extends TablePage<Flow> {
return Flow.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -7,6 +7,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Group } from "../../api/Groups";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-group-list")
export class GroupListPage extends TablePage<Group> {
@ -30,6 +31,7 @@ export class GroupListPage extends TablePage<Group> {
return Group.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -10,6 +10,7 @@ import "./OutpostHealth";
import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/TokenCopyButton";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-outpost-list")
export class OutpostListPage extends TablePage<Outpost> {
@ -29,6 +30,7 @@ export class OutpostListPage extends TablePage<Outpost> {
return Outpost.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -11,6 +11,7 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/ModalButton";
import "../../elements/buttons/Dropdown";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-outpost-service-connection-list")
export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceConnection> {
@ -31,6 +32,7 @@ export class OutpostServiceConnectionListPage extends TablePage<OutpostServiceCo
return OutpostServiceConnection.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -9,6 +9,7 @@ import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Policy } from "../../api/Policies";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-policy-list")
export class PolicyListPage extends TablePage<Policy> {
@ -31,7 +32,8 @@ export class PolicyListPage extends TablePage<Policy> {
apiEndpoint(page: number): Promise<AKResponse<Policy>> {
return Policy.list({
ordering: this.order,
page: page,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -9,6 +9,7 @@ import "../../elements/buttons/Dropdown";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-property-mapping-list")
export class PropertyMappingListPage extends TablePage<PropertyMapping> {
@ -35,6 +36,7 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
return PropertyMapping.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
managed__isnull: this.hideManaged,
});

View File

@ -148,10 +148,16 @@ export class OAuth2ProviderViewPage extends Page {
</div>
<div class="pf-c-form__group">
<label class="pf-c-form__label" for="help-text-simple-form-name">
<span class="pf-c-form__label-text">${gettext("Userinfo Endpoint")}</span>
<span class="pf-c-form__label-text">${gettext("Userinfo URL")}</span>
</label>
<input class="pf-c-form-control" readonly type="text" value="${this.providerUrls?.user_info || "-"}" />
</div>
<div class="pf-c-form__group">
<label class="pf-c-form__label" for="help-text-simple-form-name">
<span class="pf-c-form__label-text">${gettext("Logout URL")}</span>
</label>
<input class="pf-c-form-control" readonly type="text" value="${this.providerUrls?.logout || "-"}" />
</div>
</form>
</div>
</div>

View File

@ -9,6 +9,7 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import { TableColumn } from "../../elements/table/Table";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-provider-list")
export class ProviderListPage extends TablePage<Provider> {
@ -32,6 +33,7 @@ export class ProviderListPage extends TablePage<Provider> {
return Provider.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -9,6 +9,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import { until } from "lit-html/directives/until";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-source-list")
export class SourceListPage extends TablePage<Source> {
@ -32,6 +33,7 @@ export class SourceListPage extends TablePage<Source> {
return Source.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -7,6 +7,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Invitation } from "../../api/Invitations";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-stage-invitation-list")
export class InvitationListPage extends TablePage<Invitation> {
@ -30,6 +31,7 @@ export class InvitationListPage extends TablePage<Invitation> {
return Invitation.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -7,6 +7,7 @@ import "../../elements/buttons/ModalButton";
import "../../elements/buttons/SpinnerButton";
import { TableColumn } from "../../elements/table/Table";
import { Prompt } from "../../api/Prompts";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-stage-prompt-list")
export class PromptListPage extends TablePage<Prompt> {
@ -30,6 +31,7 @@ export class PromptListPage extends TablePage<Prompt> {
return Prompt.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -9,6 +9,7 @@ import "../../elements/buttons/SpinnerButton";
import "../../elements/buttons/Dropdown";
import { until } from "lit-html/directives/until";
import { Stage } from "../../api/Flows";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-stage-list")
export class StageListPage extends TablePage<Stage> {
@ -32,6 +33,7 @@ export class StageListPage extends TablePage<Stage> {
return Stage.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -8,6 +8,7 @@ import "../../elements/buttons/Dropdown";
import "../../elements/buttons/TokenCopyButton";
import { TableColumn } from "../../elements/table/Table";
import { Token } from "../../api/Tokens";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-token-list")
export class TokenListPage extends TablePage<Token> {
@ -31,6 +32,7 @@ export class TokenListPage extends TablePage<Token> {
return Token.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -7,6 +7,7 @@ import "../../elements/buttons/Dropdown";
import "../../elements/buttons/TokenCopyButton";
import { Table, TableColumn } from "../../elements/table/Table";
import { Token } from "../../api/Tokens";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-token-user-list")
export class UserTokenList extends Table<Token> {
@ -21,6 +22,7 @@ export class UserTokenList extends Table<Token> {
return Token.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}
@ -35,6 +37,18 @@ export class UserTokenList extends Table<Token> {
];
}
renderToolbar(): TemplateResult {
return html`
<ak-modal-button href="-/user/tokens/create/">
<ak-spinner-button slot="trigger" class="pf-m-primary">
${gettext("Create")}
</ak-spinner-button>
<div slot="modal"></div>
</ak-modal-button>
${super.renderToolbar()}
`;
}
row(item: Token): TemplateResult[] {
return [
html`${item.identifier}`,

View File

@ -8,6 +8,7 @@ import "../../elements/buttons/Dropdown";
import "../../elements/buttons/ActionButton";
import { TableColumn } from "../../elements/table/Table";
import { User } from "../../api/Users";
import { PAGE_SIZE } from "../../constants";
@customElement("ak-user-list")
export class UserListPage extends TablePage<User> {
@ -31,6 +32,7 @@ export class UserListPage extends TablePage<User> {
return User.list({
ordering: this.order,
page: page,
page_size: PAGE_SIZE,
search: this.search || "",
});
}

View File

@ -13,5 +13,7 @@ See [Docker-compose](installation/docker-compose) or [Kubernetes](installation/k
## Screenshots
![](/img/screen_apps.png)
![](/img/screen_admin.png)
Light | Dark
--- | ---
![](/img/screen_apps_light.png) | ![](/img/screen_apps_dark.png)
![](/img/screen_admin_light.png) | ![](/img/screen_admin_dark.png)

View File

@ -16,7 +16,7 @@ Download the latest `docker-compose.yml` from [here](https://raw.githubuserconte
To optionally enable error-reporting, run `echo AUTHENTIK_ERROR_REPORTING__ENABLED=true >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.3.1-rc1 >> .env`
To optionally deploy a different version run `echo AUTHENTIK_TAG=2021.3.1-rc2 >> .env`
If this is a fresh authentik install run the following commands to generate a password:

View File

@ -24,7 +24,7 @@ image:
name: beryju/authentik
name_static: beryju/authentik-static
name_outposts: beryju/authentik # Prefix used for Outpost deployments, Outpost type and version is appended
tag: 2021.3.1-rc1
tag: 2021.3.1-rc2
serverReplicas: 1
workerReplicas: 1

View File

@ -123,7 +123,7 @@ The integrations affected are:
### docker-compose
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-2021.1/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-2021.2/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
### Kubernetes

View File

@ -45,7 +45,7 @@ This release does not introduce any new requirements.
### docker-compose
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-2021.1/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
Download the latest docker-compose file from [here](https://raw.githubusercontent.com/BeryJu/authentik/version-2021.3/docker-compose.yml). Afterwards, simply run `docker-compose up -d` and then the standard upgrade command of `docker-compose run --rm server migrate`.
### Kubernetes

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 9.6 KiB

View File

@ -100,7 +100,7 @@ function Home() {
<div className="row">
<div className="col col--5">
<div>
<img className={styles.featureImage} src={useBaseUrl('img/screen_apps.png')} alt="library screenshot"/>
<img className={styles.featureImage} src={useBaseUrl('img/screen_apps_light.png')} alt="library screenshot"/>
</div>
</div>
<div className="col col--5 col--offset-2 padding-vert--xl">
@ -131,7 +131,7 @@ function Home() {
</div>
<div className="col col--5">
<div>
<img className={styles.featureImage} src={useBaseUrl('img/screen_admin.png')} alt="library screenshot" />
<img className={styles.featureImage} src={useBaseUrl('img/screen_admin_light.png')} alt="library screenshot" />
</div>
</div>
</div>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 382 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 747 KiB