Merge branch 'master' into stage-challenge
This commit is contained in:
commit
d2dfc6d63b
|
@ -30,7 +30,11 @@ def event_notification_handler(event_uuid: str):
|
||||||
@CELERY_APP.task()
|
@CELERY_APP.task()
|
||||||
def event_trigger_handler(event_uuid: str, trigger_name: str):
|
def event_trigger_handler(event_uuid: str, trigger_name: str):
|
||||||
"""Check if policies attached to NotificationRule match event"""
|
"""Check if policies attached to NotificationRule match event"""
|
||||||
event: Event = Event.objects.get(event_uuid=event_uuid)
|
events = Event.objects.filter(event_uuid=event_uuid)
|
||||||
|
if not events.exists():
|
||||||
|
LOGGER.warning("event doesn't exist yet or anymore", event_uuid=event_uuid)
|
||||||
|
return
|
||||||
|
event: Event = events.first()
|
||||||
trigger: NotificationRule = NotificationRule.objects.get(name=trigger_name)
|
trigger: NotificationRule = NotificationRule.objects.get(name=trigger_name)
|
||||||
|
|
||||||
if "policy_uuid" in event.context:
|
if "policy_uuid" in event.context:
|
||||||
|
|
|
@ -24,6 +24,6 @@ def pbflow_tester(file_name: str) -> Callable:
|
||||||
return tester
|
return tester
|
||||||
|
|
||||||
|
|
||||||
for flow_file in glob("website/static/flows/*.pbflow"):
|
for flow_file in glob("website/static/flows/*.akflow"):
|
||||||
method_name = Path(flow_file).stem.replace("-", "_").replace(".", "_")
|
method_name = Path(flow_file).stem.replace("-", "_").replace(".", "_")
|
||||||
setattr(TestTransferDocs, f"test_flow_{method_name}", pbflow_tester(flow_file))
|
setattr(TestTransferDocs, f"test_flow_{method_name}", pbflow_tester(flow_file))
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
from authentik.core.models import Group
|
||||||
from authentik.lib.widgets import GroupedModelChoiceField
|
from authentik.lib.widgets import GroupedModelChoiceField
|
||||||
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel
|
from authentik.policies.models import Policy, PolicyBinding, PolicyBindingModel
|
||||||
|
|
||||||
|
@ -16,6 +17,9 @@ class PolicyBindingForm(forms.ModelForm):
|
||||||
policy = GroupedModelChoiceField(
|
policy = GroupedModelChoiceField(
|
||||||
queryset=Policy.objects.all().select_subclasses(), required=False
|
queryset=Policy.objects.all().select_subclasses(), required=False
|
||||||
)
|
)
|
||||||
|
group = forms.ModelChoiceField(
|
||||||
|
queryset=Group.objects.all().order_by("name"), required=False
|
||||||
|
)
|
||||||
|
|
||||||
def __init__(self, *args, **kwargs): # pragma: no cover
|
def __init__(self, *args, **kwargs): # pragma: no cover
|
||||||
super().__init__(*args, **kwargs)
|
super().__init__(*args, **kwargs)
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
|
|
||||||
from django import forms
|
from django import forms
|
||||||
|
|
||||||
|
from authentik.core.models import Group
|
||||||
from authentik.policies.forms import PolicyForm
|
from authentik.policies.forms import PolicyForm
|
||||||
from authentik.policies.group_membership.models import GroupMembershipPolicy
|
from authentik.policies.group_membership.models import GroupMembershipPolicy
|
||||||
|
|
||||||
|
@ -9,6 +10,8 @@ from authentik.policies.group_membership.models import GroupMembershipPolicy
|
||||||
class GroupMembershipPolicyForm(PolicyForm):
|
class GroupMembershipPolicyForm(PolicyForm):
|
||||||
"""GroupMembershipPolicy Form"""
|
"""GroupMembershipPolicy Form"""
|
||||||
|
|
||||||
|
group = forms.ModelChoiceField(queryset=Group.objects.all().order_by("name"))
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
|
|
||||||
model = GroupMembershipPolicy
|
model = GroupMembershipPolicy
|
||||||
|
|
|
@ -4,6 +4,7 @@ import binascii
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
from dataclasses import asdict, dataclass, field
|
from dataclasses import asdict, dataclass, field
|
||||||
|
from datetime import datetime
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from typing import Any, Optional, Type
|
from typing import Any, Optional, Type
|
||||||
from urllib.parse import urlparse
|
from urllib.parse import urlparse
|
||||||
|
@ -480,10 +481,14 @@ class RefreshToken(ExpiringModel, BaseGrantModel):
|
||||||
now + timedelta_from_string(self.provider.token_validity).seconds
|
now + timedelta_from_string(self.provider.token_validity).seconds
|
||||||
)
|
)
|
||||||
# We use the timestamp of the user's last successful login (EventAction.LOGIN) for auth_time
|
# We use the timestamp of the user's last successful login (EventAction.LOGIN) for auth_time
|
||||||
auth_event = Event.objects.filter(
|
auth_events = Event.objects.filter(
|
||||||
action=EventAction.LOGIN, user=get_user(user)
|
action=EventAction.LOGIN, user=get_user(user)
|
||||||
).latest("created")
|
).order_by("-created")
|
||||||
auth_time = int(dateformat.format(auth_event.created, "U"))
|
# Fallback in case we can't find any login events
|
||||||
|
auth_time = datetime.now()
|
||||||
|
if auth_events.exists():
|
||||||
|
auth_time = auth_events.first().created
|
||||||
|
auth_time = int(dateformat.format(auth_time, "U"))
|
||||||
|
|
||||||
token = IDToken(
|
token = IDToken(
|
||||||
iss=self.provider.get_issuer(request),
|
iss=self.provider.get_issuer(request),
|
||||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 1.3 MiB |
|
@ -1,7 +0,0 @@
|
||||||
---
|
|
||||||
title: Dummy stage
|
|
||||||
---
|
|
||||||
|
|
||||||
This stage is used for development and has no function. It presents the user with a form which requires a single confirmation.
|
|
||||||
|
|
||||||
![](dummy.png)
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
---
|
||||||
|
title: Troubleshooting Login problems
|
||||||
|
---
|
||||||
|
|
||||||
|
In case you can't login anymore, perhaps due to an incorrectly configured stage or a failed flow import, you can create a recovery key.
|
||||||
|
|
||||||
|
:::caution
|
||||||
|
This recovery key will give whoever has the link direct access to your instances. Keep this key safe.
|
||||||
|
:::
|
||||||
|
|
||||||
|
To create the key, run the following command:
|
||||||
|
|
||||||
|
```
|
||||||
|
docker-compose run --rm server create_recovery_key 10 akadmin
|
||||||
|
```
|
||||||
|
|
||||||
|
or, for Kubernetes, run
|
||||||
|
|
||||||
|
```
|
||||||
|
kubectl exec -it authentik-web-<hash> -- ./manage.py create_recovery_key 10 akadmin
|
||||||
|
```
|
||||||
|
|
||||||
|
This will output a link, that can be used to instantly gain access to authentik as the user specified above. The link is valid for amount of years specified above, in this case, 10 years.
|
|
@ -50,7 +50,6 @@ module.exports = {
|
||||||
"flow/stages/authenticator_totp/index",
|
"flow/stages/authenticator_totp/index",
|
||||||
"flow/stages/authenticator_validate/index",
|
"flow/stages/authenticator_validate/index",
|
||||||
"flow/stages/captcha/index",
|
"flow/stages/captcha/index",
|
||||||
"flow/stages/dummy/index",
|
|
||||||
"flow/stages/email/index",
|
"flow/stages/email/index",
|
||||||
"flow/stages/identification/index",
|
"flow/stages/identification/index",
|
||||||
"flow/stages/invitation/index",
|
"flow/stages/invitation/index",
|
||||||
|
@ -150,6 +149,7 @@ module.exports = {
|
||||||
items: [
|
items: [
|
||||||
"troubleshooting/access",
|
"troubleshooting/access",
|
||||||
"troubleshooting/emails",
|
"troubleshooting/emails",
|
||||||
|
"troubleshooting/login",
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|
Reference in New Issue