Merge branch 'web/config-provider' into web/config-provider-2-tenant
* web/config-provider: (23 commits) web: Added a README with a description of the applications' "mental model," essentially an architectural description. stages/email: improve error handling for incorrect template syntax (#7758) core: bump github.com/go-openapi/strfmt from 0.21.7 to 0.21.8 (#7768) website: bump postcss from 8.4.31 to 8.4.32 in /website (#7770) web: bump the eslint group in /tests/wdio with 1 update (#7773) website: bump @types/react from 18.2.39 to 18.2.41 in /website (#7769) web: bump the eslint group in /web with 1 update (#7772) website: fix typos in example URLs (#7774) root: include ca-certificates in container (#7763) root: don't show warning when app has no URLs to import (#7765) web: revert storybook (#7764) web: bump the eslint group in /web with 2 updates (#7730) website: bump @types/react from 18.2.38 to 18.2.39 in /website (#7720) web: bump the storybook group in /web with 5 updates (#7750) website/blog: fix email syntax (#7753) web: bump the wdio group in /tests/wdio with 3 updates (#7751) web: bump the babel group in /web with 3 updates (#7741) web: bump the sentry group in /web with 2 updates (#7747) web: bump pyright from 1.1.337 to 1.1.338 in /web (#7743) website: bump the docusaurus group in /website with 9 updates (#7746) ...
This commit is contained in:
commit
6cf2de8a7c
|
@ -121,7 +121,7 @@ WORKDIR /
|
||||||
# We cannot cache this layer otherwise we'll end up with a bigger image
|
# We cannot cache this layer otherwise we'll end up with a bigger image
|
||||||
RUN apt-get update && \
|
RUN apt-get update && \
|
||||||
# Required for runtime
|
# Required for runtime
|
||||||
apt-get install -y --no-install-recommends libpq5 openssl libxmlsec1-openssl libmaxminddb0 && \
|
apt-get install -y --no-install-recommends libpq5 openssl libxmlsec1-openssl libmaxminddb0 ca-certificates && \
|
||||||
# Required for bootstrap & healtcheck
|
# Required for bootstrap & healtcheck
|
||||||
apt-get install -y --no-install-recommends runit && \
|
apt-get install -y --no-install-recommends runit && \
|
||||||
apt-get clean && \
|
apt-get clean && \
|
||||||
|
|
|
@ -21,7 +21,9 @@ _other_urls = []
|
||||||
for _authentik_app in get_apps():
|
for _authentik_app in get_apps():
|
||||||
try:
|
try:
|
||||||
api_urls = import_module(f"{_authentik_app.name}.urls")
|
api_urls = import_module(f"{_authentik_app.name}.urls")
|
||||||
except (ModuleNotFoundError, ImportError) as exc:
|
except ModuleNotFoundError:
|
||||||
|
continue
|
||||||
|
except ImportError as exc:
|
||||||
LOGGER.warning("Could not import app's URLs", app_name=_authentik_app.name, exc=exc)
|
LOGGER.warning("Could not import app's URLs", app_name=_authentik_app.name, exc=exc)
|
||||||
continue
|
continue
|
||||||
if not hasattr(api_urls, "api_urlpatterns"):
|
if not hasattr(api_urls, "api_urlpatterns"):
|
||||||
|
|
|
@ -38,7 +38,7 @@ class SourceSerializer(ModelSerializer, MetaNameSerializer):
|
||||||
|
|
||||||
managed = ReadOnlyField()
|
managed = ReadOnlyField()
|
||||||
component = SerializerMethodField()
|
component = SerializerMethodField()
|
||||||
icon = ReadOnlyField(source="get_icon")
|
icon = ReadOnlyField(source="icon_url")
|
||||||
|
|
||||||
def get_component(self, obj: Source) -> str:
|
def get_component(self, obj: Source) -> str:
|
||||||
"""Get object component so that we know how to edit the object"""
|
"""Get object component so that we know how to edit the object"""
|
||||||
|
|
|
@ -167,7 +167,11 @@ class ChallengeStageView(StageView):
|
||||||
stage_type=self.__class__.__name__, method="get_challenge"
|
stage_type=self.__class__.__name__, method="get_challenge"
|
||||||
).time(),
|
).time(),
|
||||||
):
|
):
|
||||||
challenge = self.get_challenge(*args, **kwargs)
|
try:
|
||||||
|
challenge = self.get_challenge(*args, **kwargs)
|
||||||
|
except StageInvalidException as exc:
|
||||||
|
self.logger.debug("Got StageInvalidException", exc=exc)
|
||||||
|
return self.executor.stage_invalid()
|
||||||
with Hub.current.start_span(
|
with Hub.current.start_span(
|
||||||
op="authentik.flow.stage._get_challenge",
|
op="authentik.flow.stage._get_challenge",
|
||||||
description=self.__class__.__name__,
|
description=self.__class__.__name__,
|
||||||
|
|
|
@ -5,6 +5,7 @@ from uuid import uuid4
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.http import HttpRequest, HttpResponse
|
from django.http import HttpRequest, HttpResponse
|
||||||
from django.http.request import QueryDict
|
from django.http.request import QueryDict
|
||||||
|
from django.template.exceptions import TemplateSyntaxError
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.text import slugify
|
from django.utils.text import slugify
|
||||||
from django.utils.timezone import now
|
from django.utils.timezone import now
|
||||||
|
@ -12,11 +13,14 @@ from django.utils.translation import gettext as _
|
||||||
from rest_framework.fields import CharField
|
from rest_framework.fields import CharField
|
||||||
from rest_framework.serializers import ValidationError
|
from rest_framework.serializers import ValidationError
|
||||||
|
|
||||||
|
from authentik.events.models import Event, EventAction
|
||||||
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
from authentik.flows.challenge import Challenge, ChallengeResponse, ChallengeTypes
|
||||||
|
from authentik.flows.exceptions import StageInvalidException
|
||||||
from authentik.flows.models import FlowDesignation, FlowToken
|
from authentik.flows.models import FlowDesignation, FlowToken
|
||||||
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
|
from authentik.flows.planner import PLAN_CONTEXT_IS_RESTORED, PLAN_CONTEXT_PENDING_USER
|
||||||
from authentik.flows.stage import ChallengeStageView
|
from authentik.flows.stage import ChallengeStageView
|
||||||
from authentik.flows.views.executor import QS_KEY_TOKEN, QS_QUERY
|
from authentik.flows.views.executor import QS_KEY_TOKEN, QS_QUERY
|
||||||
|
from authentik.lib.utils.errors import exception_to_string
|
||||||
from authentik.stages.email.models import EmailStage
|
from authentik.stages.email.models import EmailStage
|
||||||
from authentik.stages.email.tasks import send_mails
|
from authentik.stages.email.tasks import send_mails
|
||||||
from authentik.stages.email.utils import TemplateEmailMessage
|
from authentik.stages.email.utils import TemplateEmailMessage
|
||||||
|
@ -103,18 +107,27 @@ class EmailStageView(ChallengeStageView):
|
||||||
current_stage: EmailStage = self.executor.current_stage
|
current_stage: EmailStage = self.executor.current_stage
|
||||||
token = self.get_token()
|
token = self.get_token()
|
||||||
# Send mail to user
|
# Send mail to user
|
||||||
message = TemplateEmailMessage(
|
try:
|
||||||
subject=_(current_stage.subject),
|
message = TemplateEmailMessage(
|
||||||
to=[email],
|
subject=_(current_stage.subject),
|
||||||
language=pending_user.locale(self.request),
|
to=[email],
|
||||||
template_name=current_stage.template,
|
language=pending_user.locale(self.request),
|
||||||
template_context={
|
template_name=current_stage.template,
|
||||||
"url": self.get_full_url(**{QS_KEY_TOKEN: token.key}),
|
template_context={
|
||||||
"user": pending_user,
|
"url": self.get_full_url(**{QS_KEY_TOKEN: token.key}),
|
||||||
"expires": token.expires,
|
"user": pending_user,
|
||||||
},
|
"expires": token.expires,
|
||||||
)
|
},
|
||||||
send_mails(current_stage, message)
|
)
|
||||||
|
send_mails(current_stage, message)
|
||||||
|
except TemplateSyntaxError as exc:
|
||||||
|
Event.new(
|
||||||
|
EventAction.CONFIGURATION_ERROR,
|
||||||
|
message=_("Exception occurred while rendering E-mail template"),
|
||||||
|
error=exception_to_string(exc),
|
||||||
|
template=current_stage.template,
|
||||||
|
).from_http(self.request)
|
||||||
|
raise StageInvalidException from exc
|
||||||
|
|
||||||
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
def get(self, request: HttpRequest, *args, **kwargs) -> HttpResponse:
|
||||||
# Check if the user came back from the email link to verify
|
# Check if the user came back from the email link to verify
|
||||||
|
@ -135,7 +148,11 @@ class EmailStageView(ChallengeStageView):
|
||||||
return self.executor.stage_invalid()
|
return self.executor.stage_invalid()
|
||||||
# Check if we've already sent the initial e-mail
|
# Check if we've already sent the initial e-mail
|
||||||
if PLAN_CONTEXT_EMAIL_SENT not in self.executor.plan.context:
|
if PLAN_CONTEXT_EMAIL_SENT not in self.executor.plan.context:
|
||||||
self.send_email()
|
try:
|
||||||
|
self.send_email()
|
||||||
|
except StageInvalidException as exc:
|
||||||
|
self.logger.debug("Got StageInvalidException", exc=exc)
|
||||||
|
return self.executor.stage_invalid()
|
||||||
self.executor.plan.context[PLAN_CONTEXT_EMAIL_SENT] = True
|
self.executor.plan.context[PLAN_CONTEXT_EMAIL_SENT] = True
|
||||||
return super().get(request, *args, **kwargs)
|
return super().get(request, *args, **kwargs)
|
||||||
|
|
||||||
|
|
|
@ -4,11 +4,20 @@ from pathlib import Path
|
||||||
from shutil import rmtree
|
from shutil import rmtree
|
||||||
from tempfile import mkdtemp, mkstemp
|
from tempfile import mkdtemp, mkstemp
|
||||||
from typing import Any
|
from typing import Any
|
||||||
|
from unittest.mock import PropertyMock, patch
|
||||||
|
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from django.test import TestCase
|
from django.core.mail.backends.locmem import EmailBackend
|
||||||
|
from django.urls import reverse
|
||||||
|
|
||||||
from authentik.stages.email.models import get_template_choices
|
from authentik.core.tests.utils import create_test_admin_user, create_test_flow
|
||||||
|
from authentik.events.models import Event, EventAction
|
||||||
|
from authentik.flows.markers import StageMarker
|
||||||
|
from authentik.flows.models import FlowDesignation, FlowStageBinding
|
||||||
|
from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan
|
||||||
|
from authentik.flows.tests import FlowTestCase
|
||||||
|
from authentik.flows.views.executor import SESSION_KEY_PLAN
|
||||||
|
from authentik.stages.email.models import EmailStage, get_template_choices
|
||||||
|
|
||||||
|
|
||||||
def get_templates_setting(temp_dir: str) -> dict[str, Any]:
|
def get_templates_setting(temp_dir: str) -> dict[str, Any]:
|
||||||
|
@ -18,11 +27,18 @@ def get_templates_setting(temp_dir: str) -> dict[str, Any]:
|
||||||
return templates_setting
|
return templates_setting
|
||||||
|
|
||||||
|
|
||||||
class TestEmailStageTemplates(TestCase):
|
class TestEmailStageTemplates(FlowTestCase):
|
||||||
"""Email tests"""
|
"""Email tests"""
|
||||||
|
|
||||||
def setUp(self) -> None:
|
def setUp(self) -> None:
|
||||||
self.dir = mkdtemp()
|
self.dir = Path(mkdtemp())
|
||||||
|
self.user = create_test_admin_user()
|
||||||
|
|
||||||
|
self.flow = create_test_flow(FlowDesignation.AUTHENTICATION)
|
||||||
|
self.stage = EmailStage.objects.create(
|
||||||
|
name="email",
|
||||||
|
)
|
||||||
|
self.binding = FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2)
|
||||||
|
|
||||||
def tearDown(self) -> None:
|
def tearDown(self) -> None:
|
||||||
rmtree(self.dir)
|
rmtree(self.dir)
|
||||||
|
@ -38,3 +54,37 @@ class TestEmailStageTemplates(TestCase):
|
||||||
self.assertEqual(len(choices), 3)
|
self.assertEqual(len(choices), 3)
|
||||||
unlink(file)
|
unlink(file)
|
||||||
unlink(file2)
|
unlink(file2)
|
||||||
|
|
||||||
|
def test_custom_template_invalid_syntax(self):
|
||||||
|
"""Test with custom template"""
|
||||||
|
with open(self.dir / Path("invalid.html"), "w+", encoding="utf-8") as _invalid:
|
||||||
|
_invalid.write("{% blocktranslate %}")
|
||||||
|
with self.settings(TEMPLATES=get_templates_setting(self.dir)):
|
||||||
|
self.stage.template = "invalid.html"
|
||||||
|
plan = FlowPlan(
|
||||||
|
flow_pk=self.flow.pk.hex, bindings=[self.binding], markers=[StageMarker()]
|
||||||
|
)
|
||||||
|
plan.context[PLAN_CONTEXT_PENDING_USER] = self.user
|
||||||
|
session = self.client.session
|
||||||
|
session[SESSION_KEY_PLAN] = plan
|
||||||
|
session.save()
|
||||||
|
|
||||||
|
url = reverse("authentik_api:flow-executor", kwargs={"flow_slug": self.flow.slug})
|
||||||
|
with patch(
|
||||||
|
"authentik.stages.email.models.EmailStage.backend_class",
|
||||||
|
PropertyMock(return_value=EmailBackend),
|
||||||
|
):
|
||||||
|
response = self.client.get(url)
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertStageResponse(
|
||||||
|
response,
|
||||||
|
self.flow,
|
||||||
|
error_message="Unknown error",
|
||||||
|
)
|
||||||
|
events = Event.objects.filter(action=EventAction.CONFIGURATION_ERROR)
|
||||||
|
self.assertEqual(len(events), 1)
|
||||||
|
event = events.first()
|
||||||
|
self.assertEqual(
|
||||||
|
event.context["message"], "Exception occurred while rendering E-mail template"
|
||||||
|
)
|
||||||
|
self.assertEqual(event.context["template"], "invalid.html")
|
||||||
|
|
2
go.mod
2
go.mod
|
@ -10,7 +10,7 @@ require (
|
||||||
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
github.com/go-http-utils/etag v0.0.0-20161124023236-513ea8f21eb1
|
||||||
github.com/go-ldap/ldap/v3 v3.4.6
|
github.com/go-ldap/ldap/v3 v3.4.6
|
||||||
github.com/go-openapi/runtime v0.26.0
|
github.com/go-openapi/runtime v0.26.0
|
||||||
github.com/go-openapi/strfmt v0.21.7
|
github.com/go-openapi/strfmt v0.21.8
|
||||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||||
github.com/google/uuid v1.4.0
|
github.com/google/uuid v1.4.0
|
||||||
github.com/gorilla/handlers v1.5.2
|
github.com/gorilla/handlers v1.5.2
|
||||||
|
|
4
go.sum
4
go.sum
|
@ -123,8 +123,8 @@ github.com/go-openapi/spec v0.20.8/go.mod h1:2OpW+JddWPrpXSCIX8eOx7lZ5iyuWj3RYR6
|
||||||
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
|
github.com/go-openapi/strfmt v0.21.0/go.mod h1:ZRQ409bWMj+SOgXofQAGTIo2Ebu72Gs+WaRADcS5iNg=
|
||||||
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
github.com/go-openapi/strfmt v0.21.1/go.mod h1:I/XVKeLc5+MM5oPNN7P6urMOpuLXEcNrCX/rPGuWb0k=
|
||||||
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
|
github.com/go-openapi/strfmt v0.21.3/go.mod h1:k+RzNO0Da+k3FrrynSNN8F7n/peCmQQqbbXjtDfvmGg=
|
||||||
github.com/go-openapi/strfmt v0.21.7 h1:rspiXgNWgeUzhjo1YU01do6qsahtJNByjLVbPLNHb8k=
|
github.com/go-openapi/strfmt v0.21.8 h1:VYBUoKYRLAlgKDrIxR/I0lKrztDQ0tuTDrbhLVP8Erg=
|
||||||
github.com/go-openapi/strfmt v0.21.7/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
|
github.com/go-openapi/strfmt v0.21.8/go.mod h1:adeGTkxE44sPyLk0JV235VQAO/ZXUr8KAzYjclFs3ew=
|
||||||
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
github.com/go-openapi/swag v0.19.5/go.mod h1:POnQmlKehdgb5mhVOsnJFsivZCEZ/vjK9gh66Z9tfKk=
|
||||||
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.19.15/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
github.com/go-openapi/swag v0.21.1/go.mod h1:QYRuS/SOXUCsnplDa677K7+DxSOj6IPNl/eQntq43wQ=
|
||||||
|
|
120
tests/wdio/package-lock.json
generated
120
tests/wdio/package-lock.json
generated
|
@ -9,11 +9,11 @@
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
||||||
"@typescript-eslint/parser": "^6.13.1",
|
"@typescript-eslint/parser": "^6.13.1",
|
||||||
"@wdio/cli": "^8.24.3",
|
"@wdio/cli": "^8.24.6",
|
||||||
"@wdio/local-runner": "^8.24.3",
|
"@wdio/local-runner": "^8.24.6",
|
||||||
"@wdio/mocha-framework": "^8.24.3",
|
"@wdio/mocha-framework": "^8.24.6",
|
||||||
"@wdio/spec-reporter": "^8.24.2",
|
"@wdio/spec-reporter": "^8.24.2",
|
||||||
"eslint": "^8.54.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-sonarjs": "^0.23.0",
|
"eslint-plugin-sonarjs": "^0.23.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
|
@ -332,9 +332,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/eslintrc": {
|
"node_modules/@eslint/eslintrc": {
|
||||||
"version": "2.1.3",
|
"version": "2.1.4",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz",
|
||||||
"integrity": "sha512-yZzuIG+jnVu6hNSzFEN07e8BxF3uAzYtQb6uDkaYZLo6oYZDCq454c5kB8zxnzfCYyP4MIuyBn10L0DqwujTmA==",
|
"integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ajv": "^6.12.4",
|
"ajv": "^6.12.4",
|
||||||
|
@ -382,9 +382,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "8.54.0",
|
"version": "8.55.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.55.0.tgz",
|
||||||
"integrity": "sha512-ut5V+D+fOoWPgGGNj83GGjnntO39xDy6DWxO0wb7Jp3DcMX0TfIqdzHF85VTQkerdyGmuuMD9AKAo5KiNlf/AQ==",
|
"integrity": "sha512-qQfo2mxH5yVom1kacMtZZJFVdW+E70mqHMJvVg6WTLo+VBuQJ4TojZlfWBjK0ve5BdEeNAVxOsl/nvNMpJOaJA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||||
|
@ -1141,18 +1141,18 @@
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/cli": {
|
"node_modules/@wdio/cli": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/cli/-/cli-8.24.6.tgz",
|
||||||
"integrity": "sha512-yJBsYubAws7X9i2vgM/9VOnI+f7YpaeVv4utz8DEXFTWtNm5X0OVqUBZnU173OXLuNan9ychaH7L1Fyth1KYnA==",
|
"integrity": "sha512-QXRiP1FeGaSmUO24pFhyzP6lZY/FsZAhXyofl3r6TGwTlnw9i4S7C4Te2qQcccgAQq03rdSK058YURPwbiKhmg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.1",
|
"@types/node": "^20.1.1",
|
||||||
"@wdio/config": "8.24.3",
|
"@wdio/config": "8.24.6",
|
||||||
"@wdio/globals": "8.24.3",
|
"@wdio/globals": "8.24.6",
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/protocols": "8.23.0",
|
"@wdio/protocols": "8.23.0",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"@wdio/utils": "8.24.3",
|
"@wdio/utils": "8.24.6",
|
||||||
"async-exit-hook": "^2.0.1",
|
"async-exit-hook": "^2.0.1",
|
||||||
"chalk": "^5.2.0",
|
"chalk": "^5.2.0",
|
||||||
"chokidar": "^3.5.3",
|
"chokidar": "^3.5.3",
|
||||||
|
@ -1168,7 +1168,7 @@
|
||||||
"lodash.union": "^4.6.0",
|
"lodash.union": "^4.6.0",
|
||||||
"read-pkg-up": "^10.0.0",
|
"read-pkg-up": "^10.0.0",
|
||||||
"recursive-readdir": "^2.2.3",
|
"recursive-readdir": "^2.2.3",
|
||||||
"webdriverio": "8.24.3",
|
"webdriverio": "8.24.6",
|
||||||
"yargs": "^17.7.2"
|
"yargs": "^17.7.2"
|
||||||
},
|
},
|
||||||
"bin": {
|
"bin": {
|
||||||
|
@ -1191,14 +1191,14 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/config": {
|
"node_modules/@wdio/config": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/config/-/config-8.24.6.tgz",
|
||||||
"integrity": "sha512-KXJ3qKJTTOa0nwwPtCxxgYBMfqGghij8bEg7DTGkydyuqVvBTSc0py7tXmSI4Uoh7ZdpZxZ6Q9C+Y3CVQhaiWQ==",
|
"integrity": "sha512-ZFmd6rB1kgL4k/SjLXbtFTCxvxSf1qzdt/losiTqkqFBYznkTRUBGSoGaVTlkMtHAReiVSK92sICc15JWaCdEA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"@wdio/utils": "8.24.3",
|
"@wdio/utils": "8.24.6",
|
||||||
"decamelize": "^6.0.0",
|
"decamelize": "^6.0.0",
|
||||||
"deepmerge-ts": "^5.0.0",
|
"deepmerge-ts": "^5.0.0",
|
||||||
"glob": "^10.2.2",
|
"glob": "^10.2.2",
|
||||||
|
@ -1209,28 +1209,28 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/globals": {
|
"node_modules/@wdio/globals": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/globals/-/globals-8.24.6.tgz",
|
||||||
"integrity": "sha512-hxCe5qKl1eBSqNtI5MVSBqO5E0PR+KEal7/mAYYLN4YFUUEwNFXlamUrkbM9lj5VyYf29RAig+Mt4LgTCYaReA==",
|
"integrity": "sha512-v5Sjyix9ddrxPM8DCf0vADUxr21Fx7nWVYS6Z/gkTEhuQbi5svjs6EGjMmErO6tp3CY4SNTUiz+ZFJw9YH4Swg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.13 || >=18"
|
"node": "^16.13 || >=18"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"expect-webdriverio": "^4.6.1",
|
"expect-webdriverio": "^4.6.1",
|
||||||
"webdriverio": "8.24.3"
|
"webdriverio": "8.24.6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/local-runner": {
|
"node_modules/@wdio/local-runner": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/local-runner/-/local-runner-8.24.6.tgz",
|
||||||
"integrity": "sha512-zSlLYta2IOgAySza9U829VTpQ9+5etfMJrjuzTKwILWOhH6uHOTyLnYVQZgp5GIcEhcPevKGJAsnD3CkYopBxg==",
|
"integrity": "sha512-fd91CxlVpOpSxg+QuqgdFl66kEtY7R/ohdKBXNhdMXtXFb4EQIGp/igiMBvuTHcHUMHOw3N8KaHfe6YXo+6Qyw==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/repl": "8.23.1",
|
"@wdio/repl": "8.23.1",
|
||||||
"@wdio/runner": "8.24.3",
|
"@wdio/runner": "8.24.6",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"async-exit-hook": "^2.0.1",
|
"async-exit-hook": "^2.0.1",
|
||||||
"split2": "^4.1.0",
|
"split2": "^4.1.0",
|
||||||
|
@ -1268,16 +1268,16 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/mocha-framework": {
|
"node_modules/@wdio/mocha-framework": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/mocha-framework/-/mocha-framework-8.24.6.tgz",
|
||||||
"integrity": "sha512-6+ew6hWEETiy1ZANX1XUY9XbGQ/gMQsDfINlzUGVoh8YzptcU9Su+7QtfZBw4ioo5CrDVDlg4X3CKN6VDBp6Bg==",
|
"integrity": "sha512-qTRU7trzPJKjdlO6r4+YnyauEQ/cTvCJYRl5t2jqsG8y2OoCRsw4qUydzGTxX3YEkmgZjSN845hMNtyWuZUjcg==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/mocha": "^10.0.0",
|
"@types/mocha": "^10.0.0",
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"@wdio/utils": "8.24.3",
|
"@wdio/utils": "8.24.6",
|
||||||
"mocha": "^10.0.0"
|
"mocha": "^10.0.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
|
@ -1319,22 +1319,22 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/runner": {
|
"node_modules/@wdio/runner": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/runner/-/runner-8.24.6.tgz",
|
||||||
"integrity": "sha512-HmK3vBnJnhYKhH4h2sPxTIddvRZ/QVDR8mBRDAgaZwozAuovBbnAvUYeHKpau2KCH4m4sLD6YDVZRcQvzTeYjQ==",
|
"integrity": "sha512-2dt5F9scy0klYwB/E4JztLo04OaPsqcuZP9WKn+NSIBNug0UrgUcBv5ARJEuE3iUyPWpTeczWkU3UtcdMmjagQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/config": "8.24.3",
|
"@wdio/config": "8.24.6",
|
||||||
"@wdio/globals": "8.24.3",
|
"@wdio/globals": "8.24.6",
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"@wdio/utils": "8.24.3",
|
"@wdio/utils": "8.24.6",
|
||||||
"deepmerge-ts": "^5.0.0",
|
"deepmerge-ts": "^5.0.0",
|
||||||
"expect-webdriverio": "^4.6.1",
|
"expect-webdriverio": "^4.6.1",
|
||||||
"gaze": "^1.1.2",
|
"gaze": "^1.1.2",
|
||||||
"webdriver": "8.24.3",
|
"webdriver": "8.24.6",
|
||||||
"webdriverio": "8.24.3"
|
"webdriverio": "8.24.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.13 || >=18"
|
"node": "^16.13 || >=18"
|
||||||
|
@ -1381,9 +1381,9 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@wdio/utils": {
|
"node_modules/@wdio/utils": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/@wdio/utils/-/utils-8.24.6.tgz",
|
||||||
"integrity": "sha512-/thr+f2pn7z5wUWiyiFp7/JoJ30oHatyfuxKpcIBcjkv+YZbph0bbEBVv641UlmZxUMVVeXGvWMNdlWH7rMo7g==",
|
"integrity": "sha512-qwcshLH9iKnhK0jXoXjPw3G02UhyShT0I+ljC0hMybJEBsra92TYFa47Cp6n1fdvM3+/BTuhsgtzRz0anObicQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@puppeteer/browsers": "^1.6.0",
|
"@puppeteer/browsers": "^1.6.0",
|
||||||
|
@ -2927,15 +2927,15 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/eslint": {
|
"node_modules/eslint": {
|
||||||
"version": "8.54.0",
|
"version": "8.55.0",
|
||||||
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.54.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint/-/eslint-8.55.0.tgz",
|
||||||
"integrity": "sha512-NY0DfAkM8BIZDVl6PgSa1ttZbx3xHgJzSNJKYcQglem6CppHyMhRIQkBVSSMaSRnLhig3jsDbEzOjwCVt4AmmA==",
|
"integrity": "sha512-iyUUAM0PCKj5QpwGfmCAG9XXbZCWsqP/eWAWrG/W0umvjuLRBECwSFdt+rCntju0xEH7teIABPwXpahftIaTdA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@eslint-community/eslint-utils": "^4.2.0",
|
"@eslint-community/eslint-utils": "^4.2.0",
|
||||||
"@eslint-community/regexpp": "^4.6.1",
|
"@eslint-community/regexpp": "^4.6.1",
|
||||||
"@eslint/eslintrc": "^2.1.3",
|
"@eslint/eslintrc": "^2.1.4",
|
||||||
"@eslint/js": "8.54.0",
|
"@eslint/js": "8.55.0",
|
||||||
"@humanwhocodes/config-array": "^0.11.13",
|
"@humanwhocodes/config-array": "^0.11.13",
|
||||||
"@humanwhocodes/module-importer": "^1.0.1",
|
"@humanwhocodes/module-importer": "^1.0.1",
|
||||||
"@nodelib/fs.walk": "^1.2.8",
|
"@nodelib/fs.walk": "^1.2.8",
|
||||||
|
@ -8616,18 +8616,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webdriver": {
|
"node_modules/webdriver": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/webdriver/-/webdriver-8.24.6.tgz",
|
||||||
"integrity": "sha512-GbD1X7WzSh2ssb/U52K5RyChKgcPjNDZft5RmHJa1ieT2biTEHAqZycHxNBcpExAlwGlw91hmpoNbwPfdFORRw==",
|
"integrity": "sha512-k5XI2/SHd/14h4ElPQH8EzSUXujZIGbBEi+3dTS2H457KFR5Q8QYfIazDs/YnEdooOp8b6Oe9N7qI99LP8K6bQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@types/ws": "^8.5.3",
|
"@types/ws": "^8.5.3",
|
||||||
"@wdio/config": "8.24.3",
|
"@wdio/config": "8.24.6",
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/protocols": "8.23.0",
|
"@wdio/protocols": "8.23.0",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"@wdio/utils": "8.24.3",
|
"@wdio/utils": "8.24.6",
|
||||||
"deepmerge-ts": "^5.1.0",
|
"deepmerge-ts": "^5.1.0",
|
||||||
"got": "^ 12.6.1",
|
"got": "^ 12.6.1",
|
||||||
"ky": "^0.33.0",
|
"ky": "^0.33.0",
|
||||||
|
@ -8675,18 +8675,18 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/webdriverio": {
|
"node_modules/webdriverio": {
|
||||||
"version": "8.24.3",
|
"version": "8.24.6",
|
||||||
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.24.3.tgz",
|
"resolved": "https://registry.npmjs.org/webdriverio/-/webdriverio-8.24.6.tgz",
|
||||||
"integrity": "sha512-c0IkkGkJtxxpuO53DfeN9UlHmEKSeKCWCREJBzEkpHrjveVlfhh8cQBacLdUzJwE61xByNDH1cu1RVXKL+ZEJw==",
|
"integrity": "sha512-gJMAJiErbXe/oFJbV+H9lXp9GPxnUgHrbtxkG6SCKQlk1zPFho9FZ3fQWl/ty84w5n9ZMhAdnQIfZM9aytxIBQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/node": "^20.1.0",
|
"@types/node": "^20.1.0",
|
||||||
"@wdio/config": "8.24.3",
|
"@wdio/config": "8.24.6",
|
||||||
"@wdio/logger": "8.16.17",
|
"@wdio/logger": "8.16.17",
|
||||||
"@wdio/protocols": "8.23.0",
|
"@wdio/protocols": "8.23.0",
|
||||||
"@wdio/repl": "8.23.1",
|
"@wdio/repl": "8.23.1",
|
||||||
"@wdio/types": "8.24.2",
|
"@wdio/types": "8.24.2",
|
||||||
"@wdio/utils": "8.24.3",
|
"@wdio/utils": "8.24.6",
|
||||||
"archiver": "^6.0.0",
|
"archiver": "^6.0.0",
|
||||||
"aria-query": "^5.0.0",
|
"aria-query": "^5.0.0",
|
||||||
"css-shorthand-properties": "^1.1.1",
|
"css-shorthand-properties": "^1.1.1",
|
||||||
|
@ -8703,7 +8703,7 @@
|
||||||
"resq": "^1.9.1",
|
"resq": "^1.9.1",
|
||||||
"rgb2hex": "0.2.5",
|
"rgb2hex": "0.2.5",
|
||||||
"serialize-error": "^11.0.1",
|
"serialize-error": "^11.0.1",
|
||||||
"webdriver": "8.24.3"
|
"webdriver": "8.24.6"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^16.13 || >=18"
|
"node": "^16.13 || >=18"
|
||||||
|
|
|
@ -6,11 +6,11 @@
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
||||||
"@typescript-eslint/parser": "^6.13.1",
|
"@typescript-eslint/parser": "^6.13.1",
|
||||||
"@wdio/cli": "^8.24.3",
|
"@wdio/cli": "^8.24.6",
|
||||||
"@wdio/local-runner": "^8.24.3",
|
"@wdio/local-runner": "^8.24.6",
|
||||||
"@wdio/mocha-framework": "^8.24.3",
|
"@wdio/mocha-framework": "^8.24.6",
|
||||||
"@wdio/spec-reporter": "^8.24.2",
|
"@wdio/spec-reporter": "^8.24.2",
|
||||||
"eslint": "^8.54.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-sonarjs": "^0.23.0",
|
"eslint-plugin-sonarjs": "^0.23.0",
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
|
|
|
@ -3,6 +3,92 @@
|
||||||
This is the default UI for the authentik server. The documentation is going to be a little sparse
|
This is the default UI for the authentik server. The documentation is going to be a little sparse
|
||||||
for awhile, but at least let's get started.
|
for awhile, but at least let's get started.
|
||||||
|
|
||||||
|
# The Theory of the authentik UI
|
||||||
|
|
||||||
|
In Peter Naur's 1985 essay [Programming as Theory
|
||||||
|
Building](https://pages.cs.wisc.edu/~remzi/Naur.pdf), programming is described as creating a mental
|
||||||
|
model of how a program *should* run, then writing the code to test if the program *can* run that
|
||||||
|
way.
|
||||||
|
|
||||||
|
The mental model for the authentik UI is straightforward. There are five "applications" within the
|
||||||
|
UI, each with its own base URL, router, and responsibilities, and each application needs as many as
|
||||||
|
three contexts in which to run.
|
||||||
|
|
||||||
|
The three contexts corresponds to objects in the API's `model` section, so let's use those names.
|
||||||
|
|
||||||
|
- The root `Config`. The root configuration object of the server, containing mostly caching and
|
||||||
|
error reporting information. This is misleading, however; the `Config` object contains some user
|
||||||
|
information, specifically a list of permissions the current user (or "no user") has.
|
||||||
|
- The root `CurrentTenant`. This describes the `Brand` information UIs should use, such as themes,
|
||||||
|
logos, favicon, and specific default flows for logging in, logging out, and recovering a user
|
||||||
|
password.
|
||||||
|
- The current `SessionUser`, the person logged in: username, display name, and various states.
|
||||||
|
(Note: the authentik server permits administrators to "impersonate" any other user in order to
|
||||||
|
debug their authentikation experience. If impersonation is active, the `user` field reflects that
|
||||||
|
user, but it also includes a field, `original`, with the administrator's information.)
|
||||||
|
|
||||||
|
(There is a fourth context object, Version, but its use is limited to displaying version information
|
||||||
|
and checking for upgrades. Just be aware that you will see it, but you will probably never interact
|
||||||
|
with it.)
|
||||||
|
|
||||||
|
There are five applications. Two (`loading` and `api-browser`) are trivial applications whose
|
||||||
|
insides are provided by third-party libraries (Patternfly and Rapidoc, respectively). The other
|
||||||
|
three are actual applications. The descriptions below are wholly from the view of the user's
|
||||||
|
experience:
|
||||||
|
|
||||||
|
- `Flow`: From a given URL, displays a form that requests information from the user to accomplish a
|
||||||
|
task. Some tasks require the user to be logged in, but many (such as logging in itself!)
|
||||||
|
obviously do not.
|
||||||
|
- `User`: Provides the user with access to the applications they can access, plus a few user
|
||||||
|
settings.
|
||||||
|
- `Admin`: Provides someone with super-user permissions access to the administrative functions of
|
||||||
|
the authentik server.
|
||||||
|
|
||||||
|
**Mental Model**
|
||||||
|
|
||||||
|
- Upon initialization, *every* authentik UI application fetches `Config` and `CurrentTenant`. `User`
|
||||||
|
and `Admin` will also attempt to load the `SessionUser`; if there is none, the user is kicked out
|
||||||
|
to the `Flow` for logging into authentik itself.
|
||||||
|
- `Config`, `CurrentTenant`, and `SessionUser`, are provided by the `@goauthentik/api` application,
|
||||||
|
not by the codebase under `./web`. (Where you are now).
|
||||||
|
- `Flow`, `User`, and `Admin` are all called `Interfaces` and are found in
|
||||||
|
`./web/src/flow/FlowInterface`, `./web/src/user/UserInterface`, `./web/src/admin/AdminInterface`,
|
||||||
|
respectively.
|
||||||
|
|
||||||
|
Inside each of these you will find, in a hierarchal order:
|
||||||
|
|
||||||
|
- The context layer described above
|
||||||
|
- A theme managing layer
|
||||||
|
- The orchestration layer:
|
||||||
|
- web socket handler for server-generated events
|
||||||
|
- The router
|
||||||
|
- Individual routes for each vertical slice and its relationship to other objects:
|
||||||
|
|
||||||
|
Each slice corresponds to an object table on the server, and each slice _usually_ consists of the
|
||||||
|
following:
|
||||||
|
|
||||||
|
- A paginated collection display, usually using the `Table` foundation (found in
|
||||||
|
`./web/src/elements/Table`)
|
||||||
|
- The ability to view an individual object from the collection, which you may be able to:
|
||||||
|
- Edit
|
||||||
|
- Delete
|
||||||
|
- A form for creating a new object
|
||||||
|
- Tabs showing that object's relationship to other objects
|
||||||
|
- Interactive elements for changing or deleting those relationships, or creating new ones.
|
||||||
|
- The ability to create new objects with which to have that relationship, if they're not part of
|
||||||
|
the core objects (such as User->MFA authenticator apps, since the latter is not a "core" object
|
||||||
|
and has no tab of its own).
|
||||||
|
|
||||||
|
We are still a bit "all over the place" with respect to sub-units and common units; there are
|
||||||
|
folders `common`, `elements`, and `components`, and ideally they would be:
|
||||||
|
|
||||||
|
- `common`: non-UI related libraries all of our applications need
|
||||||
|
- `elements`: UI elements shared among multiple applications that do not need context
|
||||||
|
- `components`: UI elements shared among multiple that use one or more context
|
||||||
|
|
||||||
|
... but at the moment there are some context-sensitive elements, and some UI-related stuff in
|
||||||
|
`common`.
|
||||||
|
|
||||||
# Comments
|
# Comments
|
||||||
|
|
||||||
**NOTE:** The comments in this section are for specific changes to this repository that cannot be
|
**NOTE:** The comments in this section are for specific changes to this repository that cannot be
|
||||||
|
|
3730
web/package-lock.json
generated
3730
web/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -37,7 +37,7 @@
|
||||||
"@codemirror/legacy-modes": "^6.3.3",
|
"@codemirror/legacy-modes": "^6.3.3",
|
||||||
"@codemirror/theme-one-dark": "^6.1.2",
|
"@codemirror/theme-one-dark": "^6.1.2",
|
||||||
"@formatjs/intl-listformat": "^7.5.3",
|
"@formatjs/intl-listformat": "^7.5.3",
|
||||||
"@fortawesome/fontawesome-free": "^6.5.0",
|
"@fortawesome/fontawesome-free": "^6.5.1",
|
||||||
"@goauthentik/api": "^2023.10.4-1700591367",
|
"@goauthentik/api": "^2023.10.4-1700591367",
|
||||||
"@lit-labs/context": "^0.4.0",
|
"@lit-labs/context": "^0.4.0",
|
||||||
"@lit-labs/task": "^3.1.0",
|
"@lit-labs/task": "^3.1.0",
|
||||||
|
@ -45,8 +45,8 @@
|
||||||
"@open-wc/lit-helpers": "^0.6.0",
|
"@open-wc/lit-helpers": "^0.6.0",
|
||||||
"@patternfly/elements": "^2.4.0",
|
"@patternfly/elements": "^2.4.0",
|
||||||
"@patternfly/patternfly": "^4.224.2",
|
"@patternfly/patternfly": "^4.224.2",
|
||||||
"@sentry/browser": "^7.83.0",
|
"@sentry/browser": "^7.84.0",
|
||||||
"@sentry/tracing": "^7.83.0",
|
"@sentry/tracing": "^7.84.0",
|
||||||
"@webcomponents/webcomponentsjs": "^2.8.0",
|
"@webcomponents/webcomponentsjs": "^2.8.0",
|
||||||
"base64-js": "^1.5.1",
|
"base64-js": "^1.5.1",
|
||||||
"chart.js": "^4.4.0",
|
"chart.js": "^4.4.0",
|
||||||
|
@ -64,13 +64,13 @@
|
||||||
"yaml": "^2.3.4"
|
"yaml": "^2.3.4"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.23.3",
|
"@babel/core": "^7.23.5",
|
||||||
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
"@babel/plugin-proposal-class-properties": "^7.18.6",
|
||||||
"@babel/plugin-proposal-decorators": "^7.23.3",
|
"@babel/plugin-proposal-decorators": "^7.23.5",
|
||||||
"@babel/plugin-transform-private-methods": "^7.23.3",
|
"@babel/plugin-transform-private-methods": "^7.23.3",
|
||||||
"@babel/plugin-transform-private-property-in-object": "^7.23.4",
|
"@babel/plugin-transform-private-property-in-object": "^7.23.4",
|
||||||
"@babel/plugin-transform-runtime": "^7.23.4",
|
"@babel/plugin-transform-runtime": "^7.23.4",
|
||||||
"@babel/preset-env": "^7.23.3",
|
"@babel/preset-env": "^7.23.5",
|
||||||
"@babel/preset-typescript": "^7.23.3",
|
"@babel/preset-typescript": "^7.23.3",
|
||||||
"@hcaptcha/types": "^1.0.3",
|
"@hcaptcha/types": "^1.0.3",
|
||||||
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
"@jackfranklin/rollup-plugin-markdown": "^0.4.0",
|
||||||
|
@ -82,21 +82,21 @@
|
||||||
"@rollup/plugin-replace": "^5.0.5",
|
"@rollup/plugin-replace": "^5.0.5",
|
||||||
"@rollup/plugin-terser": "^0.4.4",
|
"@rollup/plugin-terser": "^0.4.4",
|
||||||
"@rollup/plugin-typescript": "^11.1.5",
|
"@rollup/plugin-typescript": "^11.1.5",
|
||||||
"@storybook/addon-essentials": "^7.6.0",
|
"@storybook/addon-essentials": "^7.5.3",
|
||||||
"@storybook/addon-links": "^7.6.0",
|
"@storybook/addon-links": "^7.5.3",
|
||||||
"@storybook/blocks": "^7.1.1",
|
"@storybook/blocks": "^7.1.1",
|
||||||
"@storybook/web-components": "^7.6.0",
|
"@storybook/web-components": "^7.5.3",
|
||||||
"@storybook/web-components-vite": "^7.6.0",
|
"@storybook/web-components-vite": "^7.5.3",
|
||||||
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
"@trivago/prettier-plugin-sort-imports": "^4.3.0",
|
||||||
"@types/chart.js": "^2.9.41",
|
"@types/chart.js": "^2.9.41",
|
||||||
"@types/codemirror": "5.60.15",
|
"@types/codemirror": "5.60.15",
|
||||||
"@types/grecaptcha": "^3.0.7",
|
"@types/grecaptcha": "^3.0.7",
|
||||||
"@typescript-eslint/eslint-plugin": "^6.13.0",
|
"@typescript-eslint/eslint-plugin": "^6.13.1",
|
||||||
"@typescript-eslint/parser": "^6.13.0",
|
"@typescript-eslint/parser": "^6.13.1",
|
||||||
"babel-plugin-macros": "^3.1.0",
|
"babel-plugin-macros": "^3.1.0",
|
||||||
"babel-plugin-tsconfig-paths": "^1.0.3",
|
"babel-plugin-tsconfig-paths": "^1.0.3",
|
||||||
"cross-env": "^7.0.3",
|
"cross-env": "^7.0.3",
|
||||||
"eslint": "^8.54.0",
|
"eslint": "^8.55.0",
|
||||||
"eslint-config-google": "^0.14.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"eslint-plugin-custom-elements": "0.0.8",
|
"eslint-plugin-custom-elements": "0.0.8",
|
||||||
"eslint-plugin-lit": "^1.10.1",
|
"eslint-plugin-lit": "^1.10.1",
|
||||||
|
@ -106,14 +106,14 @@
|
||||||
"npm-run-all": "^4.1.5",
|
"npm-run-all": "^4.1.5",
|
||||||
"prettier": "^3.1.0",
|
"prettier": "^3.1.0",
|
||||||
"pseudolocale": "^2.0.0",
|
"pseudolocale": "^2.0.0",
|
||||||
"pyright": "^1.1.337",
|
"pyright": "^1.1.338",
|
||||||
"react": "^18.2.0",
|
"react": "^18.2.0",
|
||||||
"react-dom": "^18.2.0",
|
"react-dom": "^18.2.0",
|
||||||
"rollup": "^4.6.0",
|
"rollup": "^4.6.1",
|
||||||
"rollup-plugin-copy": "^3.5.0",
|
"rollup-plugin-copy": "^3.5.0",
|
||||||
"rollup-plugin-cssimport": "^1.0.3",
|
"rollup-plugin-cssimport": "^1.0.3",
|
||||||
"rollup-plugin-postcss-lit": "^2.1.0",
|
"rollup-plugin-postcss-lit": "^2.1.0",
|
||||||
"storybook": "^7.6.0",
|
"storybook": "^7.5.3",
|
||||||
"storybook-addon-mock": "^4.3.0",
|
"storybook-addon-mock": "^4.3.0",
|
||||||
"ts-lit-plugin": "^2.0.1",
|
"ts-lit-plugin": "^2.0.1",
|
||||||
"tslib": "^2.6.2",
|
"tslib": "^2.6.2",
|
||||||
|
|
|
@ -98,7 +98,7 @@ The challenges for multi-repos are basically the inverse of the advantages of a
|
||||||
|
|
||||||
We are still a small company here at Authentik Security, moving fast to grow our product’s feature set and leap-frog our competitors, while staying true to our open source origins. We want to innovate, release, and at this stage, tilt towards rapid development. Our engineers and infrastructure team have the ability and desire to collaborate closely and learn from one another; this culture is important going forward, and using a monorepo works as a compelling incentive for team transparency and support across the projects.
|
We are still a small company here at Authentik Security, moving fast to grow our product’s feature set and leap-frog our competitors, while staying true to our open source origins. We want to innovate, release, and at this stage, tilt towards rapid development. Our engineers and infrastructure team have the ability and desire to collaborate closely and learn from one another; this culture is important going forward, and using a monorepo works as a compelling incentive for team transparency and support across the projects.
|
||||||
|
|
||||||
The history of authenik provides some additional insight into our use of a monorepo; as the single maintainer for many years, a monorepo was simply easier for me to manage, and even as our wonderful community grew and contributions increased and sponsors appeared, the benefits of a monorepo remain.
|
The history of authentik provides some additional insight into our use of a monorepo; as the single maintainer for many years, a monorepo was simply easier for me to manage, and even as our wonderful community grew and contributions increased and sponsors appeared, the benefits of a monorepo remain.
|
||||||
|
|
||||||
So for us, at this stage, we benefit greatly from using a monorepo for the vast majority of our code base (and documentation). Using a monorepo means that as a team, we closely integrate our work: coding, documentation, test suites, refactoring efforts, common dependencies and tooling.
|
So for us, at this stage, we benefit greatly from using a monorepo for the vast majority of our code base (and documentation). Using a monorepo means that as a team, we closely integrate our work: coding, documentation, test suites, refactoring efforts, common dependencies and tooling.
|
||||||
|
|
||||||
|
|
|
@ -155,4 +155,4 @@ In another example, a breach at Okta (not [that one](https://goauthentik.io/blog
|
||||||
|
|
||||||
The two types of breaches above will drive further interest in zero trust. On the one hand, we see companies fail because they are too trusting; on the other hand, we see other companies fail in some ways but prevent further damage thanks to a few solid elements in their security postures. The potential becomes clear – if companies embrace zero trust, they can do even better.
|
The two types of breaches above will drive further interest in zero trust. On the one hand, we see companies fail because they are too trusting; on the other hand, we see other companies fail in some ways but prevent further damage thanks to a few solid elements in their security postures. The potential becomes clear – if companies embrace zero trust, they can do even better.
|
||||||
|
|
||||||
As always, we look forward to hearing your thoughts! Send us an email at hello@goauthentik, or join us on on [Github](https://github.com/goauthentik/authentik) or [Discord](https://discord.com/invite/jg33eMhnj6).
|
As always, we look forward to hearing your thoughts! Send us an email at hello@goauthentik.io, or join us on on [Github](https://github.com/goauthentik/authentik) or [Discord](https://discord.com/invite/jg33eMhnj6).
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,163 @@
|
||||||
|
---
|
||||||
|
title: Automated security versus the security mindset
|
||||||
|
description: “Automated security plays a key part in many cybersecurity tasks. But what are its failings and will a security mindset always require the human factor?”
|
||||||
|
slug: 2023-11-30-automated-security-versus-the-security-mindset
|
||||||
|
authors:
|
||||||
|
- name: Jens Langhammer
|
||||||
|
title: CTO at Authentik Security Inc
|
||||||
|
url: https://github.com/BeryJu
|
||||||
|
image_url: https://github.com/BeryJu.png
|
||||||
|
tags:
|
||||||
|
- authentik
|
||||||
|
- automated security
|
||||||
|
- security mindset
|
||||||
|
- incident response
|
||||||
|
- vulnerabilities
|
||||||
|
- human factor in cybersecurity
|
||||||
|
- SSO
|
||||||
|
- identity provider
|
||||||
|
- authentication
|
||||||
|
- Authentik Security
|
||||||
|
hide_table_of_contents: false
|
||||||
|
image: ./authentication.png
|
||||||
|
---
|
||||||
|
|
||||||
|
> **_authentik is an open source Identity Provider that unifies your identity needs into a single platform, replacing Okta, Active Directory, and auth0. Authentik Security is a [public benefit company](https://github.com/OpenCoreVentures/ocv-public-benefit-company/blob/main/ocv-public-benefit-company-charter.md) building on top of the open source project._**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Automation plays a large and increasingly important role in cybersecurity. Cybersecurity vendors promote their Machine Learning and Artificial Intelligence products as the inevitable future. However, thanks to the work of security experts like [Bruce Schneier](https://en.wikipedia.org/wiki/Bruce_Schneier), we have more insight into the human adversaries that create the underlying risks to network security, and a better understanding of why teaching humans to have a security mindset is the critical first step to keeping your network safe.
|
||||||
|
|
||||||
|
> The best response to these malicious actors is to think like a security expert and develop the security mindset.
|
||||||
|
|
||||||
|
In this blog post, we examine why automation is such a popular solution to cybersecurity problems—from vulnerability scanning to risk assessments. Then, we will look at those tasks in which security automation by itself proves inadequate, with particular focus on automatic scanning. Next, we make a positive case for why the human factor will always be needed in security. Finally, we will propose that good security isn't a feature. It's a proactive security mindset that's required—one with a human element at its core.
|
||||||
|
|
||||||
|
![authentik UI](./authentication.png)
|
||||||
|
|
||||||
|
<!--truncate-->
|
||||||
|
|
||||||
|
## Why automate security in the first place?
|
||||||
|
|
||||||
|
Automated security is such a popular option purely because of the current dynamics:
|
||||||
|
|
||||||
|
- On the one hand, there is a growing number of security incidents, instigated by systematic threat actors who may use the exact same auto security testing tools to find and target weaknesses
|
||||||
|
- On the other, there is a shortage of trained cybersecurity professionals with adequate time resources to deal with those threats
|
||||||
|
|
||||||
|
Meanwhile, companies concerned about the security of their networks are facing the demands of savvy insurers keen to reduce their risks, while CISOs are coming under increasing personal pressure, considering some have faced new warnings of personal liabilities (including jail time, as we wrote about in a [recent blog](https://goauthentik.io/blog/2023-11-22-how-we-saved-over-100k#repercussions)) from government legislators.
|
||||||
|
|
||||||
|
But it's not just a personnel problem. The nature of some cybersecurity approaches, such as penetration testing, also plays a part. Many of a security engineer’s tasks are repetitive and prolonged. Automated security testing means time can be freed up to make the best use of an internal security engineer or external pentester's resources.
|
||||||
|
|
||||||
|
Finally, it is impossible to deny that securing the perimeter (running regular scans for misconfigurations and unusual behavior) and enforcing robust security policies are all impossible to deploy without some automation. 24/7/365 monitoring, processing massive data sets, and rapid threat detection and remediation all call for significant automated elements. Automated security is also key in helping scale cybersecurity operations to match company, staffing, system, and platform growth.
|
||||||
|
|
||||||
|
### What is the role of automation in security tasks?
|
||||||
|
|
||||||
|
Let’s not throw the baby out with the bath water. Automation has a place and positive role to play in cybersecurity. Auto security testing tools are best deployed for tasks that are repetitive and routine, and that require high volume processing.
|
||||||
|
|
||||||
|
Examples of these tasks include:
|
||||||
|
|
||||||
|
- Scheduled tasks such as vulnerability scanning
|
||||||
|
- 24/7 user and other activity monitoring
|
||||||
|
- Actions that require speed such as detecting and immediately responding to malicious intrusions
|
||||||
|
|
||||||
|
Removing tasks like these from the manual operations of your SOC (security operations center) aids efficiency, supports your security team, and helps ameliorate any skills shortage.
|
||||||
|
|
||||||
|
What are the benefits of an automated security system?
|
||||||
|
|
||||||
|
Automated security also excels in:
|
||||||
|
|
||||||
|
- Reducing human error
|
||||||
|
- Eliminating manual steps
|
||||||
|
- Lowering the number of false positives
|
||||||
|
- Updating software
|
||||||
|
- Helping with compliance
|
||||||
|
- Enhancing incident response and threat intelligence
|
||||||
|
|
||||||
|
## Why automation is a threat to cybersecurity
|
||||||
|
|
||||||
|
If automation is such a popular and necessary asset in the cybersecurity field, why can't we automate everything?
|
||||||
|
|
||||||
|
_Let’s think: Could over-reliance on automated security testing ultimately prove detrimental to cybersecurity and threaten the safety of your systems?_
|
||||||
|
|
||||||
|
To help avoid this, we need to acknowledge that automation can't:
|
||||||
|
|
||||||
|
- Keep security teams up to date with new standards, such as the NIST Cybersecurity Framework; the ISO/IEC 27001 standard for information security management; the CIS Critical Security Controls; the OSSTMM; the Web Application Security Consortium (WASC 2.0); or the finance standard of PCI Data Security Standards for the payment card industry
|
||||||
|
- Adjust your internal security policies and practices to all the nuances of relevant industry, country or regulations such as NIST SP 800-52; The California Consumer Privacy Act: the Canadian PIPEDA; the EU’s GDPR; or HIPAA’s personal health data legislation
|
||||||
|
- Rapidly respond to every new CVE or every item that makes an appearance in the SANS Top 25, or the most common vulnerabilities listed in the OWASP lists
|
||||||
|
- Ensure that your own internal cybersecurity protocols and policies are enforced
|
||||||
|
|
||||||
|
_But what else?_
|
||||||
|
|
||||||
|
The first point to remember is that automated solutions can only reliably alert and respond to the threats to your network, services, databases, APIs, and applications that they've been configured to detect. This configuration is limited to the settings available in the particular software. Automated processes are only as good as the rules human engineers give them. Security processes must still be configured and employed correctly.
|
||||||
|
|
||||||
|
And, your own company’s internal business logic must be factored in. This is where pentesters (who may, of course, rely on some automated tools to help them identify some vulnerabilities across your network) can delve deep on specific vulnerabilities and apply your company’s custom business logic and data breach implications. Resultant summary reports must explain the business, financial, reputational, data, and user implications of likely breaches, investigations and penalties.
|
||||||
|
|
||||||
|
Also, malicious hackers can use automated security techniques just as much as defenders to find potential security flaws in an organization’s network. They use novel attacks inspired by vulnerabilities that automated tools are unable to detect at all, by exploiting mistakes made by users that automation by itself can't solve. Examples include social engineering attacks that can begin with an innocuous looking email, or an SMS or email phishing scam. Given that over 80% of bad actors gain illegitimate entry using social engineering attacks, it is obvious that company-wide staff training is an excellent deployment of resources.
|
||||||
|
|
||||||
|
## Against automatic scanning in favor of a proactive security mindset
|
||||||
|
|
||||||
|
In the case of social engineering attacks that we’ve just mentioned, a security-oriented mindset is what will keep your staff watchful—not the knowledge of automated tools.
|
||||||
|
|
||||||
|
_Could mindset, then, be the greatest weapon in your defensive arsenal? Let’s explore further._
|
||||||
|
|
||||||
|
### What elements are crucial to a security mindset?
|
||||||
|
|
||||||
|
Despite the advantages of automation in security scanning, the element of human expertise is needed in many steps of the scanning process. There is no purely automatic way to proactively identify all new threats and preempt sophisticated or unconventional attacks, for example. Security engineers must wait for the tools on which they rely to be updated with the latest CVEs, and they must then have the expertise to understand the reasons and logic behind threats. They will sometimes have to manually validate these threats where required, then plan mitigation activities for future avoidance.
|
||||||
|
|
||||||
|
Further, it is the practice and discipline of working in cybersecurity that give developers the mindset and expertise to build software that is ‘secure by design’. We expect vulnerabilities, and we write more secure code because of it.
|
||||||
|
|
||||||
|
### Some of the drawbacks of vulnerability scanning tools
|
||||||
|
|
||||||
|
While automated scanning tools can provide a major asset in the arsenal of any cybersecurity professional, we must honestly acknowledge their weaknesses when set side-by-side with a human:
|
||||||
|
|
||||||
|
- An automated scanner can miss vulnerabilities if they are new and not in its database, or if the vulnerability is complex and adaptive. Scanners can only hunt for known vulnerabilities, and according to how automated scans are further configured by users.
|
||||||
|
- The problem of false positives can never be completely eliminated even by the most accurate scanners. In the end, a human expert is needed to filter them out.
|
||||||
|
- Detecting vulnerabilities is only the start. While some scanners assign an urgent priority to their findings, human expertise is needed to assess the _specific_ implications of these vulnerabilities for the platform, system or business.
|
||||||
|
- Once vulnerabilities are detected, fixing and patching them is a manual process. A vulnerability report is a starting point. Identifying a vulnerability is one thing; successfully remediating it is another. Further, security engineers will sometimes also have to further reengineer their code, to ensure a similar problem does not recur.
|
||||||
|
|
||||||
|
Of course, automatic scanners are excellent assets for speed and quick action, repeatability, ease of use, and constant monitoring. They can provide a good starting point for further investigations, not an end point. But they are not equivalent to a full penetration test and can only find risks that are known.
|
||||||
|
|
||||||
|
### What about AI in automated security scanning?
|
||||||
|
|
||||||
|
AI and machine learning contribute to the speed and accuracy of dealing with risks posed by known threats. But, for all these advances, the mind of the security engineer is still required when dealing with unknown or new threats, threats that are chaotic and unpredictable or morphable, and threats that don't follow the rules.
|
||||||
|
|
||||||
|
## The human factor in cybersecurity will always be required
|
||||||
|
|
||||||
|
The fact that there are automated tasks and processes in cybersecurity does not mean that the good security as a whole is autonomous or automatic. Security is more about developing a _security mindset_ than a set of features.
|
||||||
|
|
||||||
|
For further information on the human element in SaaS security, see [Securing the future of SaaS: Enterprise Security and Single Sign-On](https://goauthentik.io/blog/2023-07-28-securing-the-future-of-saas#good-security-cant-be-automated-the-human-element-in-saas-security).
|
||||||
|
|
||||||
|
### Human cyber risk
|
||||||
|
|
||||||
|
Humans are at the forefront of cybercrime. Cyber crimes are committed by human beings using adaptation and innovation to invent fresh attack tactics. It is the human mind that continually develops new techniques to hack, infiltrate, and bypass security systems.
|
||||||
|
|
||||||
|
For example, if your company does not have a 2FA/MFA credential policy, vulnerabilities exist around whether your staff share user credentials to save them time and stress. If these credentials are not updated regularly, or worse, if they’re shared by email, any moderately skilled, malicious hacker could attempt to access the email account of a single user, and use it to find other company passwords. It is these human weaknesses and errors that most bad actors hackers rely on.
|
||||||
|
|
||||||
|
_Over 80% of malicious hacks are as a result of the exploitation of the widest weakness of all—predictable human behavior._
|
||||||
|
|
||||||
|
### Human elements of cybersecurity
|
||||||
|
|
||||||
|
Even in a cybersecurity system that is maximally automated there is human input that can never be removed. Obviously, human experts are needed to guide the automated systems in their functioning. Automation technology depends on humans to set rules and workflows, monitor results over time, and rapidly prioritize then respond to alarming findings.
|
||||||
|
|
||||||
|
Once new and significant threats are detected by the automated security, it is human experts again who have to adjust the performance of the automated system as a response to this changing environment. Any further changes need humans to evaluate the performance of automated systems in real-time. Finally, it is humans who train staff in cyber threat detection for these new dangers.
|
||||||
|
|
||||||
|
### Human-centered cybersecurity
|
||||||
|
|
||||||
|
Despite the growing technology around automated security, and the temptation to relax when it is deployed, there are human factors that are irreplaceable in the practice of cybersecurity. We recently wrote about the importance of the “Blue Team” and how [organizational and product hardening](https://goauthentik.io/blog/2023-11-22-how-we-saved-over-100k#hardening) are an integral part of our human-centered security mindset.
|
||||||
|
|
||||||
|
- The human ability to think creatively and rapidly adapt to changing situations is invaluable to good security processes.
|
||||||
|
- The higher the security risk, the more you need skilled security professionals to supervise the security process.
|
||||||
|
- After automation has quickly gathered information, humans are needed to make any well-informed security and organizational decisions that may arise.
|
||||||
|
- Exclusively human tasks include containment, triage, remediation, and launching new initiatives such as better responses (see [Okta got breached again and they still have not learned their lesson](https://goauthentik.io/blog/2023-10-23-another-okta-breach)).
|
||||||
|
- Only humans can know the commercial implications of a data breach.
|
||||||
|
|
||||||
|
## The security mindset is not a feature
|
||||||
|
|
||||||
|
One misconception is that for every cybersecurity problem or threat, there is an automated feature in some software somewhere that can match it.
|
||||||
|
|
||||||
|
> Some cybersecurity software plans seem to promote feature-rich products but forget to promote highly skilled and aware cybersecurity teams with a proactive security mindset.
|
||||||
|
|
||||||
|
Companies have become too dependent on automation, due to the overwhelming volume of threats and frequency of attacks. This overreliance can cause all sorts of unintended problems—alert fatigue, data overload, devaluing human expertise and input, and an inability to handle zero-day (previously unknown) vulnerabilities.
|
||||||
|
|
||||||
|
Automated security platforms and measures assist and augment human expertise; they do not replace or supersede it. If their corresponding strengths and shortfalls are properly acknowledged, automation and teams with a healthily skeptical security mindset can collaborate for success.
|
||||||
|
|
||||||
|
Let us know if you'd like to learn more about how authentik works as a primary component in a security stack. You can send an email to hello@authentik.io, or find us on [GitHub](https://github.com/goauthentik/authentik) or [Discord](https://discord.com/channels/809154715984199690).
|
|
@ -76,7 +76,7 @@ In Rocket.chat, follow the procedure below:
|
||||||
|
|
||||||
3. In the top right corner, click _Add custom oauth_
|
3. In the top right corner, click _Add custom oauth_
|
||||||
|
|
||||||
4. Give your new oauth the name of _Authenik_, then click _Send_
|
4. Give your new oauth the name of _Authentik_, then click _Send_
|
||||||
|
|
||||||
![](./rocketchat6.png)
|
![](./rocketchat6.png)
|
||||||
|
|
||||||
|
|
|
@ -56,7 +56,7 @@ _I'm only going to list the mandatory/important fields to complete._
|
||||||
|
|
||||||
21. **Application Type:** Web Application
|
21. **Application Type:** Web Application
|
||||||
22. **Name:** Choose a name
|
22. **Name:** Choose a name
|
||||||
23. **Authorized redirect URIs:** `https://authenik.company/source/oauth/callback/google/`
|
23. **Authorized redirect URIs:** `https://authentik.company/source/oauth/callback/google/`
|
||||||
|
|
||||||
![](googledeveloper6.png)
|
![](googledeveloper6.png)
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@ You will need to create a new project, and OAuth credentials in the Twitter Deve
|
||||||
|
|
||||||
6. Enable **OAuth 2.0**
|
6. Enable **OAuth 2.0**
|
||||||
7. Set **Type of App** to _Web_
|
7. Set **Type of App** to _Web_
|
||||||
8. Set **Callback URI / Redirect URL** to `https://authenik.company/source/oauth/callback/twitter/`
|
8. Set **Callback URI / Redirect URL** to `https://authentik.company/source/oauth/callback/twitter/`
|
||||||
9. Set **Website URL** to `https://authentik.company`
|
9. Set **Website URL** to `https://authentik.company`
|
||||||
|
|
||||||
![](./twitter2.png)
|
![](./twitter2.png)
|
||||||
|
|
1175
website/package-lock.json
generated
1175
website/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -16,16 +16,16 @@
|
||||||
"test": "node --test"
|
"test": "node --test"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@docusaurus/core": "3.0.0",
|
"@docusaurus/core": "3.0.1",
|
||||||
"@docusaurus/plugin-client-redirects": "^3.0.0",
|
"@docusaurus/plugin-client-redirects": "^3.0.1",
|
||||||
"@docusaurus/plugin-content-docs": "^3.0.0",
|
"@docusaurus/plugin-content-docs": "^3.0.1",
|
||||||
"@docusaurus/preset-classic": "^3.0.0",
|
"@docusaurus/preset-classic": "^3.0.1",
|
||||||
"@docusaurus/theme-common": "^3.0.0",
|
"@docusaurus/theme-common": "^3.0.1",
|
||||||
"@docusaurus/theme-mermaid": "^3.0.0",
|
"@docusaurus/theme-mermaid": "^3.0.1",
|
||||||
"@mdx-js/react": "^3.0.0",
|
"@mdx-js/react": "^3.0.0",
|
||||||
"clsx": "^2.0.0",
|
"clsx": "^2.0.0",
|
||||||
"disqus-react": "^1.1.5",
|
"disqus-react": "^1.1.5",
|
||||||
"postcss": "^8.4.31",
|
"postcss": "^8.4.32",
|
||||||
"prism-react-renderer": "^2.3.0",
|
"prism-react-renderer": "^2.3.0",
|
||||||
"rapidoc": "^9.3.4",
|
"rapidoc": "^9.3.4",
|
||||||
"react-before-after-slider-component": "^1.1.8",
|
"react-before-after-slider-component": "^1.1.8",
|
||||||
|
@ -49,10 +49,10 @@
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@docusaurus/module-type-aliases": "3.0.0",
|
"@docusaurus/module-type-aliases": "3.0.1",
|
||||||
"@docusaurus/tsconfig": "3.0.0",
|
"@docusaurus/tsconfig": "3.0.1",
|
||||||
"@docusaurus/types": "3.0.0",
|
"@docusaurus/types": "3.0.1",
|
||||||
"@types/react": "^18.2.38",
|
"@types/react": "^18.2.41",
|
||||||
"prettier": "3.1.0",
|
"prettier": "3.1.0",
|
||||||
"typescript": "~5.3.2"
|
"typescript": "~5.3.2"
|
||||||
},
|
},
|
||||||
|
|
Reference in a new issue