stages/authenticator_sms: Add SMS Authenticator Stage (#1577)
* stages/authenticator_sms: initial implementation Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: add initial stage UI Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/elements: clear invalid state when old input was invalid but new input is correct Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * stages/authenticator_sms: add more logic Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/user: add basic SMS settings Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * stages/authenticator_sms: initial working version Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * stages/authenticator_sms: add tests Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/flows: optimise totp password manager entry on authenticator_validation stage Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/elements: add grouping support for table Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: allow sms class in authenticator stage Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web/admin: add grouping to more pages Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * stages/authenticator_validate: add SMS support Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * api: add throttling for flow executor based on session key and pending user Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * web: fix style issues Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org> * ci: add workflow to compile backend translations Signed-off-by: Jens Langhammer <jens.langhammer@beryju.org>
This commit is contained in:
parent
7bf587af24
commit
aef9d27706
|
@ -0,0 +1,43 @@
|
||||||
|
name: authentik-backend-translate-compile
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [ master ]
|
||||||
|
paths:
|
||||||
|
- '/locale/'
|
||||||
|
schedule:
|
||||||
|
- cron: "*/15 * * * *"
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
env:
|
||||||
|
POSTGRES_DB: authentik
|
||||||
|
POSTGRES_USER: authentik
|
||||||
|
POSTGRES_PASSWORD: "EK-5jnKfjrGRm<77"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
compile:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v2
|
||||||
|
- uses: actions/setup-python@v2
|
||||||
|
with:
|
||||||
|
python-version: '3.9'
|
||||||
|
- id: cache-pipenv
|
||||||
|
uses: actions/cache@v2.1.6
|
||||||
|
with:
|
||||||
|
path: ~/.local/share/virtualenvs
|
||||||
|
key: ${{ runner.os }}-pipenv-v2-${{ hashFiles('**/Pipfile.lock') }}
|
||||||
|
- name: prepare
|
||||||
|
env:
|
||||||
|
INSTALL: ${{ steps.cache-pipenv.outputs.cache-hit }}
|
||||||
|
run: scripts/ci_prepare.sh
|
||||||
|
- name: run pylint
|
||||||
|
run: pipenv run ./manage.py compilemessages
|
||||||
|
- name: Create Pull Request
|
||||||
|
uses: peter-evans/create-pull-request@v3
|
||||||
|
with:
|
||||||
|
token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
branch: compile-backend-translation
|
||||||
|
commit-message: "core: compile backend translations"
|
||||||
|
title: "core: compile backend translations"
|
||||||
|
delete-branch: true
|
||||||
|
signoff: true
|
2
Makefile
2
Makefile
|
@ -73,4 +73,4 @@ migrate:
|
||||||
python -m lifecycle.migrate
|
python -m lifecycle.migrate
|
||||||
|
|
||||||
run:
|
run:
|
||||||
WORKERS=1 go run -v cmd/server/main.go
|
go run -v cmd/server/main.go
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
"""Throttling classes"""
|
||||||
|
from typing import Type
|
||||||
|
|
||||||
|
from django.views import View
|
||||||
|
from rest_framework.request import Request
|
||||||
|
from rest_framework.throttling import ScopedRateThrottle
|
||||||
|
|
||||||
|
|
||||||
|
class SessionThrottle(ScopedRateThrottle):
|
||||||
|
"""Throttle based on session key"""
|
||||||
|
|
||||||
|
def allow_request(self, request: Request, view):
|
||||||
|
if request._request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
return super().allow_request(request, view)
|
||||||
|
|
||||||
|
def get_cache_key(self, request: Request, view: Type[View]) -> str:
|
||||||
|
return f"authentik-throttle-session-{request._request.session.session_key}"
|
|
@ -68,6 +68,11 @@ from authentik.stages.authenticator_duo.api import (
|
||||||
DuoAdminDeviceViewSet,
|
DuoAdminDeviceViewSet,
|
||||||
DuoDeviceViewSet,
|
DuoDeviceViewSet,
|
||||||
)
|
)
|
||||||
|
from authentik.stages.authenticator_sms.api import (
|
||||||
|
AuthenticatorSMSStageViewSet,
|
||||||
|
SMSAdminDeviceViewSet,
|
||||||
|
SMSDeviceViewSet,
|
||||||
|
)
|
||||||
from authentik.stages.authenticator_static.api import (
|
from authentik.stages.authenticator_static.api import (
|
||||||
AuthenticatorStaticStageViewSet,
|
AuthenticatorStaticStageViewSet,
|
||||||
StaticAdminDeviceViewSet,
|
StaticAdminDeviceViewSet,
|
||||||
|
@ -165,6 +170,7 @@ router.register("propertymappings/scope", ScopeMappingViewSet)
|
||||||
router.register("propertymappings/notification", NotificationWebhookMappingViewSet)
|
router.register("propertymappings/notification", NotificationWebhookMappingViewSet)
|
||||||
|
|
||||||
router.register("authenticators/duo", DuoDeviceViewSet)
|
router.register("authenticators/duo", DuoDeviceViewSet)
|
||||||
|
router.register("authenticators/sms", SMSDeviceViewSet)
|
||||||
router.register("authenticators/static", StaticDeviceViewSet)
|
router.register("authenticators/static", StaticDeviceViewSet)
|
||||||
router.register("authenticators/totp", TOTPDeviceViewSet)
|
router.register("authenticators/totp", TOTPDeviceViewSet)
|
||||||
router.register("authenticators/webauthn", WebAuthnDeviceViewSet)
|
router.register("authenticators/webauthn", WebAuthnDeviceViewSet)
|
||||||
|
@ -173,6 +179,11 @@ router.register(
|
||||||
DuoAdminDeviceViewSet,
|
DuoAdminDeviceViewSet,
|
||||||
basename="admin-duodevice",
|
basename="admin-duodevice",
|
||||||
)
|
)
|
||||||
|
router.register(
|
||||||
|
"authenticators/admin/sms",
|
||||||
|
SMSAdminDeviceViewSet,
|
||||||
|
basename="admin-smsdevice",
|
||||||
|
)
|
||||||
router.register(
|
router.register(
|
||||||
"authenticators/admin/static",
|
"authenticators/admin/static",
|
||||||
StaticAdminDeviceViewSet,
|
StaticAdminDeviceViewSet,
|
||||||
|
@ -187,6 +198,7 @@ router.register(
|
||||||
|
|
||||||
router.register("stages/all", StageViewSet)
|
router.register("stages/all", StageViewSet)
|
||||||
router.register("stages/authenticator/duo", AuthenticatorDuoStageViewSet)
|
router.register("stages/authenticator/duo", AuthenticatorDuoStageViewSet)
|
||||||
|
router.register("stages/authenticator/sms", AuthenticatorSMSStageViewSet)
|
||||||
router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet)
|
router.register("stages/authenticator/static", AuthenticatorStaticStageViewSet)
|
||||||
router.register("stages/authenticator/totp", AuthenticatorTOTPStageViewSet)
|
router.register("stages/authenticator/totp", AuthenticatorTOTPStageViewSet)
|
||||||
router.register("stages/authenticator/validate", AuthenticatorValidateStageViewSet)
|
router.register("stages/authenticator/validate", AuthenticatorValidateStageViewSet)
|
||||||
|
|
|
@ -17,10 +17,13 @@ from django.views.generic import View
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema
|
from drf_spectacular.utils import OpenApiParameter, PolymorphicProxySerializer, extend_schema
|
||||||
from rest_framework.permissions import AllowAny
|
from rest_framework.permissions import AllowAny
|
||||||
|
from rest_framework.request import Request
|
||||||
|
from rest_framework.throttling import ScopedRateThrottle
|
||||||
from rest_framework.views import APIView
|
from rest_framework.views import APIView
|
||||||
from sentry_sdk import capture_exception
|
from sentry_sdk import capture_exception
|
||||||
from structlog.stdlib import BoundLogger, get_logger
|
from structlog.stdlib import BoundLogger, get_logger
|
||||||
|
|
||||||
|
from authentik.api.throttle import SessionThrottle
|
||||||
from authentik.core.models import USER_ATTRIBUTE_DEBUG
|
from authentik.core.models import USER_ATTRIBUTE_DEBUG
|
||||||
from authentik.events.models import Event, EventAction, cleanse_dict
|
from authentik.events.models import Event, EventAction, cleanse_dict
|
||||||
from authentik.flows.challenge import (
|
from authentik.flows.challenge import (
|
||||||
|
@ -97,10 +100,33 @@ class InvalidStageError(SentryIgnoredException):
|
||||||
"""Error raised when a challenge from a stage is not valid"""
|
"""Error raised when a challenge from a stage is not valid"""
|
||||||
|
|
||||||
|
|
||||||
|
class FlowPendingUserThrottle(ScopedRateThrottle):
|
||||||
|
"""Custom throttle based on which user is pending"""
|
||||||
|
|
||||||
|
def get_cache_key(self, request: Request, view) -> str:
|
||||||
|
if SESSION_KEY_PLAN not in request._request.session:
|
||||||
|
return ""
|
||||||
|
if PLAN_CONTEXT_PENDING_USER not in request._request.session[SESSION_KEY_PLAN].context:
|
||||||
|
return ""
|
||||||
|
user = request._request.session[SESSION_KEY_PLAN].context[PLAN_CONTEXT_PENDING_USER]
|
||||||
|
return f"authentik-throttle-flow-pending-{user.uid}"
|
||||||
|
|
||||||
|
def allow_request(self, request: Request, view) -> bool:
|
||||||
|
if SESSION_KEY_PLAN not in request._request.session:
|
||||||
|
return True
|
||||||
|
if PLAN_CONTEXT_PENDING_USER not in request._request.session[SESSION_KEY_PLAN].context:
|
||||||
|
return True
|
||||||
|
if request._request.user.is_superuser:
|
||||||
|
return True
|
||||||
|
return super().allow_request(request, view)
|
||||||
|
|
||||||
|
|
||||||
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
@method_decorator(xframe_options_sameorigin, name="dispatch")
|
||||||
class FlowExecutorView(APIView):
|
class FlowExecutorView(APIView):
|
||||||
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
"""Stage 1 Flow executor, passing requests to Stage Views"""
|
||||||
|
|
||||||
|
throttle_classes = [SessionThrottle, FlowPendingUserThrottle]
|
||||||
|
throttle_scope = "flow_executor"
|
||||||
permission_classes = [AllowAny]
|
permission_classes = [AllowAny]
|
||||||
|
|
||||||
flow: Flow
|
flow: Flow
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
# Generated by Django 3.2.8 on 2021-10-09 17:43
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_policies_event_matcher", "0018_alter_eventmatcherpolicy_action"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="eventmatcherpolicy",
|
||||||
|
name="app",
|
||||||
|
field=models.TextField(
|
||||||
|
blank=True,
|
||||||
|
choices=[
|
||||||
|
("authentik.admin", "authentik Admin"),
|
||||||
|
("authentik.api", "authentik API"),
|
||||||
|
("authentik.crypto", "authentik Crypto"),
|
||||||
|
("authentik.events", "authentik Events"),
|
||||||
|
("authentik.flows", "authentik Flows"),
|
||||||
|
("authentik.lib", "authentik lib"),
|
||||||
|
("authentik.outposts", "authentik Outpost"),
|
||||||
|
("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.hibp", "authentik Policies.HaveIBeenPwned"),
|
||||||
|
("authentik.policies.password", "authentik Policies.Password"),
|
||||||
|
("authentik.policies.reputation", "authentik Policies.Reputation"),
|
||||||
|
("authentik.policies", "authentik Policies"),
|
||||||
|
("authentik.providers.ldap", "authentik Providers.LDAP"),
|
||||||
|
("authentik.providers.oauth2", "authentik Providers.OAuth2"),
|
||||||
|
("authentik.providers.proxy", "authentik Providers.Proxy"),
|
||||||
|
("authentik.providers.saml", "authentik Providers.SAML"),
|
||||||
|
("authentik.recovery", "authentik Recovery"),
|
||||||
|
("authentik.sources.ldap", "authentik Sources.LDAP"),
|
||||||
|
("authentik.sources.oauth", "authentik Sources.OAuth"),
|
||||||
|
("authentik.sources.plex", "authentik Sources.Plex"),
|
||||||
|
("authentik.sources.saml", "authentik Sources.SAML"),
|
||||||
|
("authentik.stages.authenticator_duo", "authentik Stages.Authenticator.Duo"),
|
||||||
|
("authentik.stages.authenticator_sms", "authentik Stages.Authenticator.SMS"),
|
||||||
|
(
|
||||||
|
"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.tenants", "authentik Tenants"),
|
||||||
|
("authentik.core", "authentik Core"),
|
||||||
|
("authentik.managed", "authentik Managed"),
|
||||||
|
],
|
||||||
|
default="",
|
||||||
|
help_text="Match events created by selected application. When left empty, all applications are matched.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
]
|
|
@ -93,12 +93,11 @@ INSTALLED_APPS = [
|
||||||
"django.contrib.humanize",
|
"django.contrib.humanize",
|
||||||
"authentik.admin",
|
"authentik.admin",
|
||||||
"authentik.api",
|
"authentik.api",
|
||||||
"authentik.events",
|
|
||||||
"authentik.crypto",
|
"authentik.crypto",
|
||||||
|
"authentik.events",
|
||||||
"authentik.flows",
|
"authentik.flows",
|
||||||
"authentik.outposts",
|
|
||||||
"authentik.lib",
|
"authentik.lib",
|
||||||
"authentik.policies",
|
"authentik.outposts",
|
||||||
"authentik.policies.dummy",
|
"authentik.policies.dummy",
|
||||||
"authentik.policies.event_matcher",
|
"authentik.policies.event_matcher",
|
||||||
"authentik.policies.expiry",
|
"authentik.policies.expiry",
|
||||||
|
@ -106,9 +105,10 @@ INSTALLED_APPS = [
|
||||||
"authentik.policies.hibp",
|
"authentik.policies.hibp",
|
||||||
"authentik.policies.password",
|
"authentik.policies.password",
|
||||||
"authentik.policies.reputation",
|
"authentik.policies.reputation",
|
||||||
"authentik.providers.proxy",
|
"authentik.policies",
|
||||||
"authentik.providers.ldap",
|
"authentik.providers.ldap",
|
||||||
"authentik.providers.oauth2",
|
"authentik.providers.oauth2",
|
||||||
|
"authentik.providers.proxy",
|
||||||
"authentik.providers.saml",
|
"authentik.providers.saml",
|
||||||
"authentik.recovery",
|
"authentik.recovery",
|
||||||
"authentik.sources.ldap",
|
"authentik.sources.ldap",
|
||||||
|
@ -116,6 +116,7 @@ INSTALLED_APPS = [
|
||||||
"authentik.sources.plex",
|
"authentik.sources.plex",
|
||||||
"authentik.sources.saml",
|
"authentik.sources.saml",
|
||||||
"authentik.stages.authenticator_duo",
|
"authentik.stages.authenticator_duo",
|
||||||
|
"authentik.stages.authenticator_sms",
|
||||||
"authentik.stages.authenticator_static",
|
"authentik.stages.authenticator_static",
|
||||||
"authentik.stages.authenticator_totp",
|
"authentik.stages.authenticator_totp",
|
||||||
"authentik.stages.authenticator_validate",
|
"authentik.stages.authenticator_validate",
|
||||||
|
@ -204,6 +205,9 @@ REST_FRAMEWORK = {
|
||||||
],
|
],
|
||||||
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
"DEFAULT_SCHEMA_CLASS": "drf_spectacular.openapi.AutoSchema",
|
||||||
"TEST_REQUEST_DEFAULT_FORMAT": "json",
|
"TEST_REQUEST_DEFAULT_FORMAT": "json",
|
||||||
|
"DEFAULT_THROTTLE_RATES": {
|
||||||
|
"flow_executor": "100/day",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
REDIS_PROTOCOL_PREFIX = "redis://"
|
REDIS_PROTOCOL_PREFIX = "redis://"
|
||||||
|
|
|
@ -0,0 +1,79 @@
|
||||||
|
"""AuthenticatorSMSStage API Views"""
|
||||||
|
from django_filters.rest_framework.backends import DjangoFilterBackend
|
||||||
|
from rest_framework import mixins
|
||||||
|
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||||
|
from rest_framework.permissions import IsAdminUser
|
||||||
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
from rest_framework.viewsets import GenericViewSet, ModelViewSet, ReadOnlyModelViewSet
|
||||||
|
|
||||||
|
from authentik.api.authorization import OwnerFilter, OwnerPermissions
|
||||||
|
from authentik.core.api.used_by import UsedByMixin
|
||||||
|
from authentik.flows.api.stages import StageSerializer
|
||||||
|
from authentik.stages.authenticator_sms.models import AuthenticatorSMSStage, SMSDevice
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSStageSerializer(StageSerializer):
|
||||||
|
"""AuthenticatorSMSStage Serializer"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = AuthenticatorSMSStage
|
||||||
|
fields = StageSerializer.Meta.fields + [
|
||||||
|
"configure_flow",
|
||||||
|
"provider",
|
||||||
|
"from_number",
|
||||||
|
"twilio_account_sid",
|
||||||
|
"twilio_auth",
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSStageViewSet(UsedByMixin, ModelViewSet):
|
||||||
|
"""AuthenticatorSMSStage Viewset"""
|
||||||
|
|
||||||
|
queryset = AuthenticatorSMSStage.objects.all()
|
||||||
|
serializer_class = AuthenticatorSMSStageSerializer
|
||||||
|
filterset_fields = "__all__"
|
||||||
|
ordering = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class SMSDeviceSerializer(ModelSerializer):
|
||||||
|
"""Serializer for sms authenticator devices"""
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
model = SMSDevice
|
||||||
|
fields = ["name", "pk", "phone_number"]
|
||||||
|
depth = 2
|
||||||
|
extra_kwargs = {
|
||||||
|
"phone_number": {"read_only": True},
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class SMSDeviceViewSet(
|
||||||
|
mixins.RetrieveModelMixin,
|
||||||
|
mixins.UpdateModelMixin,
|
||||||
|
mixins.DestroyModelMixin,
|
||||||
|
UsedByMixin,
|
||||||
|
mixins.ListModelMixin,
|
||||||
|
GenericViewSet,
|
||||||
|
):
|
||||||
|
"""Viewset for sms authenticator devices"""
|
||||||
|
|
||||||
|
queryset = SMSDevice.objects.all()
|
||||||
|
serializer_class = SMSDeviceSerializer
|
||||||
|
permission_classes = [OwnerPermissions]
|
||||||
|
filter_backends = [OwnerFilter, DjangoFilterBackend, OrderingFilter, SearchFilter]
|
||||||
|
search_fields = ["name"]
|
||||||
|
filterset_fields = ["name"]
|
||||||
|
ordering = ["name"]
|
||||||
|
|
||||||
|
|
||||||
|
class SMSAdminDeviceViewSet(ReadOnlyModelViewSet):
|
||||||
|
"""Viewset for sms authenticator devices (for admins)"""
|
||||||
|
|
||||||
|
permission_classes = [IsAdminUser]
|
||||||
|
queryset = SMSDevice.objects.all()
|
||||||
|
serializer_class = SMSDeviceSerializer
|
||||||
|
search_fields = ["name"]
|
||||||
|
filterset_fields = ["name"]
|
||||||
|
ordering = ["name"]
|
|
@ -0,0 +1,10 @@
|
||||||
|
"""SMS"""
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class AuthentikStageAuthenticatorSMSConfig(AppConfig):
|
||||||
|
"""SMS App config"""
|
||||||
|
|
||||||
|
name = "authentik.stages.authenticator_sms"
|
||||||
|
label = "authentik_stages_authenticator_sms"
|
||||||
|
verbose_name = "authentik Stages.Authenticator.SMS"
|
|
@ -0,0 +1,100 @@
|
||||||
|
# Generated by Django 3.2.8 on 2021-10-09 19:15
|
||||||
|
|
||||||
|
import django.db.models.deletion
|
||||||
|
import django.utils.timezone
|
||||||
|
from django.conf import settings
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_flows", "0024_alter_flow_compatibility_mode"),
|
||||||
|
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="AuthenticatorSMSStage",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"stage_ptr",
|
||||||
|
models.OneToOneField(
|
||||||
|
auto_created=True,
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
parent_link=True,
|
||||||
|
primary_key=True,
|
||||||
|
serialize=False,
|
||||||
|
to="authentik_flows.stage",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("provider", models.TextField(choices=[("twilio", "Twilio")])),
|
||||||
|
("twilio_account_sid", models.TextField()),
|
||||||
|
("twilio_auth", models.TextField()),
|
||||||
|
(
|
||||||
|
"configure_flow",
|
||||||
|
models.ForeignKey(
|
||||||
|
blank=True,
|
||||||
|
help_text="Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage.",
|
||||||
|
null=True,
|
||||||
|
on_delete=django.db.models.deletion.SET_NULL,
|
||||||
|
to="authentik_flows.flow",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "SMS Authenticator Setup Stage",
|
||||||
|
"verbose_name_plural": "SMS Authenticator Setup Stages",
|
||||||
|
},
|
||||||
|
bases=("authentik_flows.stage", models.Model),
|
||||||
|
),
|
||||||
|
migrations.CreateModel(
|
||||||
|
name="SMSDevice",
|
||||||
|
fields=[
|
||||||
|
(
|
||||||
|
"id",
|
||||||
|
models.AutoField(
|
||||||
|
auto_created=True, primary_key=True, serialize=False, verbose_name="ID"
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"name",
|
||||||
|
models.CharField(
|
||||||
|
help_text="The human-readable name of this device.", max_length=64
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"confirmed",
|
||||||
|
models.BooleanField(default=True, help_text="Is this device ready for use?"),
|
||||||
|
),
|
||||||
|
("token", models.CharField(blank=True, max_length=16, null=True)),
|
||||||
|
(
|
||||||
|
"valid_until",
|
||||||
|
models.DateTimeField(
|
||||||
|
default=django.utils.timezone.now,
|
||||||
|
help_text="The timestamp of the moment of expiry of the saved token.",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
("phone_number", models.TextField()),
|
||||||
|
(
|
||||||
|
"stage",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE,
|
||||||
|
to="authentik_stages_authenticator_sms.authenticatorsmsstage",
|
||||||
|
),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"user",
|
||||||
|
models.ForeignKey(
|
||||||
|
on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
"verbose_name": "SMS Device",
|
||||||
|
"verbose_name_plural": "SMS Devices",
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,19 @@
|
||||||
|
# Generated by Django 3.2.8 on 2021-10-09 20:02
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
("authentik_stages_authenticator_sms", "0001_initial"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AddField(
|
||||||
|
model_name="authenticatorsmsstage",
|
||||||
|
name="from_number",
|
||||||
|
field=models.TextField(default=""),
|
||||||
|
preserve_default=False,
|
||||||
|
),
|
||||||
|
]
|
|
@ -0,0 +1,118 @@
|
||||||
|
"""OTP Time-based models"""
|
||||||
|
from typing import Optional, Type
|
||||||
|
|
||||||
|
from django.contrib.auth import get_user_model
|
||||||
|
from django.db import models
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from django.views import View
|
||||||
|
from django_otp.models import SideChannelDevice
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
from rest_framework.serializers import BaseSerializer
|
||||||
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.core.types import UserSettingSerializer
|
||||||
|
from authentik.flows.models import ConfigurableStage, Stage
|
||||||
|
from authentik.lib.utils.http import get_http_session
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
|
||||||
|
|
||||||
|
class SMSProviders(models.TextChoices):
|
||||||
|
"""Supported SMS Providers"""
|
||||||
|
|
||||||
|
TWILIO = "twilio"
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSStage(ConfigurableStage, Stage):
|
||||||
|
"""Use SMS-based TOTP instead of authenticator-based."""
|
||||||
|
|
||||||
|
provider = models.TextField(choices=SMSProviders.choices)
|
||||||
|
|
||||||
|
from_number = models.TextField()
|
||||||
|
|
||||||
|
twilio_account_sid = models.TextField()
|
||||||
|
twilio_auth = models.TextField()
|
||||||
|
|
||||||
|
def send(self, token: str, device: "SMSDevice"):
|
||||||
|
"""Send message via selected provider"""
|
||||||
|
if self.provider == SMSProviders.TWILIO:
|
||||||
|
return self.send_twilio(token, device)
|
||||||
|
raise ValueError(f"invalid provider {self.provider}")
|
||||||
|
|
||||||
|
def send_twilio(self, token: str, device: "SMSDevice"):
|
||||||
|
"""send sms via twilio provider"""
|
||||||
|
response = get_http_session().post(
|
||||||
|
f"https://api.twilio.com/2010-04-01/Accounts/{self.twilio_account_sid}/Messages.json",
|
||||||
|
data={
|
||||||
|
"From": self.from_number,
|
||||||
|
"To": device.phone_number,
|
||||||
|
"Body": token,
|
||||||
|
},
|
||||||
|
auth=(self.twilio_account_sid, self.twilio_auth),
|
||||||
|
)
|
||||||
|
LOGGER.debug("Sent SMS", to=device.phone_number)
|
||||||
|
try:
|
||||||
|
response.raise_for_status()
|
||||||
|
except RequestException as exc:
|
||||||
|
LOGGER.warning("Error sending token by Twilio SMS", exc=exc, body=response.text)
|
||||||
|
if response.status_code == 400:
|
||||||
|
raise ValidationError(response.json().get("message"))
|
||||||
|
raise
|
||||||
|
|
||||||
|
if "sid" not in response.json():
|
||||||
|
message = response.json().get("message")
|
||||||
|
LOGGER.warning("Error sending token by Twilio SMS", message=message)
|
||||||
|
raise Exception(message)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def serializer(self) -> BaseSerializer:
|
||||||
|
from authentik.stages.authenticator_sms.api import AuthenticatorSMSStageSerializer
|
||||||
|
|
||||||
|
return AuthenticatorSMSStageSerializer
|
||||||
|
|
||||||
|
@property
|
||||||
|
def type(self) -> Type[View]:
|
||||||
|
from authentik.stages.authenticator_sms.stage import AuthenticatorSMSStageView
|
||||||
|
|
||||||
|
return AuthenticatorSMSStageView
|
||||||
|
|
||||||
|
@property
|
||||||
|
def component(self) -> str:
|
||||||
|
return "ak-stage-authenticator-sms-form"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def ui_user_settings(self) -> Optional[UserSettingSerializer]:
|
||||||
|
return UserSettingSerializer(
|
||||||
|
data={
|
||||||
|
"title": str(self._meta.verbose_name),
|
||||||
|
"component": "ak-user-settings-authenticator-sms",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def __str__(self) -> str:
|
||||||
|
return f"SMS Authenticator Setup Stage {self.name}"
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("SMS Authenticator Setup Stage")
|
||||||
|
verbose_name_plural = _("SMS Authenticator Setup Stages")
|
||||||
|
|
||||||
|
|
||||||
|
class SMSDevice(SideChannelDevice):
|
||||||
|
"""SMS Device"""
|
||||||
|
|
||||||
|
user = models.ForeignKey(get_user_model(), on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
# Connect to the stage to when validating access we know the API Credentials
|
||||||
|
stage = models.ForeignKey(AuthenticatorSMSStage, on_delete=models.CASCADE)
|
||||||
|
|
||||||
|
phone_number = models.TextField()
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.name or str(self.user)
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
|
||||||
|
verbose_name = _("SMS Device")
|
||||||
|
verbose_name_plural = _("SMS Devices")
|
|
@ -0,0 +1,118 @@
|
||||||
|
"""SMS Setup stage"""
|
||||||
|
from typing import Optional
|
||||||
|
|
||||||
|
from django.http import HttpRequest, HttpResponse
|
||||||
|
from django.http.request import QueryDict
|
||||||
|
from django.utils.translation import gettext_lazy as _
|
||||||
|
from rest_framework.exceptions import ValidationError
|
||||||
|
from rest_framework.fields import BooleanField, CharField, IntegerField
|
||||||
|
from structlog.stdlib import get_logger
|
||||||
|
|
||||||
|
from authentik.flows.challenge import (
|
||||||
|
Challenge,
|
||||||
|
ChallengeResponse,
|
||||||
|
ChallengeTypes,
|
||||||
|
WithUserInfoChallenge,
|
||||||
|
)
|
||||||
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
|
from authentik.flows.stage import ChallengeStageView
|
||||||
|
from authentik.stages.authenticator_sms.models import AuthenticatorSMSStage, SMSDevice
|
||||||
|
from authentik.stages.prompt.stage import PLAN_CONTEXT_PROMPT
|
||||||
|
|
||||||
|
LOGGER = get_logger()
|
||||||
|
SESSION_SMS_DEVICE = "sms_device"
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSChallenge(WithUserInfoChallenge):
|
||||||
|
"""SMS Setup challenge"""
|
||||||
|
|
||||||
|
# Set to true if no previous prompt stage set the phone number
|
||||||
|
# this stage will also check prompt_data.phone
|
||||||
|
phone_number_required = BooleanField(default=True)
|
||||||
|
component = CharField(default="ak-stage-authenticator-sms")
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSChallengeResponse(ChallengeResponse):
|
||||||
|
"""SMS Challenge response, device is set by get_response_instance"""
|
||||||
|
|
||||||
|
device: SMSDevice
|
||||||
|
|
||||||
|
code = IntegerField(required=False)
|
||||||
|
phone_number = CharField(required=False)
|
||||||
|
|
||||||
|
component = CharField(default="ak-stage-authenticator-sms")
|
||||||
|
|
||||||
|
def validate(self, attrs: dict) -> dict:
|
||||||
|
"""Check"""
|
||||||
|
stage: AuthenticatorSMSStage = self.device.stage
|
||||||
|
if "code" not in attrs:
|
||||||
|
self.device.phone_number = attrs["phone_number"]
|
||||||
|
# No code yet, but we have a phone number, so send a verification message
|
||||||
|
stage.send(self.device.token, self.device)
|
||||||
|
return super().validate(attrs)
|
||||||
|
if not self.device.verify_token(str(attrs["code"])):
|
||||||
|
raise ValidationError(_("Code does not match"))
|
||||||
|
self.device.confirmed = True
|
||||||
|
return super().validate(attrs)
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSStageView(ChallengeStageView):
|
||||||
|
"""OTP sms Setup stage"""
|
||||||
|
|
||||||
|
response_class = AuthenticatorSMSChallengeResponse
|
||||||
|
|
||||||
|
def _has_phone_number(self) -> Optional[str]:
|
||||||
|
context = self.executor.plan.context
|
||||||
|
if "phone" in context.get(PLAN_CONTEXT_PROMPT, {}):
|
||||||
|
LOGGER.debug("got phone number from plan context")
|
||||||
|
return context.get(PLAN_CONTEXT_PROMPT, {}).get("phone")
|
||||||
|
if SESSION_SMS_DEVICE in self.request.session:
|
||||||
|
LOGGER.debug("got phone number from device in session")
|
||||||
|
device: SMSDevice = self.request.session[SESSION_SMS_DEVICE]
|
||||||
|
if device.phone_number == "":
|
||||||
|
return None
|
||||||
|
return device.phone_number
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_challenge(self, *args, **kwargs) -> Challenge:
|
||||||
|
return AuthenticatorSMSChallenge(
|
||||||
|
data={
|
||||||
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
|
"phone_number_required": self._has_phone_number() is None,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
def get_response_instance(self, data: QueryDict) -> ChallengeResponse:
|
||||||
|
response = super().get_response_instance(data)
|
||||||
|
response.device = self.request.session[SESSION_SMS_DEVICE]
|
||||||
|
return response
|
||||||
|
|
||||||
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
|
user = self.executor.plan.context.get(PLAN_CONTEXT_PENDING_USER)
|
||||||
|
if not user:
|
||||||
|
LOGGER.debug("No pending user, continuing")
|
||||||
|
return self.executor.stage_ok()
|
||||||
|
|
||||||
|
# Currently, this stage only supports one device per user. If the user already
|
||||||
|
# has a device, just skip to the next stage
|
||||||
|
if SMSDevice.objects.filter(user=user).exists():
|
||||||
|
return self.executor.stage_ok()
|
||||||
|
|
||||||
|
stage: AuthenticatorSMSStage = self.executor.current_stage
|
||||||
|
|
||||||
|
if SESSION_SMS_DEVICE not in self.request.session:
|
||||||
|
device = SMSDevice(user=user, confirmed=False, stage=stage)
|
||||||
|
device.generate_token(commit=False)
|
||||||
|
if phone_number := self._has_phone_number():
|
||||||
|
device.phone_number = phone_number
|
||||||
|
self.request.session[SESSION_SMS_DEVICE] = device
|
||||||
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
def challenge_valid(self, response: ChallengeResponse) -> HttpResponse:
|
||||||
|
"""SMS Token is validated by challenge"""
|
||||||
|
device: SMSDevice = self.request.session[SESSION_SMS_DEVICE]
|
||||||
|
if not device.confirmed:
|
||||||
|
return self.challenge_invalid(response)
|
||||||
|
device.save()
|
||||||
|
del self.request.session[SESSION_SMS_DEVICE]
|
||||||
|
return self.executor.stage_ok()
|
|
@ -0,0 +1,95 @@
|
||||||
|
"""Test SMS API"""
|
||||||
|
from unittest.mock import MagicMock, patch
|
||||||
|
|
||||||
|
from django.urls import reverse
|
||||||
|
from rest_framework.test import APITestCase
|
||||||
|
|
||||||
|
from authentik.core.models import User
|
||||||
|
from authentik.flows.challenge import ChallengeTypes
|
||||||
|
from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding
|
||||||
|
from authentik.stages.authenticator_sms.models import AuthenticatorSMSStage, SMSProviders
|
||||||
|
from authentik.stages.authenticator_sms.stage import SESSION_SMS_DEVICE
|
||||||
|
|
||||||
|
|
||||||
|
class AuthenticatorSMSStageTests(APITestCase):
|
||||||
|
"""Test SMS API"""
|
||||||
|
|
||||||
|
def setUp(self) -> None:
|
||||||
|
super().setUp()
|
||||||
|
self.flow = Flow.objects.create(
|
||||||
|
name="foo",
|
||||||
|
slug="foo",
|
||||||
|
designation=FlowDesignation.STAGE_CONFIGURATION,
|
||||||
|
)
|
||||||
|
self.stage = AuthenticatorSMSStage.objects.create(
|
||||||
|
name="foo",
|
||||||
|
provider=SMSProviders.TWILIO,
|
||||||
|
configure_flow=self.flow,
|
||||||
|
)
|
||||||
|
FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=0)
|
||||||
|
self.user = User.objects.create(username="foo")
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
def test_stage_no_prefill(self):
|
||||||
|
"""test stage"""
|
||||||
|
self.client.get(
|
||||||
|
reverse("authentik_flows:configure", kwargs={"stage_uuid": self.stage.stage_uuid}),
|
||||||
|
)
|
||||||
|
response = self.client.get(
|
||||||
|
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||||
|
)
|
||||||
|
self.assertJSONEqual(
|
||||||
|
response.content,
|
||||||
|
{
|
||||||
|
"component": "ak-stage-authenticator-sms",
|
||||||
|
"flow_info": {
|
||||||
|
"background": self.flow.background_url,
|
||||||
|
"cancel_url": reverse("authentik_flows:cancel"),
|
||||||
|
"title": "",
|
||||||
|
},
|
||||||
|
"pending_user": "foo",
|
||||||
|
"pending_user_avatar": (
|
||||||
|
"https://secure.gravatar.com/avatar/d41d8cd98f00"
|
||||||
|
"b204e9800998ecf8427e?s=158&r=g"
|
||||||
|
),
|
||||||
|
"phone_number_required": True,
|
||||||
|
"type": ChallengeTypes.NATIVE.value,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_stage_submit(self):
|
||||||
|
"""test stage (submit)"""
|
||||||
|
# Prepares session etc
|
||||||
|
self.test_stage_no_prefill()
|
||||||
|
sms_send_mock = MagicMock()
|
||||||
|
with patch(
|
||||||
|
"authentik.stages.authenticator_sms.models.AuthenticatorSMSStage.send",
|
||||||
|
sms_send_mock,
|
||||||
|
):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||||
|
data={"component": "ak-stage-authenticator-sms", "phone_number": "foo"},
|
||||||
|
)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
sms_send_mock.assert_called_once()
|
||||||
|
|
||||||
|
def test_stage_submit_full(self):
|
||||||
|
"""test stage (submit)"""
|
||||||
|
# Prepares session etc
|
||||||
|
self.test_stage_submit()
|
||||||
|
sms_send_mock = MagicMock()
|
||||||
|
with patch(
|
||||||
|
"authentik.stages.authenticator_sms.models.AuthenticatorSMSStage.send",
|
||||||
|
sms_send_mock,
|
||||||
|
):
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug}),
|
||||||
|
data={
|
||||||
|
"component": "ak-stage-authenticator-sms",
|
||||||
|
"phone_number": "foo",
|
||||||
|
"code": int(self.client.session[SESSION_SMS_DEVICE].token),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
print(response.content)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
sms_send_mock.assert_not_called()
|
|
@ -6,7 +6,7 @@ from rest_framework.test import APITestCase
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
|
|
||||||
|
|
||||||
class AuthenticatorStaticStage(APITestCase):
|
class AuthenticatorStaticStageTests(APITestCase):
|
||||||
"""Test Static API"""
|
"""Test Static API"""
|
||||||
|
|
||||||
def test_api_delete(self):
|
def test_api_delete(self):
|
||||||
|
|
|
@ -42,7 +42,7 @@ class AuthenticatorTOTPChallengeResponse(ChallengeResponse):
|
||||||
"""Validate totp code"""
|
"""Validate totp code"""
|
||||||
if self.device is not None:
|
if self.device is not None:
|
||||||
if not self.device.verify_token(code):
|
if not self.device.verify_token(code):
|
||||||
raise ValidationError(_("OTP Code does not match"))
|
raise ValidationError(_("Code does not match"))
|
||||||
return code
|
return code
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@ from authentik.core.api.utils import PassiveSerializer
|
||||||
from authentik.core.models import User
|
from authentik.core.models import User
|
||||||
from authentik.lib.utils.http import get_client_ip
|
from authentik.lib.utils.http import get_client_ip
|
||||||
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
from authentik.stages.authenticator_duo.models import AuthenticatorDuoStage, DuoDevice
|
||||||
|
from authentik.stages.authenticator_sms.models import SMSDevice
|
||||||
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
from authentik.stages.authenticator_webauthn.models import WebAuthnDevice
|
||||||
from authentik.stages.authenticator_webauthn.utils import generate_challenge, get_origin
|
from authentik.stages.authenticator_webauthn.utils import generate_challenge, get_origin
|
||||||
|
|
||||||
|
@ -77,6 +78,18 @@ def get_webauthn_challenge(request: HttpRequest, device: WebAuthnDevice) -> dict
|
||||||
return assertion
|
return assertion
|
||||||
|
|
||||||
|
|
||||||
|
def select_challenge(request: HttpRequest, device: Device):
|
||||||
|
"""Callback when the user selected a challenge in the frontend."""
|
||||||
|
if isinstance(device, SMSDevice):
|
||||||
|
select_challenge_sms(request, device)
|
||||||
|
|
||||||
|
|
||||||
|
def select_challenge_sms(request: HttpRequest, device: SMSDevice):
|
||||||
|
"""Send SMS"""
|
||||||
|
device.generate_token()
|
||||||
|
device.stage.send(device.token, device)
|
||||||
|
|
||||||
|
|
||||||
def validate_challenge_code(code: str, request: HttpRequest, user: User) -> str:
|
def validate_challenge_code(code: str, request: HttpRequest, user: User) -> str:
|
||||||
"""Validate code-based challenges. We test against every device, on purpose, as
|
"""Validate code-based challenges. We test against every device, on purpose, as
|
||||||
the user mustn't choose between totp and static devices."""
|
the user mustn't choose between totp and static devices."""
|
||||||
|
|
|
@ -18,6 +18,7 @@ class DeviceClasses(models.TextChoices):
|
||||||
TOTP = "totp", _("TOTP")
|
TOTP = "totp", _("TOTP")
|
||||||
WEBAUTHN = "webauthn", _("WebAuthn")
|
WEBAUTHN = "webauthn", _("WebAuthn")
|
||||||
DUO = "duo", _("Duo")
|
DUO = "duo", _("Duo")
|
||||||
|
SMS = "sms", _("SMS")
|
||||||
|
|
||||||
|
|
||||||
def default_device_classes() -> list:
|
def default_device_classes() -> list:
|
||||||
|
|
|
@ -9,9 +9,11 @@ from authentik.flows.challenge import ChallengeResponse, ChallengeTypes, WithUse
|
||||||
from authentik.flows.models import NotConfiguredAction, Stage
|
from authentik.flows.models import NotConfiguredAction, Stage
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
|
from authentik.stages.authenticator_sms.models import SMSDevice
|
||||||
from authentik.stages.authenticator_validate.challenge import (
|
from authentik.stages.authenticator_validate.challenge import (
|
||||||
DeviceChallenge,
|
DeviceChallenge,
|
||||||
get_challenge_for_device,
|
get_challenge_for_device,
|
||||||
|
select_challenge,
|
||||||
validate_challenge_code,
|
validate_challenge_code,
|
||||||
validate_challenge_duo,
|
validate_challenge_duo,
|
||||||
validate_challenge_webauthn,
|
validate_challenge_webauthn,
|
||||||
|
@ -31,6 +33,8 @@ class AuthenticatorValidationChallenge(WithUserInfoChallenge):
|
||||||
class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
||||||
"""Challenge used for Code-based and WebAuthn authenticators"""
|
"""Challenge used for Code-based and WebAuthn authenticators"""
|
||||||
|
|
||||||
|
selected_challenge = DeviceChallenge(required=False)
|
||||||
|
|
||||||
code = CharField(required=False)
|
code = CharField(required=False)
|
||||||
webauthn = JSONField(required=False)
|
webauthn = JSONField(required=False)
|
||||||
duo = IntegerField(required=False)
|
duo = IntegerField(required=False)
|
||||||
|
@ -43,7 +47,7 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
||||||
|
|
||||||
def validate_code(self, code: str) -> str:
|
def validate_code(self, code: str) -> str:
|
||||||
"""Validate code-based response, raise error if code isn't allowed"""
|
"""Validate code-based response, raise error if code isn't allowed"""
|
||||||
self._challenge_allowed([DeviceClasses.TOTP, DeviceClasses.STATIC])
|
self._challenge_allowed([DeviceClasses.TOTP, DeviceClasses.STATIC, DeviceClasses.SMS])
|
||||||
return validate_challenge_code(code, self.stage.request, self.stage.get_pending_user())
|
return validate_challenge_code(code, self.stage.request, self.stage.get_pending_user())
|
||||||
|
|
||||||
def validate_webauthn(self, webauthn: dict) -> dict:
|
def validate_webauthn(self, webauthn: dict) -> dict:
|
||||||
|
@ -59,6 +63,22 @@ class AuthenticatorValidationChallengeResponse(ChallengeResponse):
|
||||||
self._challenge_allowed([DeviceClasses.DUO])
|
self._challenge_allowed([DeviceClasses.DUO])
|
||||||
return validate_challenge_duo(duo, self.stage.request, self.stage.get_pending_user())
|
return validate_challenge_duo(duo, self.stage.request, self.stage.get_pending_user())
|
||||||
|
|
||||||
|
def validate_selected_challenge(self, challenge: dict) -> dict:
|
||||||
|
"""Check which challenge the user has selected. Actual logic only used for SMS stage."""
|
||||||
|
# First check if the challenge is valid
|
||||||
|
for device_challenge in self.stage.request.session.get("device_challenges"):
|
||||||
|
if device_challenge.get("device_class", "") != challenge.get("device_class", ""):
|
||||||
|
raise ValidationError("invalid challenge selected")
|
||||||
|
if device_challenge.get("device_uid", "") != challenge.get("device_uid", ""):
|
||||||
|
raise ValidationError("invalid challenge selected")
|
||||||
|
if challenge.get("device_class", "") != "sms":
|
||||||
|
return challenge
|
||||||
|
devices = SMSDevice.objects.filter(pk=int(challenge.get("device_uid", "0")))
|
||||||
|
if not devices.exists():
|
||||||
|
raise ValidationError("device does not exist")
|
||||||
|
select_challenge(self.stage.request, devices.first())
|
||||||
|
return challenge
|
||||||
|
|
||||||
def validate(self, attrs: dict):
|
def validate(self, attrs: dict):
|
||||||
# Checking if the given data is from a valid device class is done above
|
# Checking if the given data is from a valid device class is done above
|
||||||
# Here we only check if the any data was sent at all
|
# Here we only check if the any data was sent at all
|
||||||
|
|
|
@ -20,6 +20,7 @@ var running = true
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
log.SetLevel(log.DebugLevel)
|
log.SetLevel(log.DebugLevel)
|
||||||
|
log.SetFormatter(&log.JSONFormatter{})
|
||||||
config.DefaultConfig()
|
config.DefaultConfig()
|
||||||
err := config.LoadConfig("./authentik/lib/default.yml")
|
err := config.LoadConfig("./authentik/lib/default.yml")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
@ -80,7 +81,7 @@ func attemptStartBackend(g *gounicorn.GoUnicorn) {
|
||||||
if !running {
|
if !running {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.WithField("logger", "authentik.g").WithError(err).Warning("gunicorn process died, restarting")
|
log.WithField("logger", "authentik.router").WithError(err).Warning("gunicorn process died, restarting")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -19,7 +19,7 @@ type GoUnicorn struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewGoUnicorn() *GoUnicorn {
|
func NewGoUnicorn() *GoUnicorn {
|
||||||
logger := log.WithField("logger", "authentik.g.unicorn")
|
logger := log.WithField("logger", "authentik.router.unicorn")
|
||||||
g := &GoUnicorn{
|
g := &GoUnicorn{
|
||||||
log: logger,
|
log: logger,
|
||||||
started: false,
|
started: false,
|
||||||
|
|
|
@ -10,7 +10,7 @@ import (
|
||||||
|
|
||||||
func recoveryMiddleware() func(next http.Handler) http.Handler {
|
func recoveryMiddleware() func(next http.Handler) http.Handler {
|
||||||
sentryHandler := sentryhttp.New(sentryhttp.Options{})
|
sentryHandler := sentryhttp.New(sentryhttp.Options{})
|
||||||
l := log.WithField("logger", "authentik.sentry")
|
l := log.WithField("logger", "authentik.router.sentry")
|
||||||
return func(next http.Handler) http.Handler {
|
return func(next http.Handler) http.Handler {
|
||||||
sentryHandler.Handle(next)
|
sentryHandler.Handle(next)
|
||||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
|
@ -32,7 +32,7 @@ type WebServer struct {
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewWebServer(g *gounicorn.GoUnicorn) *WebServer {
|
func NewWebServer(g *gounicorn.GoUnicorn) *WebServer {
|
||||||
l := log.WithField("logger", "authentik.g.web")
|
l := log.WithField("logger", "authentik.router")
|
||||||
mainHandler := mux.NewRouter()
|
mainHandler := mux.NewRouter()
|
||||||
if config.G.ErrorReporting.Enabled {
|
if config.G.ErrorReporting.Enabled {
|
||||||
mainHandler.Use(recoveryMiddleware())
|
mainHandler.Use(recoveryMiddleware())
|
||||||
|
|
|
@ -8,7 +8,7 @@ msgid ""
|
||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: PACKAGE VERSION\n"
|
"Project-Id-Version: PACKAGE VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2021-10-09 18:07+0000\n"
|
"POT-Creation-Date: 2021-10-11 14:12+0000\n"
|
||||||
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
|
||||||
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
|
||||||
"Language-Team: LANGUAGE <LL@li.org>\n"
|
"Language-Team: LANGUAGE <LL@li.org>\n"
|
||||||
|
@ -1214,6 +1214,27 @@ msgstr ""
|
||||||
msgid "Duo Devices"
|
msgid "Duo Devices"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_sms/models.py:97
|
||||||
|
msgid "SMS Authenticator Setup Stage"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_sms/models.py:98
|
||||||
|
msgid "SMS Authenticator Setup Stages"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_sms/models.py:116
|
||||||
|
msgid "SMS Device"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_sms/models.py:117
|
||||||
|
msgid "SMS Devices"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_sms/stage.py:54
|
||||||
|
#: authentik/stages/authenticator_totp/stage.py:45
|
||||||
|
msgid "Code does not match"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_static/models.py:48
|
#: authentik/stages/authenticator_static/models.py:48
|
||||||
msgid "Static Authenticator Stage"
|
msgid "Static Authenticator Stage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1238,10 +1259,6 @@ msgstr ""
|
||||||
msgid "TOTP Authenticator Setup Stages"
|
msgid "TOTP Authenticator Setup Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_totp/stage.py:45
|
|
||||||
msgid "OTP Code does not match"
|
|
||||||
msgstr ""
|
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/challenge.py:85
|
#: authentik/stages/authenticator_validate/challenge.py:85
|
||||||
msgid "Invalid Token"
|
msgid "Invalid Token"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1258,15 +1275,19 @@ msgstr ""
|
||||||
msgid "Duo"
|
msgid "Duo"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/models.py:56
|
#: authentik/stages/authenticator_validate/models.py:21
|
||||||
|
msgid "SMS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: authentik/stages/authenticator_validate/models.py:57
|
||||||
msgid "Device classes which can be used to authenticate"
|
msgid "Device classes which can be used to authenticate"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/models.py:78
|
#: authentik/stages/authenticator_validate/models.py:79
|
||||||
msgid "Authenticator Validation Stage"
|
msgid "Authenticator Validation Stage"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: authentik/stages/authenticator_validate/models.py:79
|
#: authentik/stages/authenticator_validate/models.py:80
|
||||||
msgid "Authenticator Validation Stages"
|
msgid "Authenticator Validation Stages"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
783
schema.yml
783
schema.yml
|
@ -359,6 +359,80 @@ paths:
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/authenticators/admin/sms/:
|
||||||
|
get:
|
||||||
|
operationId: authenticators_admin_sms_list
|
||||||
|
description: Viewset for sms authenticator devices (for admins)
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: ordering
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: page
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A page number within the paginated result set.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: page_size
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Number of results to return per page.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: search
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PaginatedSMSDeviceList'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/authenticators/admin/sms/{id}/:
|
||||||
|
get:
|
||||||
|
operationId: authenticators_admin_sms_retrieve
|
||||||
|
description: Viewset for sms authenticator devices (for admins)
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this SMS Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SMSDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
/authenticators/admin/static/:
|
/authenticators/admin/static/:
|
||||||
get:
|
get:
|
||||||
operationId: authenticators_admin_static_list
|
operationId: authenticators_admin_static_list
|
||||||
|
@ -765,6 +839,190 @@ paths:
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/authenticators/sms/:
|
||||||
|
get:
|
||||||
|
operationId: authenticators_sms_list
|
||||||
|
description: Viewset for sms authenticator devices
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: ordering
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: page
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A page number within the paginated result set.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: page_size
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Number of results to return per page.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: search
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PaginatedSMSDeviceList'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/authenticators/sms/{id}/:
|
||||||
|
get:
|
||||||
|
operationId: authenticators_sms_retrieve
|
||||||
|
description: Viewset for sms authenticator devices
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this SMS Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SMSDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
put:
|
||||||
|
operationId: authenticators_sms_update
|
||||||
|
description: Viewset for sms authenticator devices
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this SMS Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SMSDeviceRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SMSDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
patch:
|
||||||
|
operationId: authenticators_sms_partial_update
|
||||||
|
description: Viewset for sms authenticator devices
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this SMS Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedSMSDeviceRequest'
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/SMSDevice'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
delete:
|
||||||
|
operationId: authenticators_sms_destroy
|
||||||
|
description: Viewset for sms authenticator devices
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this SMS Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: No response body
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/authenticators/sms/{id}/used_by/:
|
||||||
|
get:
|
||||||
|
operationId: authenticators_sms_used_by_list
|
||||||
|
description: Get a list of all objects that use this object
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: id
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
description: A unique integer value identifying this SMS Device.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- authenticators
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UsedBy'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
/authenticators/static/:
|
/authenticators/static/:
|
||||||
get:
|
get:
|
||||||
operationId: authenticators_static_list
|
operationId: authenticators_static_list
|
||||||
|
@ -7282,6 +7540,7 @@ paths:
|
||||||
- authentik.sources.plex
|
- authentik.sources.plex
|
||||||
- authentik.sources.saml
|
- authentik.sources.saml
|
||||||
- authentik.stages.authenticator_duo
|
- authentik.stages.authenticator_duo
|
||||||
|
- authentik.stages.authenticator_sms
|
||||||
- authentik.stages.authenticator_static
|
- authentik.stages.authenticator_static
|
||||||
- authentik.stages.authenticator_totp
|
- authentik.stages.authenticator_totp
|
||||||
- authentik.stages.authenticator_validate
|
- authentik.stages.authenticator_validate
|
||||||
|
@ -13877,6 +14136,247 @@ paths:
|
||||||
$ref: '#/components/schemas/ValidationError'
|
$ref: '#/components/schemas/ValidationError'
|
||||||
'403':
|
'403':
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/stages/authenticator/sms/:
|
||||||
|
get:
|
||||||
|
operationId: stages_authenticator_sms_list
|
||||||
|
description: AuthenticatorSMSStage Viewset
|
||||||
|
parameters:
|
||||||
|
- in: query
|
||||||
|
name: configure_flow
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
- in: query
|
||||||
|
name: from_number
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: name
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: ordering
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Which field to use when ordering the results.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- name: page
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A page number within the paginated result set.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- name: page_size
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: Number of results to return per page.
|
||||||
|
schema:
|
||||||
|
type: integer
|
||||||
|
- in: query
|
||||||
|
name: provider
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
enum:
|
||||||
|
- twilio
|
||||||
|
- name: search
|
||||||
|
required: false
|
||||||
|
in: query
|
||||||
|
description: A search term.
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: stage_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
- in: query
|
||||||
|
name: twilio_account_sid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
- in: query
|
||||||
|
name: twilio_auth
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PaginatedAuthenticatorSMSStageList'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
post:
|
||||||
|
operationId: stages_authenticator_sms_create
|
||||||
|
description: AuthenticatorSMSStage Viewset
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthenticatorSMSStageRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'201':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthenticatorSMSStage'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/stages/authenticator/sms/{stage_uuid}/:
|
||||||
|
get:
|
||||||
|
operationId: stages_authenticator_sms_retrieve
|
||||||
|
description: AuthenticatorSMSStage Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: stage_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this SMS Authenticator Setup Stage.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthenticatorSMSStage'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
put:
|
||||||
|
operationId: stages_authenticator_sms_update
|
||||||
|
description: AuthenticatorSMSStage Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: stage_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this SMS Authenticator Setup Stage.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthenticatorSMSStageRequest'
|
||||||
|
required: true
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthenticatorSMSStage'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
patch:
|
||||||
|
operationId: stages_authenticator_sms_partial_update
|
||||||
|
description: AuthenticatorSMSStage Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: stage_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this SMS Authenticator Setup Stage.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
requestBody:
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/PatchedAuthenticatorSMSStageRequest'
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
$ref: '#/components/schemas/AuthenticatorSMSStage'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
delete:
|
||||||
|
operationId: stages_authenticator_sms_destroy
|
||||||
|
description: AuthenticatorSMSStage Viewset
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: stage_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this SMS Authenticator Setup Stage.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'204':
|
||||||
|
description: No response body
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
|
/stages/authenticator/sms/{stage_uuid}/used_by/:
|
||||||
|
get:
|
||||||
|
operationId: stages_authenticator_sms_used_by_list
|
||||||
|
description: Get a list of all objects that use this object
|
||||||
|
parameters:
|
||||||
|
- in: path
|
||||||
|
name: stage_uuid
|
||||||
|
schema:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
description: A UUID string identifying this SMS Authenticator Setup Stage.
|
||||||
|
required: true
|
||||||
|
tags:
|
||||||
|
- stages
|
||||||
|
security:
|
||||||
|
- authentik: []
|
||||||
|
responses:
|
||||||
|
'200':
|
||||||
|
content:
|
||||||
|
application/json:
|
||||||
|
schema:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/UsedBy'
|
||||||
|
description: ''
|
||||||
|
'400':
|
||||||
|
$ref: '#/components/schemas/ValidationError'
|
||||||
|
'403':
|
||||||
|
$ref: '#/components/schemas/GenericError'
|
||||||
/stages/authenticator/static/:
|
/stages/authenticator/static/:
|
||||||
get:
|
get:
|
||||||
operationId: stages_authenticator_static_list
|
operationId: stages_authenticator_static_list
|
||||||
|
@ -18240,12 +18740,11 @@ components:
|
||||||
enum:
|
enum:
|
||||||
- authentik.admin
|
- authentik.admin
|
||||||
- authentik.api
|
- authentik.api
|
||||||
- authentik.events
|
|
||||||
- authentik.crypto
|
- authentik.crypto
|
||||||
|
- authentik.events
|
||||||
- authentik.flows
|
- authentik.flows
|
||||||
- authentik.outposts
|
|
||||||
- authentik.lib
|
- authentik.lib
|
||||||
- authentik.policies
|
- authentik.outposts
|
||||||
- authentik.policies.dummy
|
- authentik.policies.dummy
|
||||||
- authentik.policies.event_matcher
|
- authentik.policies.event_matcher
|
||||||
- authentik.policies.expiry
|
- authentik.policies.expiry
|
||||||
|
@ -18253,9 +18752,10 @@ components:
|
||||||
- authentik.policies.hibp
|
- authentik.policies.hibp
|
||||||
- authentik.policies.password
|
- authentik.policies.password
|
||||||
- authentik.policies.reputation
|
- authentik.policies.reputation
|
||||||
- authentik.providers.proxy
|
- authentik.policies
|
||||||
- authentik.providers.ldap
|
- authentik.providers.ldap
|
||||||
- authentik.providers.oauth2
|
- authentik.providers.oauth2
|
||||||
|
- authentik.providers.proxy
|
||||||
- authentik.providers.saml
|
- authentik.providers.saml
|
||||||
- authentik.recovery
|
- authentik.recovery
|
||||||
- authentik.sources.ldap
|
- authentik.sources.ldap
|
||||||
|
@ -18263,6 +18763,7 @@ components:
|
||||||
- authentik.sources.plex
|
- authentik.sources.plex
|
||||||
- authentik.sources.saml
|
- authentik.sources.saml
|
||||||
- authentik.stages.authenticator_duo
|
- authentik.stages.authenticator_duo
|
||||||
|
- authentik.stages.authenticator_sms
|
||||||
- authentik.stages.authenticator_static
|
- authentik.stages.authenticator_static
|
||||||
- authentik.stages.authenticator_totp
|
- authentik.stages.authenticator_totp
|
||||||
- authentik.stages.authenticator_validate
|
- authentik.stages.authenticator_validate
|
||||||
|
@ -18609,6 +19110,123 @@ components:
|
||||||
- client_id
|
- client_id
|
||||||
- client_secret
|
- client_secret
|
||||||
- name
|
- name
|
||||||
|
AuthenticatorSMSChallenge:
|
||||||
|
type: object
|
||||||
|
description: SMS Setup challenge
|
||||||
|
properties:
|
||||||
|
type:
|
||||||
|
$ref: '#/components/schemas/ChallengeChoices'
|
||||||
|
flow_info:
|
||||||
|
$ref: '#/components/schemas/ContextualFlowInfo'
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-sms
|
||||||
|
response_errors:
|
||||||
|
type: object
|
||||||
|
additionalProperties:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/ErrorDetail'
|
||||||
|
pending_user:
|
||||||
|
type: string
|
||||||
|
pending_user_avatar:
|
||||||
|
type: string
|
||||||
|
phone_number_required:
|
||||||
|
type: boolean
|
||||||
|
default: true
|
||||||
|
required:
|
||||||
|
- pending_user
|
||||||
|
- pending_user_avatar
|
||||||
|
- type
|
||||||
|
AuthenticatorSMSChallengeResponseRequest:
|
||||||
|
type: object
|
||||||
|
description: SMS Challenge response, device is set by get_response_instance
|
||||||
|
properties:
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
default: ak-stage-authenticator-sms
|
||||||
|
code:
|
||||||
|
type: integer
|
||||||
|
phone_number:
|
||||||
|
type: string
|
||||||
|
AuthenticatorSMSStage:
|
||||||
|
type: object
|
||||||
|
description: AuthenticatorSMSStage Serializer
|
||||||
|
properties:
|
||||||
|
pk:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
readOnly: true
|
||||||
|
title: Stage uuid
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
component:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
verbose_name_plural:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
flow_set:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/Flow'
|
||||||
|
configure_flow:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
description: Flow used by an authenticated user to configure this Stage.
|
||||||
|
If empty, user will not be able to configure this stage.
|
||||||
|
provider:
|
||||||
|
$ref: '#/components/schemas/ProviderEnum'
|
||||||
|
from_number:
|
||||||
|
type: string
|
||||||
|
twilio_account_sid:
|
||||||
|
type: string
|
||||||
|
twilio_auth:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- component
|
||||||
|
- from_number
|
||||||
|
- name
|
||||||
|
- pk
|
||||||
|
- provider
|
||||||
|
- twilio_account_sid
|
||||||
|
- twilio_auth
|
||||||
|
- verbose_name
|
||||||
|
- verbose_name_plural
|
||||||
|
AuthenticatorSMSStageRequest:
|
||||||
|
type: object
|
||||||
|
description: AuthenticatorSMSStage Serializer
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
flow_set:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/FlowRequest'
|
||||||
|
configure_flow:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
description: Flow used by an authenticated user to configure this Stage.
|
||||||
|
If empty, user will not be able to configure this stage.
|
||||||
|
provider:
|
||||||
|
$ref: '#/components/schemas/ProviderEnum'
|
||||||
|
from_number:
|
||||||
|
type: string
|
||||||
|
twilio_account_sid:
|
||||||
|
type: string
|
||||||
|
twilio_auth:
|
||||||
|
type: string
|
||||||
|
required:
|
||||||
|
- from_number
|
||||||
|
- name
|
||||||
|
- provider
|
||||||
|
- twilio_account_sid
|
||||||
|
- twilio_auth
|
||||||
AuthenticatorStaticChallenge:
|
AuthenticatorStaticChallenge:
|
||||||
type: object
|
type: object
|
||||||
description: Static authenticator challenge
|
description: Static authenticator challenge
|
||||||
|
@ -18920,6 +19538,8 @@ components:
|
||||||
component:
|
component:
|
||||||
type: string
|
type: string
|
||||||
default: ak-stage-authenticator-validate
|
default: ak-stage-authenticator-validate
|
||||||
|
selected_challenge:
|
||||||
|
$ref: '#/components/schemas/DeviceChallengeRequest'
|
||||||
code:
|
code:
|
||||||
type: string
|
type: string
|
||||||
webauthn:
|
webauthn:
|
||||||
|
@ -19232,6 +19852,7 @@ components:
|
||||||
oneOf:
|
oneOf:
|
||||||
- $ref: '#/components/schemas/AccessDeniedChallenge'
|
- $ref: '#/components/schemas/AccessDeniedChallenge'
|
||||||
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
|
- $ref: '#/components/schemas/AuthenticatorDuoChallenge'
|
||||||
|
- $ref: '#/components/schemas/AuthenticatorSMSChallenge'
|
||||||
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
|
- $ref: '#/components/schemas/AuthenticatorStaticChallenge'
|
||||||
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
|
- $ref: '#/components/schemas/AuthenticatorTOTPChallenge'
|
||||||
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
|
- $ref: '#/components/schemas/AuthenticatorValidationChallenge'
|
||||||
|
@ -19252,6 +19873,7 @@ components:
|
||||||
mapping:
|
mapping:
|
||||||
ak-stage-access-denied: '#/components/schemas/AccessDeniedChallenge'
|
ak-stage-access-denied: '#/components/schemas/AccessDeniedChallenge'
|
||||||
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallenge'
|
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallenge'
|
||||||
|
ak-stage-authenticator-sms: '#/components/schemas/AuthenticatorSMSChallenge'
|
||||||
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallenge'
|
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallenge'
|
||||||
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallenge'
|
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallenge'
|
||||||
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallenge'
|
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallenge'
|
||||||
|
@ -19524,12 +20146,28 @@ components:
|
||||||
- challenge
|
- challenge
|
||||||
- device_class
|
- device_class
|
||||||
- device_uid
|
- device_uid
|
||||||
|
DeviceChallengeRequest:
|
||||||
|
type: object
|
||||||
|
description: Single device challenge
|
||||||
|
properties:
|
||||||
|
device_class:
|
||||||
|
type: string
|
||||||
|
device_uid:
|
||||||
|
type: string
|
||||||
|
challenge:
|
||||||
|
type: object
|
||||||
|
additionalProperties: {}
|
||||||
|
required:
|
||||||
|
- challenge
|
||||||
|
- device_class
|
||||||
|
- device_uid
|
||||||
DeviceClassesEnum:
|
DeviceClassesEnum:
|
||||||
enum:
|
enum:
|
||||||
- static
|
- static
|
||||||
- totp
|
- totp
|
||||||
- webauthn
|
- webauthn
|
||||||
- duo
|
- duo
|
||||||
|
- sms
|
||||||
type: string
|
type: string
|
||||||
DigestAlgorithmEnum:
|
DigestAlgorithmEnum:
|
||||||
enum:
|
enum:
|
||||||
|
@ -20283,6 +20921,7 @@ components:
|
||||||
FlowChallengeResponseRequest:
|
FlowChallengeResponseRequest:
|
||||||
oneOf:
|
oneOf:
|
||||||
- $ref: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest'
|
- $ref: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest'
|
||||||
|
- $ref: '#/components/schemas/AuthenticatorSMSChallengeResponseRequest'
|
||||||
- $ref: '#/components/schemas/AuthenticatorStaticChallengeResponseRequest'
|
- $ref: '#/components/schemas/AuthenticatorStaticChallengeResponseRequest'
|
||||||
- $ref: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest'
|
- $ref: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest'
|
||||||
- $ref: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest'
|
- $ref: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest'
|
||||||
|
@ -20300,6 +20939,7 @@ components:
|
||||||
propertyName: component
|
propertyName: component
|
||||||
mapping:
|
mapping:
|
||||||
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest'
|
ak-stage-authenticator-duo: '#/components/schemas/AuthenticatorDuoChallengeResponseRequest'
|
||||||
|
ak-stage-authenticator-sms: '#/components/schemas/AuthenticatorSMSChallengeResponseRequest'
|
||||||
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallengeResponseRequest'
|
ak-stage-authenticator-static: '#/components/schemas/AuthenticatorStaticChallengeResponseRequest'
|
||||||
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest'
|
ak-stage-authenticator-totp: '#/components/schemas/AuthenticatorTOTPChallengeResponseRequest'
|
||||||
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest'
|
ak-stage-authenticator-validate: '#/components/schemas/AuthenticatorValidationChallengeResponseRequest'
|
||||||
|
@ -22411,6 +23051,41 @@ components:
|
||||||
required:
|
required:
|
||||||
- pagination
|
- pagination
|
||||||
- results
|
- results
|
||||||
|
PaginatedAuthenticatorSMSStageList:
|
||||||
|
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/AuthenticatorSMSStage'
|
||||||
|
required:
|
||||||
|
- pagination
|
||||||
|
- results
|
||||||
PaginatedAuthenticatorStaticStageList:
|
PaginatedAuthenticatorStaticStageList:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -24301,6 +24976,41 @@ components:
|
||||||
required:
|
required:
|
||||||
- pagination
|
- pagination
|
||||||
- results
|
- results
|
||||||
|
PaginatedSMSDeviceList:
|
||||||
|
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/SMSDevice'
|
||||||
|
required:
|
||||||
|
- pagination
|
||||||
|
- results
|
||||||
PaginatedScopeMappingList:
|
PaginatedScopeMappingList:
|
||||||
type: object
|
type: object
|
||||||
properties:
|
properties:
|
||||||
|
@ -25233,6 +25943,30 @@ components:
|
||||||
writeOnly: true
|
writeOnly: true
|
||||||
api_hostname:
|
api_hostname:
|
||||||
type: string
|
type: string
|
||||||
|
PatchedAuthenticatorSMSStageRequest:
|
||||||
|
type: object
|
||||||
|
description: AuthenticatorSMSStage Serializer
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
flow_set:
|
||||||
|
type: array
|
||||||
|
items:
|
||||||
|
$ref: '#/components/schemas/FlowRequest'
|
||||||
|
configure_flow:
|
||||||
|
type: string
|
||||||
|
format: uuid
|
||||||
|
nullable: true
|
||||||
|
description: Flow used by an authenticated user to configure this Stage.
|
||||||
|
If empty, user will not be able to configure this stage.
|
||||||
|
provider:
|
||||||
|
$ref: '#/components/schemas/ProviderEnum'
|
||||||
|
from_number:
|
||||||
|
type: string
|
||||||
|
twilio_account_sid:
|
||||||
|
type: string
|
||||||
|
twilio_auth:
|
||||||
|
type: string
|
||||||
PatchedAuthenticatorStaticStageRequest:
|
PatchedAuthenticatorStaticStageRequest:
|
||||||
type: object
|
type: object
|
||||||
description: AuthenticatorStaticStage Serializer
|
description: AuthenticatorStaticStage Serializer
|
||||||
|
@ -26546,6 +27280,14 @@ components:
|
||||||
description: 'Time offset when temporary users should be deleted. This only
|
description: 'Time offset when temporary users should be deleted. This only
|
||||||
applies if your IDP uses the NameID Format ''transient'', and the user
|
applies if your IDP uses the NameID Format ''transient'', and the user
|
||||||
doesn''t log out manually. (Format: hours=1;minutes=2;seconds=3).'
|
doesn''t log out manually. (Format: hours=1;minutes=2;seconds=3).'
|
||||||
|
PatchedSMSDeviceRequest:
|
||||||
|
type: object
|
||||||
|
description: Serializer for sms authenticator devices
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The human-readable name of this device.
|
||||||
|
maxLength: 64
|
||||||
PatchedScopeMappingRequest:
|
PatchedScopeMappingRequest:
|
||||||
type: object
|
type: object
|
||||||
description: ScopeMapping Serializer
|
description: ScopeMapping Serializer
|
||||||
|
@ -27402,6 +28144,10 @@ components:
|
||||||
- pk
|
- pk
|
||||||
- verbose_name
|
- verbose_name
|
||||||
- verbose_name_plural
|
- verbose_name_plural
|
||||||
|
ProviderEnum:
|
||||||
|
enum:
|
||||||
|
- twilio
|
||||||
|
type: string
|
||||||
ProviderRequest:
|
ProviderRequest:
|
||||||
type: object
|
type: object
|
||||||
description: Provider Serializer
|
description: Provider Serializer
|
||||||
|
@ -28225,6 +28971,35 @@ components:
|
||||||
- pre_authentication_flow
|
- pre_authentication_flow
|
||||||
- slug
|
- slug
|
||||||
- sso_url
|
- sso_url
|
||||||
|
SMSDevice:
|
||||||
|
type: object
|
||||||
|
description: Serializer for sms authenticator devices
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The human-readable name of this device.
|
||||||
|
maxLength: 64
|
||||||
|
pk:
|
||||||
|
type: integer
|
||||||
|
readOnly: true
|
||||||
|
title: ID
|
||||||
|
phone_number:
|
||||||
|
type: string
|
||||||
|
readOnly: true
|
||||||
|
required:
|
||||||
|
- name
|
||||||
|
- phone_number
|
||||||
|
- pk
|
||||||
|
SMSDeviceRequest:
|
||||||
|
type: object
|
||||||
|
description: Serializer for sms authenticator devices
|
||||||
|
properties:
|
||||||
|
name:
|
||||||
|
type: string
|
||||||
|
description: The human-readable name of this device.
|
||||||
|
maxLength: 64
|
||||||
|
required:
|
||||||
|
- name
|
||||||
ScopeMapping:
|
ScopeMapping:
|
||||||
type: object
|
type: object
|
||||||
description: ScopeMapping Serializer
|
description: ScopeMapping Serializer
|
||||||
|
|
|
@ -219,6 +219,9 @@ export class Form<T> extends LitElement {
|
||||||
element.errorMessage =
|
element.errorMessage =
|
||||||
errorMessage[camelToSnake(elementName)].join(", ");
|
errorMessage[camelToSnake(elementName)].join(", ");
|
||||||
element.invalid = true;
|
element.invalid = true;
|
||||||
|
} else {
|
||||||
|
element.errorMessage = "";
|
||||||
|
element.invalid = false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
if ("non_field_errors" in errorMessage) {
|
if ("non_field_errors" in errorMessage) {
|
||||||
|
|
|
@ -15,6 +15,7 @@ import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
|
||||||
import { AKResponse } from "../../api/Client";
|
import { AKResponse } from "../../api/Client";
|
||||||
import { EVENT_REFRESH } from "../../constants";
|
import { EVENT_REFRESH } from "../../constants";
|
||||||
|
import { groupBy } from "../../utils";
|
||||||
import "../EmptyState";
|
import "../EmptyState";
|
||||||
import "../chips/Chip";
|
import "../chips/Chip";
|
||||||
import "../chips/ChipGroup";
|
import "../chips/ChipGroup";
|
||||||
|
@ -154,6 +155,12 @@ export abstract class Table<T> extends LitElement {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public groupBy(items: T[]): [string, T[]][] {
|
||||||
|
return groupBy(items, () => {
|
||||||
|
return "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public fetch(): void {
|
public fetch(): void {
|
||||||
if (this.isLoading) {
|
if (this.isLoading) {
|
||||||
return;
|
return;
|
||||||
|
@ -213,7 +220,22 @@ export abstract class Table<T> extends LitElement {
|
||||||
if (this.data.pagination.count === 0) {
|
if (this.data.pagination.count === 0) {
|
||||||
return [this.renderEmpty()];
|
return [this.renderEmpty()];
|
||||||
}
|
}
|
||||||
return this.data.results.map((item: T) => {
|
const groupedResults = this.groupBy(this.data.results);
|
||||||
|
if (groupedResults.length === 1) {
|
||||||
|
return this.renderRowGroup(groupedResults[0][1]);
|
||||||
|
}
|
||||||
|
return groupedResults.map(([group, items]) => {
|
||||||
|
return html`<thead>
|
||||||
|
<tr role="row">
|
||||||
|
<th role="columnheader" scope="row" colspan="200">${group}</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
${this.renderRowGroup(items)}`;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private renderRowGroup(items: T[]): TemplateResult[] {
|
||||||
|
return items.map((item) => {
|
||||||
return html`<tbody
|
return html`<tbody
|
||||||
role="rowgroup"
|
role="rowgroup"
|
||||||
class="${this.expandedElements.indexOf(item) > -1 ? "pf-m-expanded" : ""}"
|
class="${this.expandedElements.indexOf(item) > -1 ? "pf-m-expanded" : ""}"
|
||||||
|
|
|
@ -36,6 +36,7 @@ import "./access_denied/FlowAccessDenied";
|
||||||
import "./sources/plex/PlexLoginInit";
|
import "./sources/plex/PlexLoginInit";
|
||||||
import "./stages/RedirectStage";
|
import "./stages/RedirectStage";
|
||||||
import "./stages/authenticator_duo/AuthenticatorDuoStage";
|
import "./stages/authenticator_duo/AuthenticatorDuoStage";
|
||||||
|
import "./stages/authenticator_sms/AuthenticatorSMSStage";
|
||||||
import "./stages/authenticator_static/AuthenticatorStaticStage";
|
import "./stages/authenticator_static/AuthenticatorStaticStage";
|
||||||
import "./stages/authenticator_totp/AuthenticatorTOTPStage";
|
import "./stages/authenticator_totp/AuthenticatorTOTPStage";
|
||||||
import "./stages/authenticator_validate/AuthenticatorValidateStage";
|
import "./stages/authenticator_validate/AuthenticatorValidateStage";
|
||||||
|
@ -311,6 +312,11 @@ export class FlowExecutor extends LitElement implements StageHost {
|
||||||
.host=${this as StageHost}
|
.host=${this as StageHost}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
></ak-stage-authenticator-validate>`;
|
></ak-stage-authenticator-validate>`;
|
||||||
|
case "ak-stage-authenticator-sms":
|
||||||
|
return html`<ak-stage-authenticator-sms
|
||||||
|
.host=${this as StageHost}
|
||||||
|
.challenge=${this.challenge}
|
||||||
|
></ak-stage-authenticator-sms>`;
|
||||||
case "ak-flow-sources-plex":
|
case "ak-flow-sources-plex":
|
||||||
return html`<ak-flow-sources-plex
|
return html`<ak-flow-sources-plex
|
||||||
.host=${this as StageHost}
|
.host=${this as StageHost}
|
||||||
|
|
|
@ -0,0 +1,158 @@
|
||||||
|
import { t } from "@lingui/macro";
|
||||||
|
|
||||||
|
import { CSSResult, html, TemplateResult } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
|
|
||||||
|
import AKGlobal from "../../../authentik.css";
|
||||||
|
import PFAlert from "@patternfly/patternfly/components/Alert/alert.css";
|
||||||
|
import PFButton from "@patternfly/patternfly/components/Button/button.css";
|
||||||
|
import PFForm from "@patternfly/patternfly/components/Form/form.css";
|
||||||
|
import PFFormControl from "@patternfly/patternfly/components/FormControl/form-control.css";
|
||||||
|
import PFLogin from "@patternfly/patternfly/components/Login/login.css";
|
||||||
|
import PFTitle from "@patternfly/patternfly/components/Title/title.css";
|
||||||
|
import PFBase from "@patternfly/patternfly/patternfly-base.css";
|
||||||
|
|
||||||
|
import {
|
||||||
|
AuthenticatorSMSChallenge,
|
||||||
|
AuthenticatorSMSChallengeResponseRequest,
|
||||||
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
import "../../../elements/EmptyState";
|
||||||
|
import "../../../elements/forms/FormElement";
|
||||||
|
import "../../FormStatic";
|
||||||
|
import { BaseStage } from "../base";
|
||||||
|
|
||||||
|
@customElement("ak-stage-authenticator-sms")
|
||||||
|
export class AuthenticatorSMSStage extends BaseStage<
|
||||||
|
AuthenticatorSMSChallenge,
|
||||||
|
AuthenticatorSMSChallengeResponseRequest
|
||||||
|
> {
|
||||||
|
static get styles(): CSSResult[] {
|
||||||
|
return [PFBase, PFAlert, PFLogin, PFForm, PFFormControl, PFTitle, PFButton, AKGlobal];
|
||||||
|
}
|
||||||
|
|
||||||
|
renderPhoneNumber(): TemplateResult {
|
||||||
|
return html`<header class="pf-c-login__main-header">
|
||||||
|
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||||
|
</header>
|
||||||
|
<div class="pf-c-login__main-body">
|
||||||
|
<form
|
||||||
|
class="pf-c-form"
|
||||||
|
@submit=${(e: Event) => {
|
||||||
|
this.submitForm(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ak-form-static
|
||||||
|
class="pf-c-form__group"
|
||||||
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
|
user=${this.challenge.pendingUser}
|
||||||
|
>
|
||||||
|
<div slot="link">
|
||||||
|
<a href="${ifDefined(this.challenge.flowInfo?.cancelUrl)}"
|
||||||
|
>${t`Not you?`}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ak-form-static>
|
||||||
|
<ak-form-element
|
||||||
|
label="${t`Phone number`}"
|
||||||
|
?required="${true}"
|
||||||
|
class="pf-c-form__group"
|
||||||
|
.errors=${(this.challenge?.responseErrors || {})["phone_number"]}
|
||||||
|
>
|
||||||
|
<!-- @ts-ignore -->
|
||||||
|
<input
|
||||||
|
type="tel"
|
||||||
|
name="phoneNumber"
|
||||||
|
placeholder="${t`Please enter your Phone number.`}"
|
||||||
|
autofocus=""
|
||||||
|
autocomplete="tel"
|
||||||
|
class="pf-c-form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</ak-form-element>
|
||||||
|
${"non_field_errors" in (this.challenge?.responseErrors || {})
|
||||||
|
? this.renderNonFieldErrors(
|
||||||
|
this.challenge?.responseErrors?.non_field_errors || [],
|
||||||
|
)
|
||||||
|
: html``}
|
||||||
|
<div class="pf-c-form__group pf-m-action">
|
||||||
|
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||||
|
${t`Continue`}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<footer class="pf-c-login__main-footer">
|
||||||
|
<ul class="pf-c-login__main-footer-links"></ul>
|
||||||
|
</footer>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCode(): TemplateResult {
|
||||||
|
return html`<header class="pf-c-login__main-header">
|
||||||
|
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||||
|
</header>
|
||||||
|
<div class="pf-c-login__main-body">
|
||||||
|
<form
|
||||||
|
class="pf-c-form"
|
||||||
|
@submit=${(e: Event) => {
|
||||||
|
this.submitForm(e);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<ak-form-static
|
||||||
|
class="pf-c-form__group"
|
||||||
|
userAvatar="${this.challenge.pendingUserAvatar}"
|
||||||
|
user=${this.challenge.pendingUser}
|
||||||
|
>
|
||||||
|
<div slot="link">
|
||||||
|
<a href="${ifDefined(this.challenge.flowInfo?.cancelUrl)}"
|
||||||
|
>${t`Not you?`}</a
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</ak-form-static>
|
||||||
|
<ak-form-element
|
||||||
|
label="${t`Code`}"
|
||||||
|
?required="${true}"
|
||||||
|
class="pf-c-form__group"
|
||||||
|
.errors=${(this.challenge?.responseErrors || {})["code"]}
|
||||||
|
>
|
||||||
|
<!-- @ts-ignore -->
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
name="code"
|
||||||
|
inputmode="numeric"
|
||||||
|
pattern="[0-9]*"
|
||||||
|
placeholder="${t`Please enter your TOTP Code`}"
|
||||||
|
autofocus=""
|
||||||
|
autocomplete="one-time-code"
|
||||||
|
class="pf-c-form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</ak-form-element>
|
||||||
|
${"non_field_errors" in (this.challenge?.responseErrors || {})
|
||||||
|
? this.renderNonFieldErrors(
|
||||||
|
this.challenge?.responseErrors?.non_field_errors || [],
|
||||||
|
)
|
||||||
|
: html``}
|
||||||
|
<div class="pf-c-form__group pf-m-action">
|
||||||
|
<button type="submit" class="pf-c-button pf-m-primary pf-m-block">
|
||||||
|
${t`Continue`}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<footer class="pf-c-login__main-footer">
|
||||||
|
<ul class="pf-c-login__main-footer-links"></ul>
|
||||||
|
</footer>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
if (!this.challenge) {
|
||||||
|
return html`<ak-empty-state ?loading="${true}" header=${t`Loading`}> </ak-empty-state>`;
|
||||||
|
}
|
||||||
|
if (this.challenge.phoneNumberRequired) {
|
||||||
|
return this.renderPhoneNumber();
|
||||||
|
}
|
||||||
|
return this.renderCode();
|
||||||
|
}
|
||||||
|
}
|
|
@ -15,21 +15,17 @@ import {
|
||||||
AuthenticatorValidationChallenge,
|
AuthenticatorValidationChallenge,
|
||||||
AuthenticatorValidationChallengeResponseRequest,
|
AuthenticatorValidationChallengeResponseRequest,
|
||||||
DeviceChallenge,
|
DeviceChallenge,
|
||||||
|
DeviceClassesEnum,
|
||||||
|
FlowsApi,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { BaseStage, StageHost } from "../base";
|
import { BaseStage, StageHost } from "../base";
|
||||||
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
import { PasswordManagerPrefill } from "../identification/IdentificationStage";
|
||||||
import "./AuthenticatorValidateStageCode";
|
import "./AuthenticatorValidateStageCode";
|
||||||
import "./AuthenticatorValidateStageDuo";
|
import "./AuthenticatorValidateStageDuo";
|
||||||
import "./AuthenticatorValidateStageWebAuthn";
|
import "./AuthenticatorValidateStageWebAuthn";
|
||||||
|
|
||||||
export enum DeviceClasses {
|
|
||||||
STATIC = "static",
|
|
||||||
TOTP = "totp",
|
|
||||||
WEBAUTHN = "webauthn",
|
|
||||||
DUO = "duo",
|
|
||||||
}
|
|
||||||
|
|
||||||
@customElement("ak-stage-authenticator-validate")
|
@customElement("ak-stage-authenticator-validate")
|
||||||
export class AuthenticatorValidateStage
|
export class AuthenticatorValidateStage
|
||||||
extends BaseStage<
|
extends BaseStage<
|
||||||
|
@ -38,8 +34,29 @@ export class AuthenticatorValidateStage
|
||||||
>
|
>
|
||||||
implements StageHost
|
implements StageHost
|
||||||
{
|
{
|
||||||
|
flowSlug = "";
|
||||||
|
|
||||||
|
_selectedDeviceChallenge?: DeviceChallenge;
|
||||||
|
|
||||||
@property({ attribute: false })
|
@property({ attribute: false })
|
||||||
selectedDeviceChallenge?: DeviceChallenge;
|
set selectedDeviceChallenge(value: DeviceChallenge | undefined) {
|
||||||
|
this._selectedDeviceChallenge = value;
|
||||||
|
// We don't use this.submit here, as we don't want to advance the flow.
|
||||||
|
// We just want to notify the backend which challenge has been selected.
|
||||||
|
new FlowsApi(DEFAULT_CONFIG).flowsExecutorSolve({
|
||||||
|
flowSlug: this.host.flowSlug,
|
||||||
|
query: window.location.search.substring(1),
|
||||||
|
flowChallengeResponseRequest: {
|
||||||
|
// @ts-ignore
|
||||||
|
component: this.challenge.component || "",
|
||||||
|
selectedChallenge: value,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
get selectedDeviceChallenge(): DeviceChallenge | undefined {
|
||||||
|
return this._selectedDeviceChallenge;
|
||||||
|
}
|
||||||
|
|
||||||
submit(payload: AuthenticatorValidationChallengeResponseRequest): Promise<void> {
|
submit(payload: AuthenticatorValidationChallengeResponseRequest): Promise<void> {
|
||||||
return this.host?.submit(payload) || Promise.resolve();
|
return this.host?.submit(payload) || Promise.resolve();
|
||||||
|
@ -74,7 +91,7 @@ export class AuthenticatorValidateStage
|
||||||
|
|
||||||
renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
|
renderDevicePickerSingle(deviceChallenge: DeviceChallenge): TemplateResult {
|
||||||
switch (deviceChallenge.deviceClass) {
|
switch (deviceChallenge.deviceClass) {
|
||||||
case DeviceClasses.DUO:
|
case DeviceClassesEnum.Duo:
|
||||||
return html`<i class="fas fa-mobile-alt"></i>
|
return html`<i class="fas fa-mobile-alt"></i>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<p>${t`Duo push-notifications`}</p>
|
<p>${t`Duo push-notifications`}</p>
|
||||||
|
@ -82,37 +99,30 @@ export class AuthenticatorValidateStage
|
||||||
>${t`Receive a push notification on your phone to prove your identity.`}</small
|
>${t`Receive a push notification on your phone to prove your identity.`}</small
|
||||||
>
|
>
|
||||||
</div>`;
|
</div>`;
|
||||||
case DeviceClasses.WEBAUTHN:
|
case DeviceClassesEnum.Webauthn:
|
||||||
return html`<i class="fas fa-mobile-alt"></i>
|
return html`<i class="fas fa-mobile-alt"></i>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<p>${t`Authenticator`}</p>
|
<p>${t`Authenticator`}</p>
|
||||||
<small>${t`Use a security key to prove your identity.`}</small>
|
<small>${t`Use a security key to prove your identity.`}</small>
|
||||||
</div>`;
|
</div>`;
|
||||||
case DeviceClasses.TOTP:
|
case DeviceClassesEnum.Totp:
|
||||||
// TOTP is a bit special, assuming that TOTP is allowed from the backend,
|
|
||||||
// and we have a pre-filled value from the password manager,
|
|
||||||
// directly set the the TOTP device Challenge as active.
|
|
||||||
if (PasswordManagerPrefill.totp) {
|
|
||||||
console.debug(
|
|
||||||
"authentik/stages/authenticator_validate: found prefill totp code, selecting totp challenge",
|
|
||||||
);
|
|
||||||
this.selectedDeviceChallenge = deviceChallenge;
|
|
||||||
// Delay the update as a re-render isn't triggered from here
|
|
||||||
setTimeout(() => {
|
|
||||||
this.requestUpdate();
|
|
||||||
}, 100);
|
|
||||||
}
|
|
||||||
return html`<i class="fas fa-clock"></i>
|
return html`<i class="fas fa-clock"></i>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<p>${t`Traditional authenticator`}</p>
|
<p>${t`Traditional authenticator`}</p>
|
||||||
<small>${t`Use a code-based authenticator.`}</small>
|
<small>${t`Use a code-based authenticator.`}</small>
|
||||||
</div>`;
|
</div>`;
|
||||||
case DeviceClasses.STATIC:
|
case DeviceClassesEnum.Static:
|
||||||
return html`<i class="fas fa-key"></i>
|
return html`<i class="fas fa-key"></i>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
<p>${t`Recovery keys`}</p>
|
<p>${t`Recovery keys`}</p>
|
||||||
<small>${t`In case you can't access any other method.`}</small>
|
<small>${t`In case you can't access any other method.`}</small>
|
||||||
</div>`;
|
</div>`;
|
||||||
|
case DeviceClassesEnum.Sms:
|
||||||
|
return html`<i class="fas fa-mobile"></i>
|
||||||
|
<div class="right">
|
||||||
|
<p>${t`SMS`}</p>
|
||||||
|
<small>${t`Tokens sent via SMS.`}</small>
|
||||||
|
</div>`;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -142,8 +152,9 @@ export class AuthenticatorValidateStage
|
||||||
return html``;
|
return html``;
|
||||||
}
|
}
|
||||||
switch (this.selectedDeviceChallenge?.deviceClass) {
|
switch (this.selectedDeviceChallenge?.deviceClass) {
|
||||||
case DeviceClasses.STATIC:
|
case DeviceClassesEnum.Static:
|
||||||
case DeviceClasses.TOTP:
|
case DeviceClassesEnum.Totp:
|
||||||
|
case DeviceClassesEnum.Sms:
|
||||||
return html`<ak-stage-authenticator-validate-code
|
return html`<ak-stage-authenticator-validate-code
|
||||||
.host=${this}
|
.host=${this}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
|
@ -151,7 +162,7 @@ export class AuthenticatorValidateStage
|
||||||
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}
|
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}
|
||||||
>
|
>
|
||||||
</ak-stage-authenticator-validate-code>`;
|
</ak-stage-authenticator-validate-code>`;
|
||||||
case DeviceClasses.WEBAUTHN:
|
case DeviceClassesEnum.Webauthn:
|
||||||
return html`<ak-stage-authenticator-validate-webauthn
|
return html`<ak-stage-authenticator-validate-webauthn
|
||||||
.host=${this}
|
.host=${this}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
|
@ -159,7 +170,7 @@ export class AuthenticatorValidateStage
|
||||||
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}
|
.showBackButton=${(this.challenge?.deviceChallenges.length || []) > 1}
|
||||||
>
|
>
|
||||||
</ak-stage-authenticator-validate-webauthn>`;
|
</ak-stage-authenticator-validate-webauthn>`;
|
||||||
case DeviceClasses.DUO:
|
case DeviceClassesEnum.Duo:
|
||||||
return html`<ak-stage-authenticator-validate-duo
|
return html`<ak-stage-authenticator-validate-duo
|
||||||
.host=${this}
|
.host=${this}
|
||||||
.challenge=${this.challenge}
|
.challenge=${this.challenge}
|
||||||
|
@ -179,6 +190,18 @@ export class AuthenticatorValidateStage
|
||||||
if (this.challenge?.deviceChallenges.length === 1) {
|
if (this.challenge?.deviceChallenges.length === 1) {
|
||||||
this.selectedDeviceChallenge = this.challenge.deviceChallenges[0];
|
this.selectedDeviceChallenge = this.challenge.deviceChallenges[0];
|
||||||
}
|
}
|
||||||
|
// TOTP is a bit special, assuming that TOTP is allowed from the backend,
|
||||||
|
// and we have a pre-filled value from the password manager,
|
||||||
|
// directly set the the TOTP device Challenge as active.
|
||||||
|
const totpChallenge = this.challenge.deviceChallenges.find(
|
||||||
|
(challenge) => challenge.deviceClass === DeviceClassesEnum.Totp,
|
||||||
|
);
|
||||||
|
if (PasswordManagerPrefill.totp && totpChallenge) {
|
||||||
|
console.debug(
|
||||||
|
"authentik/stages/authenticator_validate: found prefill totp code, selecting totp challenge",
|
||||||
|
);
|
||||||
|
this.selectedDeviceChallenge = totpChallenge;
|
||||||
|
}
|
||||||
return html`<header class="pf-c-login__main-header">
|
return html`<header class="pf-c-login__main-header">
|
||||||
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
<h1 class="pf-c-title pf-m-3xl">${this.challenge.flowInfo?.title}</h1>
|
||||||
${this.selectedDeviceChallenge
|
${this.selectedDeviceChallenge
|
||||||
|
|
|
@ -16,6 +16,7 @@ import {
|
||||||
AuthenticatorValidationChallenge,
|
AuthenticatorValidationChallenge,
|
||||||
AuthenticatorValidationChallengeResponseRequest,
|
AuthenticatorValidationChallengeResponseRequest,
|
||||||
DeviceChallenge,
|
DeviceChallenge,
|
||||||
|
DeviceClassesEnum,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
|
@ -62,6 +63,9 @@ export class AuthenticatorValidateStageWebCode extends BaseStage<
|
||||||
>
|
>
|
||||||
</div>
|
</div>
|
||||||
</ak-form-static>
|
</ak-form-static>
|
||||||
|
${this.deviceChallenge?.deviceClass == DeviceClassesEnum.Sms
|
||||||
|
? html`<p>${t`A code has been sent to you via SMS.`}</p>`
|
||||||
|
: html``}
|
||||||
<ak-form-element
|
<ak-form-element
|
||||||
label="${t`Code`}"
|
label="${t`Code`}"
|
||||||
?required="${true}"
|
?required="${true}"
|
||||||
|
@ -74,7 +78,7 @@ export class AuthenticatorValidateStageWebCode extends BaseStage<
|
||||||
name="code"
|
name="code"
|
||||||
inputmode="numeric"
|
inputmode="numeric"
|
||||||
pattern="[0-9]*"
|
pattern="[0-9]*"
|
||||||
placeholder="${t`Please enter your TOTP Code`}"
|
placeholder="${t`Please enter your Code`}"
|
||||||
autofocus=""
|
autofocus=""
|
||||||
autocomplete="one-time-code"
|
autocomplete="one-time-code"
|
||||||
class="pf-c-form-control"
|
class="pf-c-form-control"
|
||||||
|
|
|
@ -5,6 +5,7 @@ import { ErrorDetail } from "@goauthentik/api";
|
||||||
|
|
||||||
export interface StageHost {
|
export interface StageHost {
|
||||||
challenge?: unknown;
|
challenge?: unknown;
|
||||||
|
flowSlug: string;
|
||||||
submit(payload: unknown): Promise<void>;
|
submit(payload: unknown): Promise<void>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,10 @@ msgstr "6 digits, widely compatible"
|
||||||
msgid "8 digits, not compatible with apps like Google Authenticator"
|
msgid "8 digits, not compatible with apps like Google Authenticator"
|
||||||
msgstr "8 digits, not compatible with apps like Google Authenticator"
|
msgstr "8 digits, not compatible with apps like Google Authenticator"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
msgid "A code has been sent to you via SMS."
|
||||||
|
msgstr "A code has been sent to you via SMS."
|
||||||
|
|
||||||
#: src/interfaces/AdminInterface.ts
|
#: src/interfaces/AdminInterface.ts
|
||||||
msgid "A newer version of the frontend is available."
|
msgid "A newer version of the frontend is available."
|
||||||
msgstr "A newer version of the frontend is available."
|
msgstr "A newer version of the frontend is available."
|
||||||
|
@ -415,7 +419,7 @@ msgstr "Audience"
|
||||||
msgid "Authenticating with Plex..."
|
msgid "Authenticating with Plex..."
|
||||||
msgstr "Authenticating with Plex..."
|
msgstr "Authenticating with Plex..."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Authentication"
|
msgid "Authentication"
|
||||||
msgstr "Authentication"
|
msgstr "Authentication"
|
||||||
|
|
||||||
|
@ -431,7 +435,7 @@ msgstr "Authentication flow"
|
||||||
msgid "Authenticator"
|
msgid "Authenticator"
|
||||||
msgstr "Authenticator"
|
msgstr "Authenticator"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Authorization"
|
msgid "Authorization"
|
||||||
msgstr "Authorization"
|
msgstr "Authorization"
|
||||||
|
|
||||||
|
@ -805,6 +809,7 @@ msgstr "Client type"
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Close"
|
msgstr "Close"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
msgid "Code"
|
msgid "Code"
|
||||||
|
@ -835,6 +840,7 @@ msgid "Configuration error"
|
||||||
msgstr "Configuration error"
|
msgstr "Configuration error"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/password/PasswordStageForm.ts
|
#: src/pages/stages/password/PasswordStageForm.ts
|
||||||
|
@ -960,6 +966,8 @@ msgstr "Consumer secret"
|
||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr "Context"
|
msgstr "Context"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
@ -1333,7 +1341,6 @@ msgid "Designates whether this user should be treated as active. Unselect this i
|
||||||
msgstr "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
|
msgstr "Designates whether this user should be treated as active. Unselect this instead of deleting accounts."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/FlowForm.ts
|
||||||
#: src/pages/flows/FlowListPage.ts
|
|
||||||
msgid "Designation"
|
msgid "Designation"
|
||||||
msgstr "Designation"
|
msgstr "Designation"
|
||||||
|
|
||||||
|
@ -1383,6 +1390,10 @@ msgstr "Digits"
|
||||||
msgid "Disable Duo authenticator"
|
msgid "Disable Duo authenticator"
|
||||||
msgstr "Disable Duo authenticator"
|
msgstr "Disable Duo authenticator"
|
||||||
|
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "Disable SMS authenticator"
|
||||||
|
msgstr "Disable SMS authenticator"
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
msgid "Disable Static Tokens"
|
msgid "Disable Static Tokens"
|
||||||
msgstr "Disable Static Tokens"
|
msgstr "Disable Static Tokens"
|
||||||
|
@ -1540,6 +1551,10 @@ msgstr "Embedded outpost is not configured correctly."
|
||||||
msgid "Enable Duo authenticator"
|
msgid "Enable Duo authenticator"
|
||||||
msgstr "Enable Duo authenticator"
|
msgstr "Enable Duo authenticator"
|
||||||
|
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "Enable SMS authenticator"
|
||||||
|
msgstr "Enable SMS authenticator"
|
||||||
|
|
||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
||||||
msgid "Enable StartTLS"
|
msgid "Enable StartTLS"
|
||||||
msgstr "Enable StartTLS"
|
msgstr "Enable StartTLS"
|
||||||
|
@ -1569,7 +1584,7 @@ msgstr "Enabled"
|
||||||
msgid "Enabling this toggle will create a group named after the user, with the user as member."
|
msgid "Enabling this toggle will create a group named after the user, with the user as member."
|
||||||
msgstr "Enabling this toggle will create a group named after the user, with the user as member."
|
msgstr "Enabling this toggle will create a group named after the user, with the user as member."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Enrollment"
|
msgid "Enrollment"
|
||||||
msgstr "Enrollment"
|
msgstr "Enrollment"
|
||||||
|
|
||||||
|
@ -1870,6 +1885,7 @@ msgid "Flow used by an authenticated user to configure their password. If empty,
|
||||||
msgstr "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
msgstr "Flow used by an authenticated user to configure their password. If empty, user will not be able to configure change their password."
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
||||||
|
@ -1954,6 +1970,10 @@ msgstr "From"
|
||||||
msgid "From address"
|
msgid "From address"
|
||||||
msgstr "From address"
|
msgstr "From address"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "From number"
|
||||||
|
msgstr "From number"
|
||||||
|
|
||||||
#: src/pages/providers/ldap/LDAPProviderForm.ts
|
#: src/pages/providers/ldap/LDAPProviderForm.ts
|
||||||
msgid "GID start number"
|
msgid "GID start number"
|
||||||
msgstr "GID start number"
|
msgstr "GID start number"
|
||||||
|
@ -1975,6 +1995,11 @@ msgstr "Generate"
|
||||||
msgid "Generate Certificate-Key Pair"
|
msgid "Generate Certificate-Key Pair"
|
||||||
msgstr "Generate Certificate-Key Pair"
|
msgstr "Generate Certificate-Key Pair"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Get this value from https://console.twilio.com"
|
||||||
|
msgstr "Get this value from https://console.twilio.com"
|
||||||
|
|
||||||
#:
|
#:
|
||||||
#~ msgid "Go to admin interface"
|
#~ msgid "Go to admin interface"
|
||||||
#~ msgstr "Go to admin interface"
|
#~ msgstr "Go to admin interface"
|
||||||
|
@ -2260,7 +2285,7 @@ msgstr "Internal host SSL Validation"
|
||||||
msgid "Invalid response action"
|
msgid "Invalid response action"
|
||||||
msgstr "Invalid response action"
|
msgstr "Invalid response action"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Invalidation"
|
msgid "Invalidation"
|
||||||
msgstr "Invalidation"
|
msgstr "Invalidation"
|
||||||
|
|
||||||
|
@ -2415,6 +2440,7 @@ msgstr "Load servers"
|
||||||
#: src/flows/FlowInspector.ts
|
#: src/flows/FlowInspector.ts
|
||||||
#: src/flows/access_denied/FlowAccessDenied.ts
|
#: src/flows/access_denied/FlowAccessDenied.ts
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
@ -2484,6 +2510,7 @@ msgstr "Loading"
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2721,6 +2748,7 @@ msgstr "My applications"
|
||||||
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
||||||
#: src/pages/stages/StageListPage.ts
|
#: src/pages/stages/StageListPage.ts
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2883,6 +2911,8 @@ msgid "Not used by any other object."
|
||||||
msgstr "Not used by any other object."
|
msgstr "Not used by any other object."
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
@ -2931,6 +2961,10 @@ msgstr "Notifications"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Number"
|
msgstr "Number"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Number the SMS will be sent from."
|
||||||
|
msgstr "Number the SMS will be sent from."
|
||||||
|
|
||||||
#: src/pages/users/UserViewPage.ts
|
#: src/pages/users/UserViewPage.ts
|
||||||
msgid "OAuth Authorization Codes"
|
msgid "OAuth Authorization Codes"
|
||||||
msgstr "OAuth Authorization Codes"
|
msgstr "OAuth Authorization Codes"
|
||||||
|
@ -3147,6 +3181,10 @@ msgstr "Password: Masked input, password is validated against sources. Policies
|
||||||
msgid "Persistent"
|
msgid "Persistent"
|
||||||
msgstr "Persistent"
|
msgstr "Persistent"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
msgid "Phone number"
|
||||||
|
msgstr "Phone number"
|
||||||
|
|
||||||
#: src/pages/stages/prompt/PromptForm.ts
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
msgid "Placeholder"
|
msgid "Placeholder"
|
||||||
msgstr "Placeholder"
|
msgstr "Placeholder"
|
||||||
|
@ -3155,8 +3193,16 @@ msgstr "Placeholder"
|
||||||
msgid "Plan history"
|
msgid "Plan history"
|
||||||
msgstr "Plan history"
|
msgstr "Plan history"
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
msgid "Please enter your Code"
|
||||||
|
msgstr "Please enter your Code"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
msgid "Please enter your Phone number."
|
||||||
|
msgstr "Please enter your Phone number."
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
msgid "Please enter your TOTP Code"
|
msgid "Please enter your TOTP Code"
|
||||||
msgstr "Please enter your TOTP Code"
|
msgstr "Please enter your TOTP Code"
|
||||||
|
|
||||||
|
@ -3339,6 +3385,7 @@ msgstr "Provide support for protocols like SAML and OAuth to assigned applicatio
|
||||||
#: src/pages/applications/ApplicationForm.ts
|
#: src/pages/applications/ApplicationForm.ts
|
||||||
#: src/pages/applications/ApplicationListPage.ts
|
#: src/pages/applications/ApplicationListPage.ts
|
||||||
#: src/pages/applications/ApplicationViewPage.ts
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
msgid "Provider"
|
msgid "Provider"
|
||||||
msgstr "Provider"
|
msgstr "Provider"
|
||||||
|
|
||||||
|
@ -3434,7 +3481,7 @@ msgstr "Re-evaluate policies"
|
||||||
msgid "Receive a push notification on your phone to prove your identity."
|
msgid "Receive a push notification on your phone to prove your identity."
|
||||||
msgstr "Receive a push notification on your phone to prove your identity."
|
msgstr "Receive a push notification on your phone to prove your identity."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
#: src/pages/tokens/TokenListPage.ts
|
#: src/pages/tokens/TokenListPage.ts
|
||||||
#: src/pages/users/UserListPage.ts
|
#: src/pages/users/UserListPage.ts
|
||||||
msgid "Recovery"
|
msgid "Recovery"
|
||||||
|
@ -3622,6 +3669,15 @@ msgstr "SHA512"
|
||||||
msgid "SLO URL"
|
msgid "SLO URL"
|
||||||
msgstr "SLO URL"
|
msgstr "SLO URL"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "SMS"
|
||||||
|
msgstr "SMS"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
msgid "SMS-based Authenticators"
|
||||||
|
msgstr "SMS-based Authenticators"
|
||||||
|
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
msgid "SMTP Host"
|
msgid "SMTP Host"
|
||||||
msgstr "SMTP Host"
|
msgstr "SMTP Host"
|
||||||
|
@ -3978,7 +4034,7 @@ msgstr "Stage"
|
||||||
msgid "Stage Bindings"
|
msgid "Stage Bindings"
|
||||||
msgstr "Stage Bindings"
|
msgstr "Stage Bindings"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Stage Configuration"
|
msgid "Stage Configuration"
|
||||||
msgstr "Stage Configuration"
|
msgstr "Stage Configuration"
|
||||||
|
|
||||||
|
@ -4026,6 +4082,10 @@ msgstr "Stage used to configure a duo-based authenticator. This stage should be
|
||||||
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
msgstr "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgstr "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Stage used to configure an SMS-based TOTP authenticator."
|
||||||
|
msgstr "Stage used to configure an SMS-based TOTP authenticator."
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
||||||
msgstr "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
msgstr "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
||||||
|
@ -4035,6 +4095,7 @@ msgid "Stage(s)"
|
||||||
msgstr "Stage(s)"
|
msgstr "Stage(s)"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4086,12 +4147,14 @@ msgid "Status"
|
||||||
msgstr "Status"
|
msgstr "Status"
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Disabled"
|
msgid "Status: Disabled"
|
||||||
msgstr "Status: Disabled"
|
msgstr "Status: Disabled"
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Enabled"
|
msgid "Status: Enabled"
|
||||||
|
@ -4218,6 +4281,7 @@ msgid "Successfully created source."
|
||||||
msgstr "Successfully created source."
|
msgstr "Successfully created source."
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4375,6 +4439,7 @@ msgid "Successfully updated source."
|
||||||
msgstr "Successfully updated source."
|
msgstr "Successfully updated source."
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4731,6 +4796,10 @@ msgstr "Tokens and App passwords"
|
||||||
msgid "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
msgid "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
||||||
msgstr "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
msgstr "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
msgid "Tokens sent via SMS."
|
||||||
|
msgstr "Tokens sent via SMS."
|
||||||
|
|
||||||
#: src/pages/admin-overview/charts/FlowStatusChart.ts
|
#: src/pages/admin-overview/charts/FlowStatusChart.ts
|
||||||
msgid "Total flows"
|
msgid "Total flows"
|
||||||
msgstr "Total flows"
|
msgstr "Total flows"
|
||||||
|
@ -4759,6 +4828,18 @@ msgstr "Transient"
|
||||||
msgid "Transports"
|
msgid "Transports"
|
||||||
msgstr "Transports"
|
msgstr "Transports"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio"
|
||||||
|
msgstr "Twilio"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio Account SID"
|
||||||
|
msgstr "Twilio Account SID"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio Auth Token"
|
||||||
|
msgstr "Twilio Auth Token"
|
||||||
|
|
||||||
#: src/pages/flows/BoundStagesList.ts
|
#: src/pages/flows/BoundStagesList.ts
|
||||||
#: src/pages/outposts/OutpostForm.ts
|
#: src/pages/outposts/OutpostForm.ts
|
||||||
#: src/pages/outposts/ServiceConnectionListPage.ts
|
#: src/pages/outposts/ServiceConnectionListPage.ts
|
||||||
|
@ -4816,7 +4897,7 @@ msgstr "URL used to request the initial token. This URL is only required for OAu
|
||||||
msgid "Unbound policies"
|
msgid "Unbound policies"
|
||||||
msgstr "Unbound policies"
|
msgstr "Unbound policies"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Unenrollment"
|
msgid "Unenrollment"
|
||||||
msgstr "Unenrollment"
|
msgstr "Unenrollment"
|
||||||
|
|
||||||
|
|
|
@ -62,6 +62,10 @@ msgstr "6 chiffres, compatibilité large"
|
||||||
msgid "8 digits, not compatible with apps like Google Authenticator"
|
msgid "8 digits, not compatible with apps like Google Authenticator"
|
||||||
msgstr "8 chiffres, incompatible avec certaines applications telles que Google Authenticator"
|
msgstr "8 chiffres, incompatible avec certaines applications telles que Google Authenticator"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
msgid "A code has been sent to you via SMS."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/interfaces/AdminInterface.ts
|
#: src/interfaces/AdminInterface.ts
|
||||||
msgid "A newer version of the frontend is available."
|
msgid "A newer version of the frontend is available."
|
||||||
msgstr "Une nouvelle version de l'interface est disponible."
|
msgstr "Une nouvelle version de l'interface est disponible."
|
||||||
|
@ -419,7 +423,7 @@ msgstr "Audience"
|
||||||
msgid "Authenticating with Plex..."
|
msgid "Authenticating with Plex..."
|
||||||
msgstr "Authentification avec Plex..."
|
msgstr "Authentification avec Plex..."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Authentication"
|
msgid "Authentication"
|
||||||
msgstr "Authentification"
|
msgstr "Authentification"
|
||||||
|
|
||||||
|
@ -435,7 +439,7 @@ msgstr "Flux d'authentification"
|
||||||
msgid "Authenticator"
|
msgid "Authenticator"
|
||||||
msgstr "Authentificateur"
|
msgstr "Authentificateur"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Authorization"
|
msgid "Authorization"
|
||||||
msgstr "Authorisation"
|
msgstr "Authorisation"
|
||||||
|
|
||||||
|
@ -806,6 +810,7 @@ msgstr "Type du client"
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr "Fermer"
|
msgstr "Fermer"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
msgid "Code"
|
msgid "Code"
|
||||||
|
@ -836,6 +841,7 @@ msgid "Configuration error"
|
||||||
msgstr "Erreur de configuration"
|
msgstr "Erreur de configuration"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/password/PasswordStageForm.ts
|
#: src/pages/stages/password/PasswordStageForm.ts
|
||||||
|
@ -958,6 +964,8 @@ msgstr "Secret consumer"
|
||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr "Contexte"
|
msgstr "Contexte"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
@ -1323,7 +1331,6 @@ msgid "Designates whether this user should be treated as active. Unselect this i
|
||||||
msgstr "Indique si cet utilisateur doit être traité comme actif. Désélectionnez cette option au lieu de supprimer les comptes."
|
msgstr "Indique si cet utilisateur doit être traité comme actif. Désélectionnez cette option au lieu de supprimer les comptes."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/FlowForm.ts
|
||||||
#: src/pages/flows/FlowListPage.ts
|
|
||||||
msgid "Designation"
|
msgid "Designation"
|
||||||
msgstr "Désignation"
|
msgstr "Désignation"
|
||||||
|
|
||||||
|
@ -1371,6 +1378,10 @@ msgstr "Chiffres"
|
||||||
msgid "Disable Duo authenticator"
|
msgid "Disable Duo authenticator"
|
||||||
msgstr "Désactiver l'authentificateur Duo"
|
msgstr "Désactiver l'authentificateur Duo"
|
||||||
|
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "Disable SMS authenticator"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
msgid "Disable Static Tokens"
|
msgid "Disable Static Tokens"
|
||||||
msgstr "Désactiver les jetons statiques"
|
msgstr "Désactiver les jetons statiques"
|
||||||
|
@ -1526,6 +1537,10 @@ msgstr "L'avant poste intégré n'est pas configuré correctement"
|
||||||
msgid "Enable Duo authenticator"
|
msgid "Enable Duo authenticator"
|
||||||
msgstr "Activer l'authentificateur Duo"
|
msgstr "Activer l'authentificateur Duo"
|
||||||
|
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "Enable SMS authenticator"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
||||||
msgid "Enable StartTLS"
|
msgid "Enable StartTLS"
|
||||||
msgstr "Activer StartTLS"
|
msgstr "Activer StartTLS"
|
||||||
|
@ -1555,7 +1570,7 @@ msgstr "Activé"
|
||||||
msgid "Enabling this toggle will create a group named after the user, with the user as member."
|
msgid "Enabling this toggle will create a group named after the user, with the user as member."
|
||||||
msgstr "Activer cette option va créer un groupe du même nom que l'utilisateur dont il sera membre."
|
msgstr "Activer cette option va créer un groupe du même nom que l'utilisateur dont il sera membre."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Enrollment"
|
msgid "Enrollment"
|
||||||
msgstr "Inscription"
|
msgstr "Inscription"
|
||||||
|
|
||||||
|
@ -1855,6 +1870,7 @@ msgid "Flow used by an authenticated user to configure their password. If empty,
|
||||||
msgstr "Flux utilisé par un utilisateur authentifié pour configurer son mot de passe. S'il est vide, l'utilisateur ne sera pas en mesure de changer son mot de passe."
|
msgstr "Flux utilisé par un utilisateur authentifié pour configurer son mot de passe. S'il est vide, l'utilisateur ne sera pas en mesure de changer son mot de passe."
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
||||||
|
@ -1939,6 +1955,10 @@ msgstr "De"
|
||||||
msgid "From address"
|
msgid "From address"
|
||||||
msgstr "Adresse d'origine"
|
msgstr "Adresse d'origine"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "From number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/providers/ldap/LDAPProviderForm.ts
|
#: src/pages/providers/ldap/LDAPProviderForm.ts
|
||||||
msgid "GID start number"
|
msgid "GID start number"
|
||||||
msgstr "Numéro de départ du GID"
|
msgstr "Numéro de départ du GID"
|
||||||
|
@ -1960,6 +1980,11 @@ msgstr "Générer"
|
||||||
msgid "Generate Certificate-Key Pair"
|
msgid "Generate Certificate-Key Pair"
|
||||||
msgstr "Générer une paire clé/certificat"
|
msgstr "Générer une paire clé/certificat"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Get this value from https://console.twilio.com"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#~ msgid "Go to admin interface"
|
#~ msgid "Go to admin interface"
|
||||||
#~ msgstr "Aller à l'interface d'administration"
|
#~ msgstr "Aller à l'interface d'administration"
|
||||||
|
|
||||||
|
@ -2243,7 +2268,7 @@ msgstr "Validation SSL de l'hôte interne"
|
||||||
msgid "Invalid response action"
|
msgid "Invalid response action"
|
||||||
msgstr "Action de réponse invalide"
|
msgstr "Action de réponse invalide"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Invalidation"
|
msgid "Invalidation"
|
||||||
msgstr "Invalidation"
|
msgstr "Invalidation"
|
||||||
|
|
||||||
|
@ -2396,6 +2421,7 @@ msgstr "Charger les serveurs"
|
||||||
#: src/flows/FlowInspector.ts
|
#: src/flows/FlowInspector.ts
|
||||||
#: src/flows/access_denied/FlowAccessDenied.ts
|
#: src/flows/access_denied/FlowAccessDenied.ts
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
@ -2465,6 +2491,7 @@ msgstr "Chargement en cours"
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2701,6 +2728,7 @@ msgstr "Mes applications"
|
||||||
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
||||||
#: src/pages/stages/StageListPage.ts
|
#: src/pages/stages/StageListPage.ts
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2863,6 +2891,8 @@ msgid "Not used by any other object."
|
||||||
msgstr "Pas utilisé par un autre objet."
|
msgstr "Pas utilisé par un autre objet."
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
@ -2909,6 +2939,10 @@ msgstr "Notifications"
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr "Nombre"
|
msgstr "Nombre"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Number the SMS will be sent from."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/users/UserViewPage.ts
|
#: src/pages/users/UserViewPage.ts
|
||||||
msgid "OAuth Authorization Codes"
|
msgid "OAuth Authorization Codes"
|
||||||
msgstr "Code d'autorisation OAuth"
|
msgstr "Code d'autorisation OAuth"
|
||||||
|
@ -3121,6 +3155,10 @@ msgstr "Mot de passe : Entrée masquée, le mot de passe est vérifié par les s
|
||||||
msgid "Persistent"
|
msgid "Persistent"
|
||||||
msgstr "Persistant"
|
msgstr "Persistant"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
msgid "Phone number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/prompt/PromptForm.ts
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
msgid "Placeholder"
|
msgid "Placeholder"
|
||||||
msgstr "Par défaut"
|
msgstr "Par défaut"
|
||||||
|
@ -3129,8 +3167,16 @@ msgstr "Par défaut"
|
||||||
msgid "Plan history"
|
msgid "Plan history"
|
||||||
msgstr "Historique du plan"
|
msgstr "Historique du plan"
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
msgid "Please enter your Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
msgid "Please enter your Phone number."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
msgid "Please enter your TOTP Code"
|
msgid "Please enter your TOTP Code"
|
||||||
msgstr "Veuillez saisirvotre code TOTP"
|
msgstr "Veuillez saisirvotre code TOTP"
|
||||||
|
|
||||||
|
@ -3310,6 +3356,7 @@ msgstr "Assure la prise en charge de protocoles tels que SAML et OAuth aux appli
|
||||||
#: src/pages/applications/ApplicationForm.ts
|
#: src/pages/applications/ApplicationForm.ts
|
||||||
#: src/pages/applications/ApplicationListPage.ts
|
#: src/pages/applications/ApplicationListPage.ts
|
||||||
#: src/pages/applications/ApplicationViewPage.ts
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
msgid "Provider"
|
msgid "Provider"
|
||||||
msgstr "Fournisseur"
|
msgstr "Fournisseur"
|
||||||
|
|
||||||
|
@ -3404,7 +3451,7 @@ msgstr "Ré-évaluer les politiques"
|
||||||
msgid "Receive a push notification on your phone to prove your identity."
|
msgid "Receive a push notification on your phone to prove your identity."
|
||||||
msgstr "Recevez une notification push sur votre téléphone pour prouver votre identité."
|
msgstr "Recevez une notification push sur votre téléphone pour prouver votre identité."
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
#: src/pages/tokens/TokenListPage.ts
|
#: src/pages/tokens/TokenListPage.ts
|
||||||
#: src/pages/users/UserListPage.ts
|
#: src/pages/users/UserListPage.ts
|
||||||
msgid "Recovery"
|
msgid "Recovery"
|
||||||
|
@ -3590,6 +3637,15 @@ msgstr "SHA512"
|
||||||
msgid "SLO URL"
|
msgid "SLO URL"
|
||||||
msgstr "URL SLO"
|
msgstr "URL SLO"
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "SMS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
msgid "SMS-based Authenticators"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
msgid "SMTP Host"
|
msgid "SMTP Host"
|
||||||
msgstr "Hôte SMTP"
|
msgstr "Hôte SMTP"
|
||||||
|
@ -3937,7 +3993,7 @@ msgstr "Étape"
|
||||||
msgid "Stage Bindings"
|
msgid "Stage Bindings"
|
||||||
msgstr "Liaisons de l'étape"
|
msgstr "Liaisons de l'étape"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Stage Configuration"
|
msgid "Stage Configuration"
|
||||||
msgstr "Configuration de l'étape"
|
msgstr "Configuration de l'étape"
|
||||||
|
|
||||||
|
@ -3984,6 +4040,10 @@ msgstr "Étape de configuration d'un authentificateur Duo. Cette étape devrait
|
||||||
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
msgstr "Étape de configuration d'un authentificateur statique (jetons statiques). Cette étape devrait être utilisée en flux de configuration."
|
msgstr "Étape de configuration d'un authentificateur statique (jetons statiques). Cette étape devrait être utilisée en flux de configuration."
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Stage used to configure an SMS-based TOTP authenticator."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
||||||
msgstr "Étape utilisée pour valider tout type d'authentificateur. Cette étape devrait être utilisée en flux d'authentification ou d'autorisation."
|
msgstr "Étape utilisée pour valider tout type d'authentificateur. Cette étape devrait être utilisée en flux d'authentification ou d'autorisation."
|
||||||
|
@ -3993,6 +4053,7 @@ msgid "Stage(s)"
|
||||||
msgstr "Étape(s)"
|
msgstr "Étape(s)"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4044,12 +4105,14 @@ msgid "Status"
|
||||||
msgstr "Statut"
|
msgstr "Statut"
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Disabled"
|
msgid "Status: Disabled"
|
||||||
msgstr "Statut : Désactivé"
|
msgstr "Statut : Désactivé"
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Enabled"
|
msgid "Status: Enabled"
|
||||||
|
@ -4174,6 +4237,7 @@ msgid "Successfully created source."
|
||||||
msgstr "Source créée avec succès"
|
msgstr "Source créée avec succès"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4329,6 +4393,7 @@ msgid "Successfully updated source."
|
||||||
msgstr "Source mise à jour avec succès"
|
msgstr "Source mise à jour avec succès"
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4673,6 +4738,10 @@ msgstr "Jetons et mots de passe d'application"
|
||||||
msgid "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
msgid "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
||||||
msgstr "Les jetons sont utilisés dans authentik pour les étapes de validation des courriels, les clés de récupération et l'accès aux API."
|
msgstr "Les jetons sont utilisés dans authentik pour les étapes de validation des courriels, les clés de récupération et l'accès aux API."
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
msgid "Tokens sent via SMS."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin-overview/charts/FlowStatusChart.ts
|
#: src/pages/admin-overview/charts/FlowStatusChart.ts
|
||||||
msgid "Total flows"
|
msgid "Total flows"
|
||||||
msgstr "Flux totaux"
|
msgstr "Flux totaux"
|
||||||
|
@ -4701,6 +4770,18 @@ msgstr "Transitoire"
|
||||||
msgid "Transports"
|
msgid "Transports"
|
||||||
msgstr "Transports"
|
msgstr "Transports"
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio Account SID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio Auth Token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/BoundStagesList.ts
|
#: src/pages/flows/BoundStagesList.ts
|
||||||
#: src/pages/outposts/OutpostForm.ts
|
#: src/pages/outposts/OutpostForm.ts
|
||||||
#: src/pages/outposts/ServiceConnectionListPage.ts
|
#: src/pages/outposts/ServiceConnectionListPage.ts
|
||||||
|
@ -4758,7 +4839,7 @@ msgstr "URL utilisée pour demander le jeton initial. Cette URL est uniquement r
|
||||||
msgid "Unbound policies"
|
msgid "Unbound policies"
|
||||||
msgstr "Politiques non liées"
|
msgstr "Politiques non liées"
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Unenrollment"
|
msgid "Unenrollment"
|
||||||
msgstr "Désinscription"
|
msgstr "Désinscription"
|
||||||
|
|
||||||
|
|
|
@ -56,6 +56,10 @@ msgstr ""
|
||||||
msgid "8 digits, not compatible with apps like Google Authenticator"
|
msgid "8 digits, not compatible with apps like Google Authenticator"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
msgid "A code has been sent to you via SMS."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/interfaces/AdminInterface.ts
|
#: src/interfaces/AdminInterface.ts
|
||||||
msgid "A newer version of the frontend is available."
|
msgid "A newer version of the frontend is available."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -411,7 +415,7 @@ msgstr ""
|
||||||
msgid "Authenticating with Plex..."
|
msgid "Authenticating with Plex..."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Authentication"
|
msgid "Authentication"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -427,7 +431,7 @@ msgstr ""
|
||||||
msgid "Authenticator"
|
msgid "Authenticator"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Authorization"
|
msgid "Authorization"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -799,6 +803,7 @@ msgstr ""
|
||||||
msgid "Close"
|
msgid "Close"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
msgid "Code"
|
msgid "Code"
|
||||||
|
@ -829,6 +834,7 @@ msgid "Configuration error"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/password/PasswordStageForm.ts
|
#: src/pages/stages/password/PasswordStageForm.ts
|
||||||
|
@ -954,6 +960,8 @@ msgstr ""
|
||||||
msgid "Context"
|
msgid "Context"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
@ -1325,7 +1333,6 @@ msgid "Designates whether this user should be treated as active. Unselect this i
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/FlowForm.ts
|
||||||
#: src/pages/flows/FlowListPage.ts
|
|
||||||
msgid "Designation"
|
msgid "Designation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1375,6 +1382,10 @@ msgstr ""
|
||||||
msgid "Disable Duo authenticator"
|
msgid "Disable Duo authenticator"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "Disable SMS authenticator"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
msgid "Disable Static Tokens"
|
msgid "Disable Static Tokens"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1532,6 +1543,10 @@ msgstr ""
|
||||||
msgid "Enable Duo authenticator"
|
msgid "Enable Duo authenticator"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "Enable SMS authenticator"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
#: src/pages/sources/ldap/LDAPSourceForm.ts
|
||||||
msgid "Enable StartTLS"
|
msgid "Enable StartTLS"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1561,7 +1576,7 @@ msgstr ""
|
||||||
msgid "Enabling this toggle will create a group named after the user, with the user as member."
|
msgid "Enabling this toggle will create a group named after the user, with the user as member."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Enrollment"
|
msgid "Enrollment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -1862,6 +1877,7 @@ msgid "Flow used by an authenticated user to configure their password. If empty,
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
msgid "Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage."
|
||||||
|
@ -1946,6 +1962,10 @@ msgstr ""
|
||||||
msgid "From address"
|
msgid "From address"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "From number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/providers/ldap/LDAPProviderForm.ts
|
#: src/pages/providers/ldap/LDAPProviderForm.ts
|
||||||
msgid "GID start number"
|
msgid "GID start number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -1967,6 +1987,11 @@ msgstr ""
|
||||||
msgid "Generate Certificate-Key Pair"
|
msgid "Generate Certificate-Key Pair"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Get this value from https://console.twilio.com"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#:
|
#:
|
||||||
#~ msgid "Go to admin interface"
|
#~ msgid "Go to admin interface"
|
||||||
#~ msgstr ""
|
#~ msgstr ""
|
||||||
|
@ -2252,7 +2277,7 @@ msgstr ""
|
||||||
msgid "Invalid response action"
|
msgid "Invalid response action"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Invalidation"
|
msgid "Invalidation"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -2407,6 +2432,7 @@ msgstr ""
|
||||||
#: src/flows/FlowInspector.ts
|
#: src/flows/FlowInspector.ts
|
||||||
#: src/flows/access_denied/FlowAccessDenied.ts
|
#: src/flows/access_denied/FlowAccessDenied.ts
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
@ -2476,6 +2502,7 @@ msgstr ""
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/sources/saml/SAMLSourceForm.ts
|
#: src/pages/sources/saml/SAMLSourceForm.ts
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2713,6 +2740,7 @@ msgstr ""
|
||||||
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
#: src/pages/sources/saml/SAMLSourceViewPage.ts
|
||||||
#: src/pages/stages/StageListPage.ts
|
#: src/pages/stages/StageListPage.ts
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -2875,6 +2903,8 @@ msgid "Not used by any other object."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
#: src/flows/stages/authenticator_duo/AuthenticatorDuoStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
#: src/flows/stages/authenticator_static/AuthenticatorStaticStage.ts
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
@ -2923,6 +2953,10 @@ msgstr ""
|
||||||
msgid "Number"
|
msgid "Number"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Number the SMS will be sent from."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/users/UserViewPage.ts
|
#: src/pages/users/UserViewPage.ts
|
||||||
msgid "OAuth Authorization Codes"
|
msgid "OAuth Authorization Codes"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3139,6 +3173,10 @@ msgstr ""
|
||||||
msgid "Persistent"
|
msgid "Persistent"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
msgid "Phone number"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/prompt/PromptForm.ts
|
#: src/pages/stages/prompt/PromptForm.ts
|
||||||
msgid "Placeholder"
|
msgid "Placeholder"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3147,8 +3185,16 @@ msgstr ""
|
||||||
msgid "Plan history"
|
msgid "Plan history"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
|
||||||
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStageCode.ts
|
||||||
|
msgid "Please enter your Code"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
msgid "Please enter your Phone number."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_sms/AuthenticatorSMSStage.ts
|
||||||
|
#: src/flows/stages/authenticator_totp/AuthenticatorTOTPStage.ts
|
||||||
msgid "Please enter your TOTP Code"
|
msgid "Please enter your TOTP Code"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3331,6 +3377,7 @@ msgstr ""
|
||||||
#: src/pages/applications/ApplicationForm.ts
|
#: src/pages/applications/ApplicationForm.ts
|
||||||
#: src/pages/applications/ApplicationListPage.ts
|
#: src/pages/applications/ApplicationListPage.ts
|
||||||
#: src/pages/applications/ApplicationViewPage.ts
|
#: src/pages/applications/ApplicationViewPage.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
msgid "Provider"
|
msgid "Provider"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -3426,7 +3473,7 @@ msgstr ""
|
||||||
msgid "Receive a push notification on your phone to prove your identity."
|
msgid "Receive a push notification on your phone to prove your identity."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
#: src/pages/tokens/TokenListPage.ts
|
#: src/pages/tokens/TokenListPage.ts
|
||||||
#: src/pages/users/UserListPage.ts
|
#: src/pages/users/UserListPage.ts
|
||||||
msgid "Recovery"
|
msgid "Recovery"
|
||||||
|
@ -3614,6 +3661,15 @@ msgstr ""
|
||||||
msgid "SLO URL"
|
msgid "SLO URL"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
|
msgid "SMS"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
msgid "SMS-based Authenticators"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/email/EmailStageForm.ts
|
#: src/pages/stages/email/EmailStageForm.ts
|
||||||
msgid "SMTP Host"
|
msgid "SMTP Host"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -3970,7 +4026,7 @@ msgstr ""
|
||||||
msgid "Stage Bindings"
|
msgid "Stage Bindings"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Stage Configuration"
|
msgid "Stage Configuration"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
@ -4018,6 +4074,10 @@ msgstr ""
|
||||||
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
msgid "Stage used to configure a static authenticator (i.e. static tokens). This stage should be used for configuration flows."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Stage used to configure an SMS-based TOTP authenticator."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
msgid "Stage used to validate any authenticator. This stage should be used during authentication or authorization flows."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -4027,6 +4087,7 @@ msgid "Stage(s)"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4078,12 +4139,14 @@ msgid "Status"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Disabled"
|
msgid "Status: Disabled"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorDuo.ts
|
||||||
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorSMS.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorStatic.ts
|
||||||
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
#: src/user/user-settings/stages/UserSettingsAuthenticatorTOTP.ts
|
||||||
msgid "Status: Enabled"
|
msgid "Status: Enabled"
|
||||||
|
@ -4210,6 +4273,7 @@ msgid "Successfully created source."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4367,6 +4431,7 @@ msgid "Successfully updated source."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
#: src/pages/stages/authenticator_duo/AuthenticatorDuoStageForm.ts
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
#: src/pages/stages/authenticator_static/AuthenticatorStaticStageForm.ts
|
||||||
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
#: src/pages/stages/authenticator_totp/AuthenticatorTOTPStageForm.ts
|
||||||
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
#: src/pages/stages/authenticator_validate/AuthenticatorValidateStageForm.ts
|
||||||
|
@ -4716,6 +4781,10 @@ msgstr ""
|
||||||
msgid "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
msgid "Tokens are used throughout authentik for Email validation stages, Recovery keys and API access."
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/flows/stages/authenticator_validate/AuthenticatorValidateStage.ts
|
||||||
|
msgid "Tokens sent via SMS."
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/admin-overview/charts/FlowStatusChart.ts
|
#: src/pages/admin-overview/charts/FlowStatusChart.ts
|
||||||
msgid "Total flows"
|
msgid "Total flows"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
@ -4744,6 +4813,18 @@ msgstr ""
|
||||||
msgid "Transports"
|
msgid "Transports"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio Account SID"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
|
#: src/pages/stages/authenticator_sms/AuthenticatorSMSStageForm.ts
|
||||||
|
msgid "Twilio Auth Token"
|
||||||
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/BoundStagesList.ts
|
#: src/pages/flows/BoundStagesList.ts
|
||||||
#: src/pages/outposts/OutpostForm.ts
|
#: src/pages/outposts/OutpostForm.ts
|
||||||
#: src/pages/outposts/ServiceConnectionListPage.ts
|
#: src/pages/outposts/ServiceConnectionListPage.ts
|
||||||
|
@ -4801,7 +4882,7 @@ msgstr ""
|
||||||
msgid "Unbound policies"
|
msgid "Unbound policies"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
#: src/pages/flows/FlowForm.ts
|
#: src/pages/flows/utils.ts
|
||||||
msgid "Unenrollment"
|
msgid "Unenrollment"
|
||||||
msgstr ""
|
msgstr ""
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ import { config, DEFAULT_CONFIG } from "../../api/Config";
|
||||||
import "../../elements/forms/HorizontalFormElement";
|
import "../../elements/forms/HorizontalFormElement";
|
||||||
import { ModelForm } from "../../elements/forms/ModelForm";
|
import { ModelForm } from "../../elements/forms/ModelForm";
|
||||||
import { first } from "../../utils";
|
import { first } from "../../utils";
|
||||||
|
import { DesignationToLabel } from "./utils";
|
||||||
|
|
||||||
@customElement("ak-flow-form")
|
@customElement("ak-flow-form")
|
||||||
export class FlowForm extends ModelForm<Flow, string> {
|
export class FlowForm extends ModelForm<Flow, string> {
|
||||||
|
@ -80,43 +81,43 @@ export class FlowForm extends ModelForm<Flow, string> {
|
||||||
value=${FlowDesignationEnum.Authentication}
|
value=${FlowDesignationEnum.Authentication}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.Authentication}
|
?selected=${this.instance?.designation === FlowDesignationEnum.Authentication}
|
||||||
>
|
>
|
||||||
${t`Authentication`}
|
${DesignationToLabel(FlowDesignationEnum.Authentication)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${FlowDesignationEnum.Authorization}
|
value=${FlowDesignationEnum.Authorization}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.Authorization}
|
?selected=${this.instance?.designation === FlowDesignationEnum.Authorization}
|
||||||
>
|
>
|
||||||
${t`Authorization`}
|
${DesignationToLabel(FlowDesignationEnum.Authorization)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${FlowDesignationEnum.Enrollment}
|
value=${FlowDesignationEnum.Enrollment}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}
|
?selected=${this.instance?.designation === FlowDesignationEnum.Enrollment}
|
||||||
>
|
>
|
||||||
${t`Enrollment`}
|
${DesignationToLabel(FlowDesignationEnum.Enrollment)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${FlowDesignationEnum.Invalidation}
|
value=${FlowDesignationEnum.Invalidation}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}
|
?selected=${this.instance?.designation === FlowDesignationEnum.Invalidation}
|
||||||
>
|
>
|
||||||
${t`Invalidation`}
|
${DesignationToLabel(FlowDesignationEnum.Invalidation)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${FlowDesignationEnum.Recovery}
|
value=${FlowDesignationEnum.Recovery}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}
|
?selected=${this.instance?.designation === FlowDesignationEnum.Recovery}
|
||||||
>
|
>
|
||||||
${t`Recovery`}
|
${DesignationToLabel(FlowDesignationEnum.Recovery)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${FlowDesignationEnum.StageConfiguration}
|
value=${FlowDesignationEnum.StageConfiguration}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.StageConfiguration}
|
?selected=${this.instance?.designation === FlowDesignationEnum.StageConfiguration}
|
||||||
>
|
>
|
||||||
${t`Stage Configuration`}
|
${DesignationToLabel(FlowDesignationEnum.StageConfiguration)}
|
||||||
</option>
|
</option>
|
||||||
<option
|
<option
|
||||||
value=${FlowDesignationEnum.Unenrollment}
|
value=${FlowDesignationEnum.Unenrollment}
|
||||||
?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}
|
?selected=${this.instance?.designation === FlowDesignationEnum.Unenrollment}
|
||||||
>
|
>
|
||||||
${t`Unenrollment`}
|
${DesignationToLabel(FlowDesignationEnum.Unenrollment)}
|
||||||
</option>
|
</option>
|
||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,8 +14,10 @@ import "../../elements/forms/DeleteBulkForm";
|
||||||
import "../../elements/forms/ModalForm";
|
import "../../elements/forms/ModalForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { TablePage } from "../../elements/table/TablePage";
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
import { groupBy } from "../../utils";
|
||||||
import "./FlowForm";
|
import "./FlowForm";
|
||||||
import "./FlowImportForm";
|
import "./FlowImportForm";
|
||||||
|
import { DesignationToLabel } from "./utils";
|
||||||
|
|
||||||
@customElement("ak-flow-list")
|
@customElement("ak-flow-list")
|
||||||
export class FlowListPage extends TablePage<Flow> {
|
export class FlowListPage extends TablePage<Flow> {
|
||||||
|
@ -46,11 +48,19 @@ export class FlowListPage extends TablePage<Flow> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupBy(items: Flow[]): [string, Flow[]][] {
|
||||||
|
return groupBy(items, (flow) => {
|
||||||
|
if (!flow.designation) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
return DesignationToLabel(flow.designation);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
columns(): TableColumn[] {
|
columns(): TableColumn[] {
|
||||||
return [
|
return [
|
||||||
new TableColumn(t`Identifier`, "slug"),
|
new TableColumn(t`Identifier`, "slug"),
|
||||||
new TableColumn(t`Name`, "name"),
|
new TableColumn(t`Name`, "name"),
|
||||||
new TableColumn(t`Designation`, "designation"),
|
|
||||||
new TableColumn(t`Stages`),
|
new TableColumn(t`Stages`),
|
||||||
new TableColumn(t`Policies`),
|
new TableColumn(t`Policies`),
|
||||||
new TableColumn(t`Actions`),
|
new TableColumn(t`Actions`),
|
||||||
|
@ -85,7 +95,6 @@ export class FlowListPage extends TablePage<Flow> {
|
||||||
<code>${item.slug}</code>
|
<code>${item.slug}</code>
|
||||||
</a>`,
|
</a>`,
|
||||||
html`${item.name}`,
|
html`${item.name}`,
|
||||||
html`${item.designation}`,
|
|
||||||
html`${Array.from(item.stages || []).length}`,
|
html`${Array.from(item.stages || []).length}`,
|
||||||
html`${Array.from(item.policies || []).length}`,
|
html`${Array.from(item.policies || []).length}`,
|
||||||
html` <ak-forms-modal>
|
html` <ak-forms-modal>
|
||||||
|
|
|
@ -0,0 +1,22 @@
|
||||||
|
import { t } from "@lingui/macro";
|
||||||
|
|
||||||
|
import { FlowDesignationEnum } from "@goauthentik/api";
|
||||||
|
|
||||||
|
export function DesignationToLabel(designation: FlowDesignationEnum): string {
|
||||||
|
switch (designation) {
|
||||||
|
case FlowDesignationEnum.Authentication:
|
||||||
|
return t`Authentication`;
|
||||||
|
case FlowDesignationEnum.Authorization:
|
||||||
|
return t`Authorization`;
|
||||||
|
case FlowDesignationEnum.Enrollment:
|
||||||
|
return t`Enrollment`;
|
||||||
|
case FlowDesignationEnum.Invalidation:
|
||||||
|
return t`Invalidation`;
|
||||||
|
case FlowDesignationEnum.Recovery:
|
||||||
|
return t`Recovery`;
|
||||||
|
case FlowDesignationEnum.StageConfiguration:
|
||||||
|
return t`Stage Configuration`;
|
||||||
|
case FlowDesignationEnum.Unenrollment:
|
||||||
|
return t`Unenrollment`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -18,6 +18,7 @@ import "../../elements/forms/ModalForm";
|
||||||
import "../../elements/forms/ProxyForm";
|
import "../../elements/forms/ProxyForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { TablePage } from "../../elements/table/TablePage";
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
import { groupBy } from "../../utils";
|
||||||
import "./PolicyTestForm";
|
import "./PolicyTestForm";
|
||||||
import "./dummy/DummyPolicyForm";
|
import "./dummy/DummyPolicyForm";
|
||||||
import "./event_matcher/EventMatcherPolicyForm";
|
import "./event_matcher/EventMatcherPolicyForm";
|
||||||
|
@ -64,6 +65,10 @@ export class PolicyListPage extends TablePage<Policy> {
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupBy(items: Policy[]): [string, Policy[]][] {
|
||||||
|
return groupBy(items, (policy) => policy.verboseNamePlural);
|
||||||
|
}
|
||||||
|
|
||||||
row(item: Policy): TemplateResult[] {
|
row(item: Policy): TemplateResult[] {
|
||||||
return [
|
return [
|
||||||
html`<div>
|
html`<div>
|
||||||
|
|
|
@ -17,6 +17,7 @@ import "../../elements/forms/ModalForm";
|
||||||
import "../../elements/forms/ProxyForm";
|
import "../../elements/forms/ProxyForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { TablePage } from "../../elements/table/TablePage";
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
import { groupBy } from "../../utils";
|
||||||
import "./PropertyMappingLDAPForm";
|
import "./PropertyMappingLDAPForm";
|
||||||
import "./PropertyMappingNotification";
|
import "./PropertyMappingNotification";
|
||||||
import "./PropertyMappingSAMLForm";
|
import "./PropertyMappingSAMLForm";
|
||||||
|
@ -56,6 +57,10 @@ export class PropertyMappingListPage extends TablePage<PropertyMapping> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupBy(items: PropertyMapping[]): [string, PropertyMapping[]][] {
|
||||||
|
return groupBy(items, (mapping) => mapping.verboseNamePlural);
|
||||||
|
}
|
||||||
|
|
||||||
columns(): TableColumn[] {
|
columns(): TableColumn[] {
|
||||||
return [
|
return [
|
||||||
new TableColumn(t`Name`, "name"),
|
new TableColumn(t`Name`, "name"),
|
||||||
|
|
|
@ -17,7 +17,9 @@ import "../../elements/forms/ModalForm";
|
||||||
import "../../elements/forms/ProxyForm";
|
import "../../elements/forms/ProxyForm";
|
||||||
import { TableColumn } from "../../elements/table/Table";
|
import { TableColumn } from "../../elements/table/Table";
|
||||||
import { TablePage } from "../../elements/table/TablePage";
|
import { TablePage } from "../../elements/table/TablePage";
|
||||||
|
import { groupBy } from "../../utils";
|
||||||
import "./authenticator_duo/AuthenticatorDuoStageForm.ts";
|
import "./authenticator_duo/AuthenticatorDuoStageForm.ts";
|
||||||
|
import "./authenticator_sms/AuthenticatorSMSStageForm.ts";
|
||||||
import "./authenticator_static/AuthenticatorStaticStageForm.ts";
|
import "./authenticator_static/AuthenticatorStaticStageForm.ts";
|
||||||
import "./authenticator_totp/AuthenticatorTOTPStageForm.ts";
|
import "./authenticator_totp/AuthenticatorTOTPStageForm.ts";
|
||||||
import "./authenticator_validate/AuthenticatorValidateStageForm.ts";
|
import "./authenticator_validate/AuthenticatorValidateStageForm.ts";
|
||||||
|
@ -65,6 +67,10 @@ export class StageListPage extends TablePage<Stage> {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
groupBy(items: Stage[]): [string, Stage[]][] {
|
||||||
|
return groupBy(items, (stage) => stage.verboseNamePlural);
|
||||||
|
}
|
||||||
|
|
||||||
columns(): TableColumn[] {
|
columns(): TableColumn[] {
|
||||||
return [
|
return [
|
||||||
new TableColumn(t`Name`, "name"),
|
new TableColumn(t`Name`, "name"),
|
||||||
|
|
|
@ -0,0 +1,169 @@
|
||||||
|
import { t } from "@lingui/macro";
|
||||||
|
|
||||||
|
import { html, TemplateResult } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { ifDefined } from "lit/directives/if-defined";
|
||||||
|
import { until } from "lit/directives/until";
|
||||||
|
|
||||||
|
import {
|
||||||
|
FlowsApi,
|
||||||
|
StagesApi,
|
||||||
|
FlowsInstancesListDesignationEnum,
|
||||||
|
AuthenticatorSMSStage,
|
||||||
|
ProviderEnum,
|
||||||
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import "../../../elements/forms/FormGroup";
|
||||||
|
import "../../../elements/forms/HorizontalFormElement";
|
||||||
|
import { ModelForm } from "../../../elements/forms/ModelForm";
|
||||||
|
|
||||||
|
@customElement("ak-stage-authenticator-sms-form")
|
||||||
|
export class AuthenticatorSMSStageForm extends ModelForm<AuthenticatorSMSStage, string> {
|
||||||
|
loadInstance(pk: string): Promise<AuthenticatorSMSStage> {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorSmsRetrieve({
|
||||||
|
stageUuid: pk,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
getSuccessMessage(): string {
|
||||||
|
if (this.instance) {
|
||||||
|
return t`Successfully updated stage.`;
|
||||||
|
} else {
|
||||||
|
return t`Successfully created stage.`;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
send = (data: AuthenticatorSMSStage): Promise<AuthenticatorSMSStage> => {
|
||||||
|
if (this.instance) {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorSmsUpdate({
|
||||||
|
stageUuid: this.instance.pk || "",
|
||||||
|
authenticatorSMSStageRequest: data,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return new StagesApi(DEFAULT_CONFIG).stagesAuthenticatorSmsCreate({
|
||||||
|
authenticatorSMSStageRequest: data,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
renderForm(): TemplateResult {
|
||||||
|
return html`<form class="pf-c-form pf-m-horizontal">
|
||||||
|
<div class="form-help-text">
|
||||||
|
${t`Stage used to configure an SMS-based TOTP authenticator.`}
|
||||||
|
</div>
|
||||||
|
<ak-form-element-horizontal label=${t`Name`} ?required=${true} name="name">
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="${ifDefined(this.instance?.name || "")}"
|
||||||
|
class="pf-c-form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-group .expanded=${true}>
|
||||||
|
<span slot="header"> ${t`Stage-specific settings`} </span>
|
||||||
|
<div slot="body" class="pf-c-form">
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${t`Provider`}
|
||||||
|
?required=${true}
|
||||||
|
name="provider"
|
||||||
|
>
|
||||||
|
<select name="users" class="pf-c-form-control">
|
||||||
|
<option
|
||||||
|
value="${ProviderEnum.Twilio}"
|
||||||
|
?selected=${this.instance?.provider === ProviderEnum.Twilio}
|
||||||
|
>
|
||||||
|
${t`Twilio`}
|
||||||
|
</option>
|
||||||
|
</select>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${t`From number`}
|
||||||
|
?required=${true}
|
||||||
|
name="fromNumber"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="${ifDefined(this.instance?.fromNumber || "")}"
|
||||||
|
class="pf-c-form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${t`Number the SMS will be sent from.`}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${t`Twilio Account SID`}
|
||||||
|
?required=${true}
|
||||||
|
name="twilioAccountSid"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="${ifDefined(this.instance?.twilioAccountSid || "")}"
|
||||||
|
class="pf-c-form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${t`Get this value from https://console.twilio.com`}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal
|
||||||
|
label=${t`Twilio Auth Token`}
|
||||||
|
?required=${true}
|
||||||
|
name="twilioAuth"
|
||||||
|
>
|
||||||
|
<input
|
||||||
|
type="text"
|
||||||
|
value="${ifDefined(this.instance?.twilioAuth || "")}"
|
||||||
|
class="pf-c-form-control"
|
||||||
|
required
|
||||||
|
/>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${t`Get this value from https://console.twilio.com`}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
<ak-form-element-horizontal label=${t`Configuration flow`} name="configureFlow">
|
||||||
|
<select class="pf-c-form-control">
|
||||||
|
<option
|
||||||
|
value=""
|
||||||
|
?selected=${this.instance?.configureFlow === undefined}
|
||||||
|
>
|
||||||
|
---------
|
||||||
|
</option>
|
||||||
|
${until(
|
||||||
|
new FlowsApi(DEFAULT_CONFIG)
|
||||||
|
.flowsInstancesList({
|
||||||
|
ordering: "pk",
|
||||||
|
designation:
|
||||||
|
FlowsInstancesListDesignationEnum.StageConfiguration,
|
||||||
|
})
|
||||||
|
.then((flows) => {
|
||||||
|
return flows.results.map((flow) => {
|
||||||
|
let selected = this.instance?.configureFlow === flow.pk;
|
||||||
|
if (
|
||||||
|
!this.instance?.pk &&
|
||||||
|
!this.instance?.configureFlow &&
|
||||||
|
flow.slug === "default-otp-time-configure"
|
||||||
|
) {
|
||||||
|
selected = true;
|
||||||
|
}
|
||||||
|
return html`<option
|
||||||
|
value=${ifDefined(flow.pk)}
|
||||||
|
?selected=${selected}
|
||||||
|
>
|
||||||
|
${flow.name} (${flow.slug})
|
||||||
|
</option>`;
|
||||||
|
});
|
||||||
|
}),
|
||||||
|
html`<option>${t`Loading...`}</option>`,
|
||||||
|
)}
|
||||||
|
</select>
|
||||||
|
<p class="pf-c-form__helper-text">
|
||||||
|
${t`Flow used by an authenticated user to configure this Stage. If empty, user will not be able to configure this stage.`}
|
||||||
|
</p>
|
||||||
|
</ak-form-element-horizontal>
|
||||||
|
</div>
|
||||||
|
</ak-form-group>
|
||||||
|
</form>`;
|
||||||
|
}
|
||||||
|
}
|
|
@ -10,6 +10,7 @@ import {
|
||||||
AuthenticatorTOTPStage,
|
AuthenticatorTOTPStage,
|
||||||
StagesApi,
|
StagesApi,
|
||||||
FlowsInstancesListDesignationEnum,
|
FlowsInstancesListDesignationEnum,
|
||||||
|
DigitsEnum,
|
||||||
} from "@goauthentik/api";
|
} from "@goauthentik/api";
|
||||||
|
|
||||||
import { DEFAULT_CONFIG } from "../../../api/Config";
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
@ -64,10 +65,16 @@ export class AuthenticatorTOTPStageForm extends ModelForm<AuthenticatorTOTPStage
|
||||||
<div slot="body" class="pf-c-form">
|
<div slot="body" class="pf-c-form">
|
||||||
<ak-form-element-horizontal label=${t`Digits`} ?required=${true} name="digits">
|
<ak-form-element-horizontal label=${t`Digits`} ?required=${true} name="digits">
|
||||||
<select name="users" class="pf-c-form-control">
|
<select name="users" class="pf-c-form-control">
|
||||||
<option value="6" ?selected=${this.instance?.digits === 6}>
|
<option
|
||||||
|
value="${DigitsEnum.NUMBER_6}"
|
||||||
|
?selected=${this.instance?.digits === DigitsEnum.NUMBER_6}
|
||||||
|
>
|
||||||
${t`6 digits, widely compatible`}
|
${t`6 digits, widely compatible`}
|
||||||
</option>
|
</option>
|
||||||
<option value="8" ?selected=${this.instance?.digits === 8}>
|
<option
|
||||||
|
value="${DigitsEnum.NUMBER_8}"
|
||||||
|
?selected=${this.instance?.digits === DigitsEnum.NUMBER_8}
|
||||||
|
>
|
||||||
${t`8 digits, not compatible with apps like Google Authenticator`}
|
${t`8 digits, not compatible with apps like Google Authenticator`}
|
||||||
</option>
|
</option>
|
||||||
</select>
|
</select>
|
||||||
|
|
|
@ -109,6 +109,12 @@ export class AuthenticatorValidateStageForm extends ModelForm<AuthenticatorValid
|
||||||
>
|
>
|
||||||
${t`Duo Authenticators`}
|
${t`Duo Authenticators`}
|
||||||
</option>
|
</option>
|
||||||
|
<option
|
||||||
|
value=${DeviceClassesEnum.Sms}
|
||||||
|
?selected=${this.isDeviceClassSelected(DeviceClassesEnum.Sms)}
|
||||||
|
>
|
||||||
|
${t`SMS-based Authenticators`}
|
||||||
|
</option>
|
||||||
</select>
|
</select>
|
||||||
<p class="pf-c-form__helper-text">
|
<p class="pf-c-form__helper-text">
|
||||||
${t`Device classes which can be used to authenticate.`}
|
${t`Device classes which can be used to authenticate.`}
|
||||||
|
|
|
@ -12,6 +12,7 @@ import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
import { EVENT_REFRESH } from "../../../constants";
|
import { EVENT_REFRESH } from "../../../constants";
|
||||||
import "../../../elements/EmptyState";
|
import "../../../elements/EmptyState";
|
||||||
import "./UserSettingsAuthenticatorDuo";
|
import "./UserSettingsAuthenticatorDuo";
|
||||||
|
import "./UserSettingsAuthenticatorSMS";
|
||||||
import "./UserSettingsAuthenticatorStatic";
|
import "./UserSettingsAuthenticatorStatic";
|
||||||
import "./UserSettingsAuthenticatorTOTP";
|
import "./UserSettingsAuthenticatorTOTP";
|
||||||
import "./UserSettingsAuthenticatorWebAuthn";
|
import "./UserSettingsAuthenticatorWebAuthn";
|
||||||
|
@ -69,6 +70,12 @@ export class UserStageSettingsPage extends LitElement {
|
||||||
.configureUrl=${stage.configureUrl}
|
.configureUrl=${stage.configureUrl}
|
||||||
>
|
>
|
||||||
</ak-user-settings-authenticator-duo>`;
|
</ak-user-settings-authenticator-duo>`;
|
||||||
|
case "ak-user-settings-authenticator-sms":
|
||||||
|
return html`<ak-user-settings-authenticator-sms
|
||||||
|
objectId=${stage.objectUid}
|
||||||
|
.configureUrl=${stage.configureUrl}
|
||||||
|
>
|
||||||
|
</ak-user-settings-authenticator-sms>`;
|
||||||
default:
|
default:
|
||||||
return html`<p>${t`Error: unsupported stage settings: ${stage.component}`}</p>`;
|
return html`<p>${t`Error: unsupported stage settings: ${stage.component}`}</p>`;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
import { t } from "@lingui/macro";
|
||||||
|
|
||||||
|
import { html, TemplateResult } from "lit";
|
||||||
|
import { customElement } from "lit/decorators";
|
||||||
|
import { until } from "lit/directives/until";
|
||||||
|
|
||||||
|
import { AuthenticatorsApi } from "@goauthentik/api";
|
||||||
|
|
||||||
|
import { DEFAULT_CONFIG } from "../../../api/Config";
|
||||||
|
import { EVENT_REFRESH } from "../../../constants";
|
||||||
|
import { BaseUserSettings } from "../BaseUserSettings";
|
||||||
|
|
||||||
|
@customElement("ak-user-settings-authenticator-sms")
|
||||||
|
export class UserSettingsAuthenticatorSMS extends BaseUserSettings {
|
||||||
|
renderEnabled(): TemplateResult {
|
||||||
|
return html`<div class="pf-c-card__body">
|
||||||
|
<p>
|
||||||
|
${t`Status: Enabled`}
|
||||||
|
<i class="pf-icon pf-icon-ok"></i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card__footer">
|
||||||
|
<button
|
||||||
|
class="pf-c-button pf-m-danger"
|
||||||
|
@click=${() => {
|
||||||
|
return new AuthenticatorsApi(DEFAULT_CONFIG)
|
||||||
|
.authenticatorsSmsList({})
|
||||||
|
.then((devices) => {
|
||||||
|
if (devices.results.length < 1) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// TODO: Handle multiple devices, currently we assume only one TOTP Device
|
||||||
|
return new AuthenticatorsApi(DEFAULT_CONFIG)
|
||||||
|
.authenticatorsSmsDestroy({
|
||||||
|
id: devices.results[0].pk || 0,
|
||||||
|
})
|
||||||
|
.then(() => {
|
||||||
|
this.dispatchEvent(
|
||||||
|
new CustomEvent(EVENT_REFRESH, {
|
||||||
|
bubbles: true,
|
||||||
|
composed: true,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
${t`Disable SMS authenticator`}
|
||||||
|
</button>
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
renderDisabled(): TemplateResult {
|
||||||
|
return html` <div class="pf-c-card__body">
|
||||||
|
<p>
|
||||||
|
${t`Status: Disabled`}
|
||||||
|
<i class="pf-icon pf-icon-error-circle-o"></i>
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
<div class="pf-c-card__footer">
|
||||||
|
${this.configureUrl
|
||||||
|
? html`<a
|
||||||
|
href="${this.configureUrl}?next=/${encodeURIComponent("#/settings")}"
|
||||||
|
class="pf-c-button pf-m-primary"
|
||||||
|
>${t`Enable SMS authenticator`}
|
||||||
|
</a>`
|
||||||
|
: html``}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
|
||||||
|
render(): TemplateResult {
|
||||||
|
return html`<div class="pf-c-card">
|
||||||
|
<div class="pf-c-card__title">${t`SMS`}</div>
|
||||||
|
${until(
|
||||||
|
new AuthenticatorsApi(DEFAULT_CONFIG).authenticatorsSmsList({}).then((devices) => {
|
||||||
|
return devices.results.length > 0
|
||||||
|
? this.renderEnabled()
|
||||||
|
: this.renderDisabled();
|
||||||
|
}),
|
||||||
|
)}
|
||||||
|
</div>`;
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue