Compare commits
18 Commits
version/0.
...
version/0.
Author | SHA1 | Date | |
---|---|---|---|
aef5c60a7b | |||
d4c9c667c9 | |||
96f0d582f0 | |||
7e8702a71e | |||
1524061480 | |||
434922f702 | |||
d2862ddc93 | |||
6e55431d4c | |||
01548c5e9c | |||
bf1dae2dbe | |||
59c93defcf | |||
a2a1a27502 | |||
e3227e7d54 | |||
1f4a8fffdb | |||
86b1183883 | |||
f781f4848c | |||
19824d693c | |||
0694b911a4 |
@ -1,5 +1,5 @@
|
||||
[bumpversion]
|
||||
current_version = 0.13.0-rc1
|
||||
current_version = 0.13.0-rc3
|
||||
tag = True
|
||||
commit = True
|
||||
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\-(?P<release>.*)
|
||||
@ -23,6 +23,8 @@ values =
|
||||
|
||||
[bumpversion:file:helm/values.yaml]
|
||||
|
||||
[bumpversion:file:helm/README.md]
|
||||
|
||||
[bumpversion:file:helm/Chart.yaml]
|
||||
|
||||
[bumpversion:file:.github/workflows/release.yml]
|
||||
|
15
.github/workflows/release.yml
vendored
@ -18,11 +18,11 @@ jobs:
|
||||
- name: Building Docker Image
|
||||
run: docker build
|
||||
--no-cache
|
||||
-t beryju/authentik:0.13.0-rc1
|
||||
-t beryju/authentik:0.13.0-rc3
|
||||
-t beryju/authentik:latest
|
||||
-f Dockerfile .
|
||||
- name: Push Docker Container to Registry (versioned)
|
||||
run: docker push beryju/authentik:0.13.0-rc1
|
||||
run: docker push beryju/authentik:0.13.0-rc3
|
||||
- name: Push Docker Container to Registry (latest)
|
||||
run: docker push beryju/authentik:latest
|
||||
build-proxy:
|
||||
@ -48,11 +48,11 @@ jobs:
|
||||
cd proxy/
|
||||
docker build \
|
||||
--no-cache \
|
||||
-t beryju/authentik-proxy:0.13.0-rc1 \
|
||||
-t beryju/authentik-proxy:0.13.0-rc3 \
|
||||
-t beryju/authentik-proxy:latest \
|
||||
-f Dockerfile .
|
||||
- name: Push Docker Container to Registry (versioned)
|
||||
run: docker push beryju/authentik-proxy:0.13.0-rc1
|
||||
run: docker push beryju/authentik-proxy:0.13.0-rc3
|
||||
- name: Push Docker Container to Registry (latest)
|
||||
run: docker push beryju/authentik-proxy:latest
|
||||
build-static:
|
||||
@ -69,17 +69,18 @@ jobs:
|
||||
cd web/
|
||||
docker build \
|
||||
--no-cache \
|
||||
-t beryju/authentik-static:0.13.0-rc1 \
|
||||
-t beryju/authentik-static:0.13.0-rc3 \
|
||||
-t beryju/authentik-static:latest \
|
||||
-f Dockerfile .
|
||||
- name: Push Docker Container to Registry (versioned)
|
||||
run: docker push beryju/authentik-static:0.13.0-rc1
|
||||
run: docker push beryju/authentik-static:0.13.0-rc3
|
||||
- name: Push Docker Container to Registry (latest)
|
||||
run: docker push beryju/authentik-static:latest
|
||||
test-release:
|
||||
needs:
|
||||
- build-server
|
||||
- build-static
|
||||
- build-proxy
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
@ -106,5 +107,5 @@ jobs:
|
||||
SENTRY_PROJECT: authentik
|
||||
SENTRY_URL: https://sentry.beryju.org
|
||||
with:
|
||||
tagName: 0.13.0-rc1
|
||||
tagName: 0.13.0-rc3
|
||||
environment: beryjuorg-prod
|
||||
|
@ -1,4 +1,4 @@
|
||||
<img src="icons/icon_top_brand.svg" height="250" alt="authentik logo">
|
||||
<img src="web/icons/icon_top_brand.svg" height="250" alt="authentik logo">
|
||||
|
||||
---
|
||||
|
||||
|
@ -1,2 +1,2 @@
|
||||
"""authentik"""
|
||||
__version__ = "0.13.0-rc1"
|
||||
__version__ = "0.13.0-rc3"
|
||||
|
@ -1,7 +1,10 @@
|
||||
"""Application API Views"""
|
||||
from django.db.models import QuerySet
|
||||
from django.http.response import Http404
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
from rest_framework.decorators import action
|
||||
from rest_framework.fields import SerializerMethodField
|
||||
from rest_framework.generics import get_object_or_404
|
||||
from rest_framework.request import Request
|
||||
from rest_framework.response import Response
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
@ -71,8 +74,12 @@ class ApplicationViewSet(ModelViewSet):
|
||||
@action(detail=True)
|
||||
def metrics(self, request: Request, slug: str):
|
||||
"""Metrics for application logins"""
|
||||
# TODO: Check app read and audit read perms
|
||||
app = Application.objects.get(slug=slug)
|
||||
app = get_object_or_404(
|
||||
get_objects_for_user(request.user, "authentik_core.view_application"),
|
||||
slug=slug,
|
||||
)
|
||||
if not request.user.has_perm("authentik_audit.view_event"):
|
||||
raise Http404
|
||||
return Response(
|
||||
get_events_per_1h(
|
||||
action=EventAction.AUTHORIZE_APPLICATION,
|
||||
|
@ -6,8 +6,6 @@
|
||||
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link rel="preload" href="{% static 'dist/assets/fonts/DINEngschriftStd.woff2' %}" as="font" type="font/woff2" crossorigin>
|
||||
<link rel="preload" href="{% static 'dist/assets/fonts/DINEngschriftStd.woff' %}" as="font" type="font/woff" crossorigin>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
|
||||
<title>{% block title %}{% trans title|default:config.authentik.branding.title %}{% endblock %}</title>
|
||||
|
26
authentik/core/templates/user/details.html
Normal file
@ -0,0 +1,26 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans 'Update details' %}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<form action="" method="post" class="pf-c-form pf-m-horizontal">
|
||||
{% include 'partials/form_horizontal.html' with form=form %}
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<div class="pf-c-form__horizontal-group">
|
||||
<div class="pf-c-form__actions">
|
||||
<input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" />
|
||||
{% if unenrollment_enabled %}
|
||||
<a class="pf-c-button pf-m-danger"
|
||||
href="{% url 'authentik_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{%
|
||||
trans "Delete account" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
@ -15,29 +15,9 @@
|
||||
<section class="pf-c-page__main-section">
|
||||
<div class="pf-u-display-flex pf-u-justify-content-center">
|
||||
<div class="pf-u-w-75">
|
||||
<div class="pf-c-card">
|
||||
<div class="pf-c-card__header pf-c-title pf-m-md">
|
||||
{% trans 'Update details' %}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<form action="" method="post" class="pf-c-form pf-m-horizontal">
|
||||
{% include 'partials/form_horizontal.html' with form=form %}
|
||||
{% block beneath_form %}
|
||||
{% endblock %}
|
||||
<div class="pf-c-form__group pf-m-action">
|
||||
<div class="pf-c-form__horizontal-group">
|
||||
<div class="pf-c-form__actions">
|
||||
<input class="pf-c-button pf-m-primary" type="submit" value="{% trans 'Update' %}" />
|
||||
{% if unenrollment_enabled %}
|
||||
<a class="pf-c-button pf-m-danger"
|
||||
href="{% url 'authentik_flows:default-unenrollment' %}?back={{ request.get_full_path }}">{% trans "Delete account" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<ak-site-shell url="{% url 'authentik_core:user-details' %}">
|
||||
<div slot="body"></div>
|
||||
</ak-site-shell>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
@ -34,9 +34,3 @@ class TestOverviewViews(TestCase):
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("authentik_core:overview")).status_code, 200
|
||||
)
|
||||
|
||||
def test_user_settings(self):
|
||||
"""Test user settings"""
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("authentik_core:user-settings")).status_code, 200
|
||||
)
|
||||
|
@ -28,3 +28,9 @@ class TestUserViews(TestCase):
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("authentik_core:user-settings")).status_code, 200
|
||||
)
|
||||
|
||||
def test_user_details(self):
|
||||
"""Test UserDetailsView"""
|
||||
self.assertEqual(
|
||||
self.client.get(reverse("authentik_core:user-details")).status_code, 200
|
||||
)
|
||||
|
@ -7,6 +7,7 @@ urlpatterns = [
|
||||
path("", shell.ShellView.as_view(), name="shell"),
|
||||
# User views
|
||||
path("-/user/", user.UserSettingsView.as_view(), name="user-settings"),
|
||||
path("-/user/details/", user.UserDetailsView.as_view(), name="user-details"),
|
||||
path("-/user/tokens/", user.TokenListView.as_view(), name="user-tokens"),
|
||||
path(
|
||||
"-/user/tokens/create/",
|
||||
|
@ -11,6 +11,7 @@ from django.http.response import HttpResponse
|
||||
from django.urls import reverse_lazy
|
||||
from django.utils.translation import gettext as _
|
||||
from django.views.generic import ListView, UpdateView
|
||||
from django.views.generic.base import TemplateView
|
||||
from guardian.mixins import PermissionListMixin, PermissionRequiredMixin
|
||||
from guardian.shortcuts import get_objects_for_user
|
||||
|
||||
@ -26,14 +27,20 @@ from authentik.flows.models import Flow, FlowDesignation
|
||||
from authentik.lib.views import CreateAssignPermView
|
||||
|
||||
|
||||
class UserSettingsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
|
||||
"""Update User settings"""
|
||||
class UserSettingsView(TemplateView):
|
||||
"""Multiple SiteShells for user details and all stages"""
|
||||
|
||||
template_name = "user/settings.html"
|
||||
|
||||
|
||||
class UserDetailsView(SuccessMessageMixin, LoginRequiredMixin, UpdateView):
|
||||
"""Update User details"""
|
||||
|
||||
template_name = "user/details.html"
|
||||
form_class = UserDetailForm
|
||||
|
||||
success_message = _("Successfully updated user.")
|
||||
success_url = reverse_lazy("authentik_core:user-settings")
|
||||
success_url = reverse_lazy("authentik_core:user-details")
|
||||
|
||||
def get_object(self):
|
||||
return self.request.user
|
||||
|
@ -22,10 +22,10 @@
|
||||
</ul>
|
||||
{% if not state %}
|
||||
{% if stage.configure_flow %}
|
||||
<a href="{% url 'authentik_flows:configure' stage_uuid=stage.stage_uuid %}?next={{ request.get_full_path }}" class="pf-c-button pf-m-primary">{% trans "Enable Static Tokens" %}</a>
|
||||
<a href="{% url 'authentik_flows:configure' stage_uuid=stage.stage_uuid %}?next={% url 'authentik_core:user-settings' %}" class="ak-root-link pf-c-button pf-m-primary">{% trans "Enable Static Tokens" %}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="{% url 'authentik_stages_otp_static:disable' stage_uuid=stage.stage_uuid %}" class="pf-c-button pf-m-danger">{% trans "Disable Static Tokens" %}</a>
|
||||
<a href="{% url 'authentik_stages_otp_static:disable' stage_uuid=stage.stage_uuid %}" class="ak-root-pf-c-button pf-m-danger">{% trans "Disable Static Tokens" %}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -41,4 +41,4 @@ class DisableView(LoginRequiredMixin, View):
|
||||
Event.new(
|
||||
"static_otp_disable", message="User disabled Static OTP Tokens."
|
||||
).from_http(request)
|
||||
return redirect("authentik_stages_otp:otp-user-settings")
|
||||
return redirect("authentik_core:user-settings")
|
||||
|
@ -18,10 +18,10 @@
|
||||
<p>
|
||||
{% if not state %}
|
||||
{% if stage.configure_flow %}
|
||||
<a href="{% url 'authentik_flows:configure' stage_uuid=stage.stage_uuid %}?next={{ request.get_full_path }}" class="pf-c-button pf-m-primary">{% trans "Enable Time-based OTP" %}</a>
|
||||
<a href="{% url 'authentik_flows:configure' stage_uuid=stage.stage_uuid %}?next={% url 'authentik_core:user-settings' %}" class="ak-root-link pf-c-button pf-m-primary">{% trans "Enable Time-based OTP" %}</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="{% url 'authentik_stages_otp_time:disable' stage_uuid=stage.stage_uuid %}" class="pf-c-button pf-m-danger">{% trans "Disable Time-based OTP" %}</a>
|
||||
<a href="{% url 'authentik_stages_otp_time:disable' stage_uuid=stage.stage_uuid %}" class="ak-root-pf-c-button pf-m-danger">{% trans "Disable Time-based OTP" %}</a>
|
||||
{% endif %}
|
||||
</p>
|
||||
</div>
|
||||
|
@ -38,4 +38,4 @@ class DisableView(LoginRequiredMixin, View):
|
||||
Event.new("totp_disable", message="User disabled Time-based OTP.").from_http(
|
||||
request
|
||||
)
|
||||
return redirect("authentik_stages_otp:otp-user-settings")
|
||||
return redirect("authentik_core:user-settings")
|
||||
|
@ -9,7 +9,7 @@
|
||||
{% trans 'Reset your password' %}
|
||||
</div>
|
||||
<div class="pf-c-card__body">
|
||||
<a class="pf-c-button pf-m-primary" href="{{ url }}">
|
||||
<a class="pf-c-button pf-m-primary ak-root-link" href="{{ url }}">
|
||||
{% trans 'Change password' %}
|
||||
</a>
|
||||
</div>
|
||||
|
@ -19,7 +19,7 @@ services:
|
||||
networks:
|
||||
- internal
|
||||
server:
|
||||
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc1}
|
||||
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc3}
|
||||
command: server
|
||||
environment:
|
||||
AUTHENTIK_REDIS__HOST: redis
|
||||
@ -42,7 +42,7 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
worker:
|
||||
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc1}
|
||||
image: beryju/authentik:${AUTHENTIK_TAG:-0.13.0-rc3}
|
||||
command: worker
|
||||
networks:
|
||||
- internal
|
||||
@ -56,7 +56,7 @@ services:
|
||||
env_file:
|
||||
- .env
|
||||
static:
|
||||
image: beryju/authentik-static:${AUTHENTIK_TAG:-0.13.0-rc1}
|
||||
image: beryju/authentik-static:${AUTHENTIK_TAG:-0.13.0-rc3}
|
||||
networks:
|
||||
- internal
|
||||
labels:
|
||||
|
@ -4,8 +4,8 @@ name: authentik
|
||||
home: https://goauthentik.io
|
||||
sources:
|
||||
- https://github.com/BeryJu/authentik
|
||||
version: "0.13.0-rc1"
|
||||
icon: https://raw.githubusercontent.com/BeryJu/authentik/master/icons/icon.svg
|
||||
version: "0.13.0-rc3"
|
||||
icon: https://raw.githubusercontent.com/BeryJu/authentik/master/web/icons/icon.svg
|
||||
dependencies:
|
||||
- name: postgresql
|
||||
version: 9.4.1
|
||||
|
@ -4,7 +4,8 @@
|
||||
|-----------------------------------|-------------------------|-------------|
|
||||
| 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 | 0.12.5-stable | Image tag |
|
||||
| image.tag | 0.13.0-rc3 | 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 |
|
||||
| kubernetesIntegration | true | Enable/disable the Kubernetes integration for authentik. This will create a service account for authentik to create and update outposts in authentik |
|
||||
|
@ -24,7 +24,7 @@ spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}-static
|
||||
image: "{{ .Values.image.name_static }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: IfNotPresent
|
||||
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 80
|
||||
|
@ -45,6 +45,7 @@ spec:
|
||||
initContainers:
|
||||
- name: authentik-database-migrations
|
||||
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
|
||||
args: [migrate]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
@ -69,6 +70,7 @@ spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
|
||||
args: [server]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
|
@ -48,7 +48,7 @@ spec:
|
||||
containers:
|
||||
- name: {{ .Chart.Name }}
|
||||
image: "{{ .Values.image.name }}:{{ .Values.image.tag }}"
|
||||
imagePullPolicy: IfNotPresent
|
||||
imagePullPolicy: "{{ .Values.image.pullPolicy }}"
|
||||
args: [worker]
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
|
@ -1,5 +1,6 @@
|
||||
image:
|
||||
tag: gh-master
|
||||
pullPolicy: Always
|
||||
|
||||
serverReplicas: 1
|
||||
workerReplicas: 1
|
||||
|
@ -5,7 +5,8 @@ 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: 0.13.0-rc1
|
||||
tag: 0.13.0-rc3
|
||||
pullPolicy: IfNotPresent
|
||||
|
||||
serverReplicas: 1
|
||||
workerReplicas: 1
|
||||
|
@ -1,4 +1,7 @@
|
||||
# flake8: noqa
|
||||
from redis import Redis
|
||||
|
||||
from authentik.lib.config import CONFIG
|
||||
from lifecycle.migrate import BaseMigration
|
||||
|
||||
SQL_STATEMENT = """BEGIN TRANSACTION;
|
||||
@ -103,3 +106,16 @@ class Migration(BaseMigration):
|
||||
def run(self):
|
||||
self.cur.execute(SQL_STATEMENT)
|
||||
self.con.commit()
|
||||
# We also need to clean the cache to make sure no pickeled objects still exist
|
||||
for db in [
|
||||
CONFIG.y("redis.message_queue_db"),
|
||||
CONFIG.y("redis.cache_db"),
|
||||
CONFIG.y("redis.ws_db"),
|
||||
]:
|
||||
redis = Redis(
|
||||
host=CONFIG.y("redis.host"),
|
||||
port=6379,
|
||||
db=db,
|
||||
password=CONFIG.y("redis.password"),
|
||||
)
|
||||
redis.flushall()
|
@ -1,3 +1,3 @@
|
||||
package pkg
|
||||
|
||||
const VERSION = "0.13.0-rc1"
|
||||
const VERSION = "0.13.0-rc3"
|
||||
|
@ -142,7 +142,7 @@ class TestSourceOAuth2(SeleniumTestCase):
|
||||
|
||||
# Wait until we've logged in
|
||||
self.wait_for_url(self.shell_url("authentik_core:overview"))
|
||||
self.driver.get(self.url("authentik_core:user-settings"))
|
||||
self.driver.get(self.url("authentik_core:user-details"))
|
||||
|
||||
self.assertEqual(
|
||||
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
|
||||
@ -224,7 +224,7 @@ class TestSourceOAuth2(SeleniumTestCase):
|
||||
|
||||
# Wait until we've logged in
|
||||
self.wait_for_url(self.shell_url("authentik_core:overview"))
|
||||
self.driver.get(self.url("authentik_core:user-settings"))
|
||||
self.driver.get(self.url("authentik_core:user-details"))
|
||||
|
||||
self.assertEqual(
|
||||
self.driver.find_element(By.ID, "id_username").get_attribute("value"), "foo"
|
||||
@ -317,7 +317,7 @@ class TestSourceOAuth1(SeleniumTestCase):
|
||||
sleep(2)
|
||||
# Wait until we've logged in
|
||||
self.wait_for_url(self.shell_url("authentik_core:overview"))
|
||||
self.driver.get(self.url("authentik_core:user-settings"))
|
||||
self.driver.get(self.url("authentik_core:user-details"))
|
||||
|
||||
self.assertEqual(
|
||||
self.driver.find_element(By.ID, "id_username").get_attribute("value"),
|
||||
|
@ -134,7 +134,7 @@ class TestSourceSAML(SeleniumTestCase):
|
||||
|
||||
# Wait until we're logged in
|
||||
self.wait_for_url(self.shell_url("authentik_core:overview"))
|
||||
self.driver.get(self.url("authentik_core:user-settings"))
|
||||
self.driver.get(self.url("authentik_core:user-details"))
|
||||
|
||||
# Wait until we've loaded the user info page
|
||||
self.assertNotEqual(
|
||||
@ -185,7 +185,7 @@ class TestSourceSAML(SeleniumTestCase):
|
||||
|
||||
# Wait until we're logged in
|
||||
self.wait_for_url(self.shell_url("authentik_core:overview"))
|
||||
self.driver.get(self.url("authentik_core:user-settings"))
|
||||
self.driver.get(self.url("authentik_core:user-details"))
|
||||
|
||||
# Wait until we've loaded the user info page
|
||||
self.assertNotEqual(
|
||||
@ -234,7 +234,7 @@ class TestSourceSAML(SeleniumTestCase):
|
||||
|
||||
# Wait until we're logged in
|
||||
self.wait_for_url(self.shell_url("authentik_core:overview"))
|
||||
self.driver.get(self.url("authentik_core:user-settings"))
|
||||
self.driver.get(self.url("authentik_core:user-details"))
|
||||
|
||||
# Wait until we've loaded the user info page
|
||||
self.assertNotEqual(
|
||||
|
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 7.3 KiB |
Before Width: | Height: | Size: 2.5 KiB After Width: | Height: | Size: 2.5 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 5.0 KiB |
@ -16,7 +16,7 @@ const resources = [
|
||||
{ src: "src/index.html", dest: "dist" },
|
||||
{ src: "src/authentik.css", dest: "dist" },
|
||||
{ src: "src/assets/*", dest: "dist/assets" },
|
||||
{ src: "../icons/*", dest: "dist/assets/icons" },
|
||||
{ src: "./icons/*", dest: "dist/assets/icons" },
|
||||
];
|
||||
|
||||
export default [
|
||||
|
@ -2,6 +2,7 @@ import { DefaultClient } from "./client";
|
||||
import * as Sentry from "@sentry/browser";
|
||||
import { Integrations } from "@sentry/tracing";
|
||||
import { VERSION } from "../constants";
|
||||
import { SentryIgnoredError } from "../common/errors";
|
||||
|
||||
export class Config {
|
||||
branding_logo: string;
|
||||
@ -24,6 +25,12 @@ export class Config {
|
||||
integrations: [new Integrations.BrowserTracing()],
|
||||
tracesSampleRate: 1.0,
|
||||
environment: config.error_reporting_environment,
|
||||
beforeSend(event: Sentry.Event, hint: Sentry.EventHint) {
|
||||
if (hint.originalException instanceof SentryIgnoredError) {
|
||||
return null;
|
||||
}
|
||||
return event;
|
||||
},
|
||||
});
|
||||
console.debug("authentik/config: Sentry enabled.");
|
||||
}
|
||||
|
1
web/src/common/errors.ts
Normal file
@ -0,0 +1 @@
|
||||
export class SentryIgnoredError extends Error {}
|
@ -28,4 +28,4 @@ export const ColorStyles = css`
|
||||
background-color: var(--pf-global--danger-color--100);
|
||||
}
|
||||
`;
|
||||
export const VERSION = "0.13.0-rc1";
|
||||
export const VERSION = "0.13.0-rc3";
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { css, CSSResult, customElement, html, LitElement, property, TemplateResult } from "lit-element";
|
||||
import Chart from "chart.js";
|
||||
import { showMessage } from "./messages/MessageContainer";
|
||||
|
||||
interface TickValue {
|
||||
value: number;
|
||||
@ -41,7 +42,13 @@ export class AdminLoginsChart extends LitElement {
|
||||
firstUpdated(): void {
|
||||
fetch(this.url)
|
||||
.then((r) => r.json())
|
||||
.catch((e) => console.error(e))
|
||||
.catch((e) => {
|
||||
showMessage({
|
||||
level_tag: "error",
|
||||
message: "Unexpected error"
|
||||
});
|
||||
console.log(e);
|
||||
})
|
||||
.then((r) => {
|
||||
const canvas = <HTMLCanvasElement>this.shadowRoot?.querySelector("canvas");
|
||||
if (!canvas) {
|
||||
|
@ -13,6 +13,7 @@ import fa from "@fortawesome/fontawesome-free/css/solid.css";
|
||||
import { convertToSlug } from "../../utils";
|
||||
import { SpinnerButton } from "./SpinnerButton";
|
||||
import { PRIMARY_CLASS } from "../../constants";
|
||||
import { showMessage } from "../messages/MessageContainer";
|
||||
|
||||
@customElement("ak-modal-button")
|
||||
export class ModalButton extends LitElement {
|
||||
@ -63,15 +64,21 @@ export class ModalButton extends LitElement {
|
||||
});
|
||||
// Make name field update slug field
|
||||
this.querySelectorAll<HTMLInputElement>("input[name=name]").forEach((input) => {
|
||||
const form = input.closest("form");
|
||||
if (form === null) {
|
||||
return;
|
||||
}
|
||||
const slugField = form.querySelector<HTMLInputElement>("input[name=slug]");
|
||||
if (!slugField) {
|
||||
return;
|
||||
}
|
||||
// Only attach handler if the slug is already equal to the name
|
||||
// if not, they are probably completely different and shouldn't update
|
||||
// each other
|
||||
if (convertToSlug(input.value) !== slugField.value) {
|
||||
return;
|
||||
}
|
||||
input.addEventListener("input", () => {
|
||||
const form = input.closest("form");
|
||||
if (form === null) {
|
||||
return;
|
||||
}
|
||||
const slugField = form.querySelector<HTMLInputElement>("input[name=slug]");
|
||||
if (!slugField) {
|
||||
return;
|
||||
}
|
||||
slugField.value = convertToSlug(input.value);
|
||||
});
|
||||
});
|
||||
@ -110,7 +117,11 @@ export class ModalButton extends LitElement {
|
||||
}
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
showMessage({
|
||||
level_tag: "error",
|
||||
message: "Unexpected error"
|
||||
});
|
||||
console.log(e);
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -139,7 +150,11 @@ export class ModalButton extends LitElement {
|
||||
});
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e);
|
||||
showMessage({
|
||||
level_tag: "error",
|
||||
message: "Unexpected error"
|
||||
});
|
||||
console.log(e);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,20 +1,6 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<link
|
||||
rel="preload"
|
||||
href="/static/authentik/fonts/DINEngschriftStd.woff2"
|
||||
as="font"
|
||||
type="font/woff2"
|
||||
crossorigin
|
||||
/>
|
||||
<link
|
||||
rel="preload"
|
||||
href="/static/authentik/fonts/DINEngschriftStd.woff"
|
||||
as="font"
|
||||
type="font/woff"
|
||||
crossorigin
|
||||
/>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
|
||||
<title>authentik</title>
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { LitElement, html, customElement, property, TemplateResult } from "lit-element";
|
||||
import { SentryIgnoredError } from "../../common/errors";
|
||||
|
||||
enum ResponseType {
|
||||
redirect = "redirect",
|
||||
@ -30,7 +31,7 @@ export class FlowShellCard extends LitElement {
|
||||
// Fallback when the flow does not exist, just redirect to the root
|
||||
window.location.pathname = "/";
|
||||
} else if (!r.ok) {
|
||||
throw Error(r.statusText);
|
||||
throw new SentryIgnoredError(r.statusText);
|
||||
}
|
||||
return r;
|
||||
})
|
||||
|
@ -8,6 +8,7 @@ import BackdropStyle from "@patternfly/patternfly/components/Backdrop/backdrop.c
|
||||
import { SpinnerSize } from "../../elements/Spinner";
|
||||
import { showMessage } from "../../elements/messages/MessageContainer";
|
||||
import { gettext } from "django";
|
||||
import { SentryIgnoredError } from "../../common/errors";
|
||||
|
||||
@customElement("ak-site-shell")
|
||||
export class SiteShell extends LitElement {
|
||||
@ -55,9 +56,16 @@ export class SiteShell extends LitElement {
|
||||
}
|
||||
|
||||
loadContent(): void {
|
||||
const bodySlot = this.querySelector("[slot=body]");
|
||||
if (!bodySlot) {
|
||||
return;
|
||||
}
|
||||
if (!this._url) {
|
||||
return;
|
||||
}
|
||||
if (this.loading) {
|
||||
return;
|
||||
}
|
||||
this.loading = true;
|
||||
fetch(this._url)
|
||||
.then((r) => {
|
||||
@ -70,52 +78,82 @@ export class SiteShell extends LitElement {
|
||||
level_tag: "error",
|
||||
message: gettext(`Request failed: ${r.statusText}`),
|
||||
});
|
||||
throw new Error("Request failed");
|
||||
this.loading = false;
|
||||
throw new SentryIgnoredError("Request failed");
|
||||
})
|
||||
.then((r) => r.text())
|
||||
.then((t) => {
|
||||
const bodySlot = this.querySelector("[slot=body]");
|
||||
if (!bodySlot) {
|
||||
return;
|
||||
}
|
||||
bodySlot.innerHTML = t;
|
||||
.then((text) => {
|
||||
bodySlot.innerHTML = text;
|
||||
this.updateHandlers();
|
||||
})
|
||||
.then(() => {
|
||||
// Ensure anchors only change the hash
|
||||
this.querySelectorAll<HTMLAnchorElement>("a:not(.ak-root-link)").forEach((a) => {
|
||||
if (a.href === "") {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const url = new URL(a.href);
|
||||
const qs = url.search || "";
|
||||
a.href = `#${url.pathname}${qs}`;
|
||||
} catch (e) {
|
||||
console.debug(`authentik/site-shell: error ${e}`);
|
||||
a.href = `#${a.href}`;
|
||||
}
|
||||
});
|
||||
// Create refresh buttons
|
||||
this.querySelectorAll("[role=ak-refresh]").forEach((rt) => {
|
||||
rt.addEventListener("click", () => {
|
||||
this.loadContent();
|
||||
});
|
||||
});
|
||||
// Make get forms (search bar) notify us on submit so we can change the hash
|
||||
this.querySelectorAll("form").forEach((f) => {
|
||||
f.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(f);
|
||||
const qs = new URLSearchParams((<any>formData)).toString(); // eslint-disable-line
|
||||
window.location.hash = `#${this._url}?${qs}`;
|
||||
});
|
||||
});
|
||||
setTimeout(() => {
|
||||
this.loading = false;
|
||||
}, 100);
|
||||
});
|
||||
}
|
||||
|
||||
updateHandlers(): void {
|
||||
// Ensure anchors only change the hash
|
||||
this.querySelectorAll<HTMLAnchorElement>("a:not(.ak-root-link)").forEach((a) => {
|
||||
if (a.href === "") {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
const url = new URL(a.href);
|
||||
const qs = url.search || "";
|
||||
a.href = `#${url.pathname}${qs}`;
|
||||
} catch (e) {
|
||||
console.debug(`authentik/site-shell: error ${e}`);
|
||||
a.href = `#${a.href}`;
|
||||
}
|
||||
});
|
||||
// Create refresh buttons
|
||||
this.querySelectorAll("[role=ak-refresh]").forEach((rt) => {
|
||||
rt.addEventListener("click", () => {
|
||||
this.loadContent();
|
||||
});
|
||||
});
|
||||
// Make get forms (search bar) notify us on submit so we can change the hash
|
||||
this.querySelectorAll<HTMLFormElement>("form[method=get]").forEach((form) => {
|
||||
form.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(form);
|
||||
const qs = new URLSearchParams((<any>formData)).toString(); // eslint-disable-line
|
||||
window.location.hash = `#${this._url}?${qs}`;
|
||||
});
|
||||
});
|
||||
// Make forms with POST Method have a correct action set
|
||||
this.querySelectorAll<HTMLFormElement>("form[method=post]").forEach((form) => {
|
||||
form.addEventListener("submit", (e) => {
|
||||
e.preventDefault();
|
||||
const formData = new FormData(form);
|
||||
fetch(this._url ? this._url : form.action, {
|
||||
method: form.method,
|
||||
body: formData,
|
||||
})
|
||||
.then((response) => {
|
||||
return response.text();
|
||||
})
|
||||
.then((data) => {
|
||||
const bodySlot = this.querySelector("[slot=body]");
|
||||
if (!bodySlot) {
|
||||
return;
|
||||
}
|
||||
bodySlot.innerHTML = data;
|
||||
this.updateHandlers();
|
||||
})
|
||||
.catch((e) => {
|
||||
showMessage({
|
||||
level_tag: "error",
|
||||
message: "Unexpected error"
|
||||
});
|
||||
console.log(e);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
render(): TemplateResult {
|
||||
return html` ${this.loading ?
|
||||
html`<div class="pf-c-backdrop">
|
||||
|
@ -15,7 +15,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=0.13.0-rc1 >> .env`
|
||||
To optionally deploy a different version run `echo AUTHENTIK_TAG=0.13.0-rc3 >> .env`
|
||||
|
||||
If this is a fresh authentik install run the following commands to generate a password:
|
||||
|
||||
|
@ -22,7 +22,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: 0.13.0-rc1
|
||||
tag: 0.13.0-rc3
|
||||
|
||||
serverReplicas: 1
|
||||
workerReplicas: 1
|
||||
|
@ -4,6 +4,21 @@ title: Upgrading to 0.13 (passbook -> authentik)
|
||||
|
||||
After a long back and forth, we've finally switched to a more permanent name. Whilst the upgrade is pretty much seamless, there are some things you have to change before upgrading.
|
||||
|
||||
# Headline changes
|
||||
|
||||
- New name (https://github.com/BeryJu/authentik/pull/361)
|
||||
- The web interface is now a semi-SPA Experience. This means that most operations are done through Asynchronous requests
|
||||
|
||||
In this initial release, this brings features such as a refresh button, a generally better User experience due to shorter loading times
|
||||
and fewer visual context changes.
|
||||
|
||||
- The web interface now has a darkmode, which is enabled automatically based on your Operating system.
|
||||
|
||||
## Smaller changes
|
||||
|
||||
- Add better support for Docker Service Connections with Certificates
|
||||
- Fix application API not returning the same format as other APIs
|
||||
|
||||
## Upgrading
|
||||
|
||||
### docker-compose
|
||||
@ -30,7 +45,7 @@ helm repo remove passbook
|
||||
helm repo add authentik https://docker.beryju.org/chartrepo/authentik
|
||||
```
|
||||
|
||||
:::notice
|
||||
:::note
|
||||
If you've set any custom image names in your values file, make sure to change them to authentik before upgrading.
|
||||
:::
|
||||
|
||||
@ -51,7 +66,7 @@ helm upgrade passbook authentik/authentik --devel -f values.yaml
|
||||
|
||||
- Some default values change, for example the SAML Provider's default issuer.
|
||||
|
||||
This only makes a difference for newly created objects.
|
||||
This only makes a difference for newly created providers.
|
||||
|
||||
- Expression Policies variables change
|
||||
|
||||
|