From 82bb179bc212585db11d11fc51ac968ea20b820e Mon Sep 17 00:00:00 2001 From: Jens L Date: Tue, 5 Jan 2021 00:41:10 +0100 Subject: [PATCH] root: global email settings (#448) * root: make global email settings configurable * stages/email: add use_global_settings * stages/email: add test_email command to test email sending * stages/email: update email template * stages/email: simplify email template path * stages/email: add support for user-supplied email templates * stages/email: add tests for sending and templates * stages/email: only add custom template if permissions are correct * docs: add custom email template docs * root: add /templates volume in docker-compose by default * stages/email: fix form not allowing custom templates * stages/email: use relative path for custom templates * stages/email: check if all templates exist on startup, reset * docs: add global email docs for docker-compose * helm: add email config to helm chart * helm: load all secrets with env prefix * helm: move s3 and smtp secret to secret * stages/email: fix test for relative name * stages/email: add argument to send email from existing stage * stages/email: set uid using slug of message id * stages/email: ensure template validation ignores migration runs * docs: add email troubleshooting docs * stages/email: fix long task_name breaking task list --- .../templates/administration/task/list.html | 2 +- authentik/lib/default.yml | 11 + authentik/lib/tasks.py | 5 + authentik/root/settings.py | 14 +- authentik/stages/email/api.py | 7 +- authentik/stages/email/apps.py | 33 ++ authentik/stages/email/forms.py | 11 +- authentik/stages/email/management/__init__.py | 0 .../email/management/commands/__init__.py | 0 .../email/management/commands/test_email.py | 42 ++ .../stages/email/migrations/0001_initial.py | 6 +- .../0002_emailstage_use_global_settings.py | 33 ++ authentik/stages/email/models.py | 47 +- .../email/static/stages/email/css/base.css | 530 ++++++++---------- authentik/stages/email/tasks.py | 7 +- .../account_confirmation.html | 2 +- .../stages/email/templates/email/base.html | 34 ++ .../stages/email/templates/email/generic.html | 20 + .../for_email => email}/password_reset.html | 2 +- .../stages/email/templates/email/setup.html | 25 + .../stages/email/for_email/base.html | 65 --- .../stages/email/for_email/generic_email.html | 26 - authentik/stages/email/tests/__init__.py | 0 authentik/stages/email/tests/test_sending.py | 83 +++ .../email/{tests.py => tests/test_stage.py} | 8 + .../stages/email/tests/test_templates.py | 28 + docker-compose.yml | 2 + helm/README.md | 16 +- helm/templates/configmap.yaml | 8 +- helm/templates/secret.yaml | 8 +- helm/templates/web-deployment.yaml | 8 +- helm/templates/worker-deployment.yaml | 8 +- helm/values.yaml | 15 + swagger.yaml | 9 +- .../flow/stages/email/custom-template.png | Bin 0 -> 85201 bytes website/docs/flow/stages/email/index.md | 16 + website/docs/index.md | 2 +- website/docs/installation/docker-compose.md | 30 +- website/docs/installation/kubernetes.md | 19 +- website/docs/troubleshooting/emails.md | 23 + website/sidebars.js | 5 +- .../enrollment-email-verification.pbflow | 2 +- .../flows/recovery-email-verification.pbflow | 2 +- 43 files changed, 791 insertions(+), 423 deletions(-) create mode 100644 authentik/stages/email/management/__init__.py create mode 100644 authentik/stages/email/management/commands/__init__.py create mode 100644 authentik/stages/email/management/commands/test_email.py create mode 100644 authentik/stages/email/migrations/0002_emailstage_use_global_settings.py rename authentik/stages/email/templates/{stages/email/for_email => email}/account_confirmation.html (95%) create mode 100644 authentik/stages/email/templates/email/base.html create mode 100644 authentik/stages/email/templates/email/generic.html rename authentik/stages/email/templates/{stages/email/for_email => email}/password_reset.html (95%) create mode 100644 authentik/stages/email/templates/email/setup.html delete mode 100644 authentik/stages/email/templates/stages/email/for_email/base.html delete mode 100644 authentik/stages/email/templates/stages/email/for_email/generic_email.html create mode 100644 authentik/stages/email/tests/__init__.py create mode 100644 authentik/stages/email/tests/test_sending.py rename authentik/stages/email/{tests.py => tests/test_stage.py} (93%) create mode 100644 authentik/stages/email/tests/test_templates.py create mode 100644 website/docs/flow/stages/email/custom-template.png create mode 100644 website/docs/troubleshooting/emails.md diff --git a/authentik/admin/templates/administration/task/list.html b/authentik/admin/templates/administration/task/list.html index 7f0ef9ea5..373bff1fc 100644 --- a/authentik/admin/templates/administration/task/list.html +++ b/authentik/admin/templates/administration/task/list.html @@ -38,7 +38,7 @@ {% for task in object_list %} -
{{ task.task_name }}
+ {{ task.html_name|join:"_­" }} diff --git a/authentik/lib/default.yml b/authentik/lib/default.yml index 4f9e1bd56..72f19b633 100644 --- a/authentik/lib/default.yml +++ b/authentik/lib/default.yml @@ -21,6 +21,17 @@ error_reporting: environment: customer send_pii: false +# Global email settings +email: + host: localhost + port: 25 + username: "" + password: "" + use_tls: false + use_ssl: false + timeout: 10 + from: authentik@localhost + outposts: docker_image_base: "beryju/authentik" # this is prepended to -proxy:version diff --git a/authentik/lib/tasks.py b/authentik/lib/tasks.py index eb9aff13c..132d03a5e 100644 --- a/authentik/lib/tasks.py +++ b/authentik/lib/tasks.py @@ -52,6 +52,11 @@ class TaskInfo: task_description: Optional[str] = field(default=None) + @property + def html_name(self) -> list[str]: + """Get task_name, but split on underscores, so we can join in the html template.""" + return self.task_name.split("_") + @staticmethod def all() -> Dict[str, "TaskInfo"]: """Get all TaskInfo objects""" diff --git a/authentik/root/settings.py b/authentik/root/settings.py index d68852758..4cc359628 100644 --- a/authentik/root/settings.py +++ b/authentik/root/settings.py @@ -196,7 +196,7 @@ ROOT_URLCONF = "authentik.root.urls" TEMPLATES = [ { "BACKEND": "django.template.backends.django.DjangoTemplates", - "DIRS": [], + "DIRS": ["/templates"], "APP_DIRS": True, "OPTIONS": { "context_processors": [ @@ -238,6 +238,18 @@ DATABASES = { } } +# Email +EMAIL_HOST = CONFIG.y("email.host") +EMAIL_PORT = int(CONFIG.y("email.port")) +EMAIL_HOST_USER = CONFIG.y("email.username") +EMAIL_HOST_PASSWORD = CONFIG.y("email.password") +EMAIL_USE_TLS = CONFIG.y("email.use_tls") +EMAIL_USE_SSL = CONFIG.y("email.use_ssl") +EMAIL_TIMEOUT = int(CONFIG.y("email.timeout")) +DEFAULT_FROM_EMAIL = CONFIG.y("email.from") +SERVER_EMAIL = DEFAULT_FROM_EMAIL +EMAIL_SUBJECT_PREFIX = "[authentik] " + # Password validation # https://docs.djangoproject.com/en/2.1/ref/settings/#auth-password-validators diff --git a/authentik/stages/email/api.py b/authentik/stages/email/api.py index b3a4860f0..01cdf3d2b 100644 --- a/authentik/stages/email/api.py +++ b/authentik/stages/email/api.py @@ -2,18 +2,23 @@ from rest_framework.serializers import ModelSerializer from rest_framework.viewsets import ModelViewSet -from authentik.stages.email.models import EmailStage +from authentik.stages.email.models import EmailStage, get_template_choices class EmailStageSerializer(ModelSerializer): """EmailStage Serializer""" + def __init__(self, *args, **kwrags): + super().__init__(*args, **kwrags) + self.fields["template"].choices = get_template_choices() + class Meta: model = EmailStage fields = [ "pk", "name", + "use_global_settings", "host", "port", "username", diff --git a/authentik/stages/email/apps.py b/authentik/stages/email/apps.py index e7fe92115..5bd33d6f7 100644 --- a/authentik/stages/email/apps.py +++ b/authentik/stages/email/apps.py @@ -2,6 +2,12 @@ from importlib import import_module from django.apps import AppConfig +from django.db import ProgrammingError +from django.template.exceptions import TemplateDoesNotExist +from django.template.loader import get_template +from structlog.stdlib import get_logger + +LOGGER = get_logger() class AuthentikStageEmailConfig(AppConfig): @@ -13,3 +19,30 @@ class AuthentikStageEmailConfig(AppConfig): def ready(self): import_module("authentik.stages.email.tasks") + try: + self.validate_stage_templates() + except ProgrammingError: + pass + + def validate_stage_templates(self): + """Ensure all stage's templates actually exist""" + from authentik.stages.email.models import EmailStage, EmailTemplates + from authentik.events.models import Event, EventAction + + for stage in EmailStage.objects.all(): + try: + get_template(stage.template) + except TemplateDoesNotExist: + LOGGER.warning( + "Stage template does not exist, resetting", path=stage.template + ) + Event.new( + EventAction.CONFIGURATION_ERROR, + stage=stage, + message=( + f"Template {stage.template} does not exist, resetting to default." + f" (Stage {stage.name})" + ), + ).save() + stage.template = EmailTemplates.ACCOUNT_CONFIRM + stage.save() diff --git a/authentik/stages/email/forms.py b/authentik/stages/email/forms.py index 6c3ea986f..303d7834b 100644 --- a/authentik/stages/email/forms.py +++ b/authentik/stages/email/forms.py @@ -2,7 +2,7 @@ from django import forms from django.utils.translation import gettext_lazy as _ -from authentik.stages.email.models import EmailStage +from authentik.stages.email.models import EmailStage, get_template_choices class EmailStageSendForm(forms.Form): @@ -14,11 +14,17 @@ class EmailStageSendForm(forms.Form): class EmailStageForm(forms.ModelForm): """Form to create/edit Email Stage""" + template = forms.ChoiceField(choices=get_template_choices) + class Meta: model = EmailStage fields = [ "name", + "use_global_settings", + "token_expiry", + "subject", + "template", "host", "port", "username", @@ -27,9 +33,6 @@ class EmailStageForm(forms.ModelForm): "use_ssl", "timeout", "from_address", - "token_expiry", - "subject", - "template", ] widgets = { "name": forms.TextInput(), diff --git a/authentik/stages/email/management/__init__.py b/authentik/stages/email/management/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/stages/email/management/commands/__init__.py b/authentik/stages/email/management/commands/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/stages/email/management/commands/test_email.py b/authentik/stages/email/management/commands/test_email.py new file mode 100644 index 000000000..02a190c0a --- /dev/null +++ b/authentik/stages/email/management/commands/test_email.py @@ -0,0 +1,42 @@ +"""Send a test-email with global settings""" +from uuid import uuid4 + +from django.core.management.base import BaseCommand, no_translations + +from authentik.stages.email.models import EmailStage +from authentik.stages.email.tasks import send_mail +from authentik.stages.email.utils import TemplateEmailMessage + + +class Command(BaseCommand): # pragma: no cover + """Send a test-email with global settings""" + + @no_translations + def handle(self, *args, **options): + """Send a test-email with global settings""" + delete_stage = False + if options["stage"]: + stage = EmailStage.objects.get(name=options["stage"]) + else: + stage = EmailStage.objects.create( + name=f"temp-global-stage-{uuid4()}", use_global_settings=True + ) + delete_stage = True + message = TemplateEmailMessage( + subject="authentik Test-Email", + template_name="email/setup.html", + to=[options["to"]], + template_context={}, + ) + try: + # pyright: reportGeneralTypeIssues=false + send_mail( # pylint: disable=no-value-for-parameter + stage.pk, message.__dict__ + ) + finally: + if delete_stage: + stage.delete() + + def add_arguments(self, parser): + parser.add_argument("to", type=str) + parser.add_argument("-s", "--stage", type=str) diff --git a/authentik/stages/email/migrations/0001_initial.py b/authentik/stages/email/migrations/0001_initial.py index b3412e76d..8db5fb842 100644 --- a/authentik/stages/email/migrations/0001_initial.py +++ b/authentik/stages/email/migrations/0001_initial.py @@ -50,15 +50,15 @@ class Migration(migrations.Migration): models.TextField( choices=[ ( - "stages/email/for_email/password_reset.html", + "email/password_reset.html", "Password Reset", ), ( - "stages/email/for_email/account_confirmation.html", + "email/account_confirmation.html", "Account Confirmation", ), ], - default="stages/email/for_email/password_reset.html", + default="email/password_reset.html", ), ), ], diff --git a/authentik/stages/email/migrations/0002_emailstage_use_global_settings.py b/authentik/stages/email/migrations/0002_emailstage_use_global_settings.py new file mode 100644 index 000000000..a13acf2de --- /dev/null +++ b/authentik/stages/email/migrations/0002_emailstage_use_global_settings.py @@ -0,0 +1,33 @@ +# Generated by Django 3.1.4 on 2021-01-04 13:15 + +from django.apps.registry import Apps +from django.db import migrations, models +from django.db.backends.base.schema import BaseDatabaseSchemaEditor + + +def update_template_path(apps: Apps, schema_editor: BaseDatabaseSchemaEditor): + EmailStage = apps.get_model("authentik_stages_email", "EmailStage") + db_alias = schema_editor.connection.alias + + for stage in EmailStage.objects.using(db_alias).all(): + stage.template = stage.template.replace("stages/email/for_email/", "email/") + stage.save() + + +class Migration(migrations.Migration): + + dependencies = [ + ("authentik_stages_email", "0001_initial"), + ] + + operations = [ + migrations.AddField( + model_name="emailstage", + name="use_global_settings", + field=models.BooleanField( + default=False, + help_text="When enabled, global Email connection settings will be used and connection settings below will be ignored.", + ), + ), + migrations.RunPython(update_template_path), + ] diff --git a/authentik/stages/email/models.py b/authentik/stages/email/models.py index 448e0f97b..936952b15 100644 --- a/authentik/stages/email/models.py +++ b/authentik/stages/email/models.py @@ -1,6 +1,9 @@ """email stage models""" +from os import R_OK, access +from pathlib import Path from typing import Type +from django.conf import settings from django.core.mail import get_connection from django.core.mail.backends.base import BaseEmailBackend from django.db import models @@ -8,26 +11,60 @@ from django.forms import ModelForm from django.utils.translation import gettext as _ from django.views import View from rest_framework.serializers import BaseSerializer +from structlog.stdlib import get_logger from authentik.flows.models import Stage +LOGGER = get_logger() + class EmailTemplates(models.TextChoices): """Templates used for rendering the Email""" PASSWORD_RESET = ( - "stages/email/for_email/password_reset.html", + "email/password_reset.html", _("Password Reset"), ) # nosec ACCOUNT_CONFIRM = ( - "stages/email/for_email/account_confirmation.html", + "email/account_confirmation.html", _("Account Confirmation"), ) +def get_template_choices(): + """Get all available Email templates, including dynamically mounted ones. + Directories are taken from TEMPLATES.DIR setting""" + static_choices = EmailTemplates.choices + + dirs = [Path(x) for x in settings.TEMPLATES[0]["DIRS"]] + for template_dir in dirs: + if not template_dir.exists(): + continue + for template in template_dir.glob("**/*.html"): + path = str(template) + if not access(path, R_OK): + LOGGER.warning( + "Custom template file is not readable, check permissions", path=path + ) + continue + rel_path = template.relative_to(template_dir) + static_choices.append((str(rel_path), f"Custom Template: {rel_path}")) + return static_choices + + class EmailStage(Stage): """Sends an Email to the user with a token to confirm their Email address.""" + use_global_settings = models.BooleanField( + default=False, + help_text=_( + ( + "When enabled, global Email connection settings will be used and " + "connection settings below will be ignored." + ) + ), + ) + host = models.TextField(default="localhost") port = models.IntegerField(default=25) username = models.TextField(default="", blank=True) @@ -42,7 +79,7 @@ class EmailStage(Stage): ) subject = models.TextField(default="authentik") template = models.TextField( - choices=EmailTemplates.choices, default=EmailTemplates.PASSWORD_RESET + choices=get_template_choices(), default=EmailTemplates.PASSWORD_RESET ) @property @@ -65,7 +102,9 @@ class EmailStage(Stage): @property def backend(self) -> BaseEmailBackend: - """Get fully configured EMail Backend instance""" + """Get fully configured Email Backend instance""" + if self.use_global_settings: + return get_connection() return get_connection( host=self.host, port=self.port, diff --git a/authentik/stages/email/static/stages/email/css/base.css b/authentik/stages/email/static/stages/email/css/base.css index 6f624e138..b8b6ab985 100644 --- a/authentik/stages/email/static/stages/email/css/base.css +++ b/authentik/stages/email/static/stages/email/css/base.css @@ -1,325 +1,285 @@ /* ------------------------------------- -GLOBAL RESETS + GLOBAL + A very basic CSS reset ------------------------------------- */ - -/*All the styling goes here*/ +* { + margin: 0; + font-family: "Helvetica Neue", Helvetica, Arial, sans-serif; + box-sizing: border-box; + font-size: 14px; +} img { - border: none; - -ms-interpolation-mode: bicubic; - max-width: 100%; + max-width: 100%; } body { - background-color: #fafafa; - font-family: sans-serif; - -webkit-font-smoothing: antialiased; - font-size: 14px; - line-height: 1.4; - margin: 0; - padding: 0; - -ms-text-size-adjust: 100%; - -webkit-text-size-adjust: 100%; + -webkit-font-smoothing: antialiased; + -webkit-text-size-adjust: none; + width: 100% !important; + height: 100%; + line-height: 1.6em; + /* 1.6em * 14px = 22.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ + /*line-height: 22px;*/ } -table { - border-collapse: separate; - mso-table-lspace: 0pt; - mso-table-rspace: 0pt; - width: 100%; } - table td { - font-family: sans-serif; - font-size: 14px; - vertical-align: top; - } +/* Let's make sure all tables have defaults */ +table td { + vertical-align: top; +} - /* ------------------------------------- +/* ------------------------------------- BODY & CONTAINER - ------------------------------------- */ +------------------------------------- */ +body { + background-color: #f6f6f6; +} - .body { - background-color: #fafafa; - width: 100%; - } +.body-wrap { + background-color: #f6f6f6; + width: 100%; +} - /* Set a max-width, and make it display as block so it will automatically stretch to that width, but will also shrink down on a phone or something */ - .container { - display: block; - margin: 0 auto !important; - /* makes it centered */ - max-width: 580px; - padding: 10px; - width: 580px; - } +.container { + display: block !important; + max-width: 600px !important; + margin: 0 auto !important; + /* makes it centered */ + clear: both !important; +} - /* This should also be a block element, so that it will fill 100% of the .container */ - .content { - box-sizing: border-box; - display: block; - margin: 0 auto; - max-width: 580px; - padding: 10px; - } +.content { + max-width: 600px; + margin: 0 auto; + display: block; + padding: 20px; +} - /* ------------------------------------- +/* ------------------------------------- HEADER, FOOTER, MAIN - ------------------------------------- */ - .main { - background: #ffffff; - border-radius: 3px; - width: 100%; - } +------------------------------------- */ +.main { + background-color: #fff; + border: 1px solid #e9e9e9; + border-radius: 3px; +} - .wrapper { - box-sizing: border-box; - padding: 20px; - } +.content-wrap { + padding: 20px; +} - .content-block { - padding-bottom: 10px; - padding-top: 10px; - } +.content-block { + padding: 0 0 20px; +} - .footer { - clear: both; - margin-top: 10px; - text-align: center; - width: 100%; - } - .footer td, - .footer p, - .footer span, - .footer a { - color: #999999; - font-size: 12px; - text-align: center; - } +.header { + width: 100%; + margin-bottom: 20px; +} - /* ------------------------------------- +.footer { + width: 100%; + clear: both; + color: #999; + padding: 20px; +} +.footer p, .footer a, .footer td { + color: #999; + font-size: 12px; +} + +/* ------------------------------------- TYPOGRAPHY - ------------------------------------- */ - h1, - h2, - h3, - h4 { - color: #000000; - font-family: sans-serif; - font-weight: 400; - line-height: 1.4; - margin: 0; - margin-bottom: 30px; - } +------------------------------------- */ +h1, h2, h3 { + font-family: "Helvetica Neue", Helvetica, Arial, "Lucida Grande", sans-serif; + color: #000; + margin: 40px 0 0; + line-height: 1.2em; + font-weight: 400; +} - h1 { - font-size: 35px; - font-weight: 300; - text-align: center; - text-transform: capitalize; - } +h1 { + font-size: 32px; + font-weight: 500; + /* 1.2em * 32px = 38.4px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ + /*line-height: 38px;*/ +} - p, - ul, - ol { - font-family: sans-serif; - font-size: 14px; - font-weight: normal; - margin: 0; - margin-bottom: 15px; - } - p li, - ul li, - ol li { - list-style-position: inside; - margin-left: 5px; - } +h2 { + font-size: 24px; + /* 1.2em * 24px = 28.8px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ + /*line-height: 29px;*/ +} - a { - color: #06c; - border-radius: 3px; - text-decoration: underline; - } +h3 { + font-size: 18px; + /* 1.2em * 18px = 21.6px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ + /*line-height: 22px;*/ +} - /* ------------------------------------- - BUTTONS - ------------------------------------- */ - .btn { - box-sizing: border-box; - width: 100%; } - .btn > tbody > tr > td { - padding-bottom: 15px; } - .btn table { - width: auto; - } - .btn table td { - background-color: #ffffff; - border-radius: 5px; - text-align: center; - } - .btn a { - background-color: #ffffff; - border: solid 1px #06c; - border-radius: 5px; - box-sizing: border-box; - color: #06c; - cursor: pointer; - display: inline-block; - font-size: 14px; - font-weight: bold; - margin: 0; - padding: 12px 25px; - text-decoration: none; - text-transform: capitalize; - } +h4 { + font-size: 14px; + font-weight: 600; +} - .btn-primary table td { - background-color: #06c; - } +p, ul, ol { + margin-bottom: 10px; + font-weight: normal; +} +p li, ul li, ol li { + margin-left: 5px; + list-style-position: inside; +} - .btn-primary a { - background-color: #06c; - border-color: #06c; - color: #ffffff; - } +/* ------------------------------------- + LINKS & BUTTONS +------------------------------------- */ +a { + color: #348eda; + text-decoration: underline; +} - /* ------------------------------------- - OTHER STYLES THAT MIGHT BE USEFUL - ------------------------------------- */ - .last { - margin-bottom: 0; - } +.btn-primary { + text-decoration: none; + color: #FFF; + background-color: #348eda; + border: solid #348eda; + border-width: 10px 20px; + line-height: 2em; + /* 2em * 14px = 28px, use px to get airier line-height also in Thunderbird, and Yahoo!, Outlook.com, AOL webmail clients */ + /*line-height: 28px;*/ + font-weight: bold; + text-align: center; + cursor: pointer; + display: inline-block; + border-radius: 5px; + text-transform: capitalize; +} - .first { - margin-top: 0; - } +/* ------------------------------------- + OTHER STYLES THAT MIGHT BE USEFUL +------------------------------------- */ +.last { + margin-bottom: 0; +} - .align-center { - text-align: center; - } +.first { + margin-top: 0; +} - .align-right { - text-align: right; - } +.aligncenter { + text-align: center; +} - .align-left { - text-align: left; - } +.alignright { + text-align: right; +} - .clear { - clear: both; - } +.alignleft { + text-align: left; +} - .mt0 { - margin-top: 0; - } +.clear { + clear: both; +} - .mb0 { - margin-bottom: 0; - } +/* ------------------------------------- + ALERTS + Change the class depending on warning email, good email or bad email +------------------------------------- */ +.alert { + font-size: 16px; + color: #fff; + font-weight: 500; + padding: 20px; + text-align: center; + border-radius: 3px 3px 0 0; +} +.alert a { + color: #fff; + text-decoration: none; + font-weight: 500; + font-size: 16px; +} +.alert-brand { + background-color: #fd4b2d; +} +.alert-warning { + background-color: #F0AB00; +} +.alert-danger { + background-color: #C9190B; +} +.alert-success { + background-color: #3E8635; +} - .preheader { - color: transparent; - display: none; - height: 0; - max-height: 0; - max-width: 0; - opacity: 0; - overflow: hidden; - mso-hide: all; - visibility: hidden; - width: 0; - } +/* ------------------------------------- + INVOICE + Styles for the billing table +------------------------------------- */ +.invoice { + margin: 40px auto; + text-align: left; + width: 80%; +} +.invoice td { + padding: 5px 0; +} +.invoice .invoice-items { + width: 100%; +} +.invoice .invoice-items td { + border-top: #eee 1px solid; +} +.invoice .invoice-items .total td { + border-top: 2px solid #333; + border-bottom: 2px solid #333; + font-weight: 700; +} - .powered-by a { - text-decoration: none; - } +/* ------------------------------------- + RESPONSIVE AND MOBILE FRIENDLY STYLES +------------------------------------- */ +@media only screen and (max-width: 640px) { + body { + padding: 0 !important; + } - hr { - border: 0; - border-bottom: 1px solid #fafafa; - margin: 20px 0; - } + h1, h2, h3, h4 { + font-weight: 800 !important; + margin: 20px 0 5px !important; + } - /* ------------------------------------- - RESPONSIVE AND MOBILE FRIENDLY STYLES - ------------------------------------- */ - @media only screen and (max-width: 620px) { - table[class=body] h1 { - font-size: 28px !important; - margin-bottom: 10px !important; - } - table[class=body] p, - table[class=body] ul, - table[class=body] ol, - table[class=body] td, - table[class=body] span, - table[class=body] a { - font-size: 16px !important; - } - table[class=body] .wrapper, - table[class=body] .article { - padding: 10px !important; - } - table[class=body] .content { - padding: 0 !important; - } - table[class=body] .container { - padding: 0 !important; - width: 100% !important; - } - table[class=body] .main { - border-left-width: 0 !important; - border-radius: 0 !important; - border-right-width: 0 !important; - } - table[class=body] .btn table { - width: 100% !important; - } - table[class=body] .btn a { - width: 100% !important; - } - table[class=body] .img-responsive { - height: auto !important; - max-width: 100% !important; - width: auto !important; - } - } + h1 { + font-size: 22px !important; + } - /* ------------------------------------- - PRESERVE THESE STYLES IN THE HEAD - ------------------------------------- */ - @media all { - .ExternalClass { - width: 100%; - } - .ExternalClass, - .ExternalClass p, - .ExternalClass span, - .ExternalClass font, - .ExternalClass td, - .ExternalClass div { - line-height: 100%; - } - .apple-link a { - color: inherit !important; - font-family: inherit !important; - font-size: inherit !important; - font-weight: inherit !important; - line-height: inherit !important; - text-decoration: none !important; - } - #MessageViewBody a { - color: inherit; - text-decoration: none; - font-size: inherit; - font-family: inherit; - font-weight: inherit; - line-height: inherit; - } - .btn-primary table td:hover { - background-color: #34495e !important; - } - .btn-primary a:hover { - background-color: #34495e !important; - border-color: #34495e !important; - } - } + h2 { + font-size: 18px !important; + } + + h3 { + font-size: 16px !important; + } + + .container { + padding: 0 !important; + width: 100% !important; + } + + .content { + padding: 0 !important; + } + + .content-wrap { + padding: 10px !important; + } + + .invoice { + width: 100% !important; + } +} + +/*# sourceMappingURL=styles.css.map */ diff --git a/authentik/stages/email/tasks.py b/authentik/stages/email/tasks.py index bf1e02634..2903bf002 100644 --- a/authentik/stages/email/tasks.py +++ b/authentik/stages/email/tasks.py @@ -6,6 +6,7 @@ from typing import Any, Dict, List from celery import group from django.core.mail import EmailMultiAlternatives from django.core.mail.utils import DNS_NAME +from django.utils.text import slugify from structlog.stdlib import get_logger from authentik.lib.tasks import MonitoredTask, TaskResult, TaskResultStatus @@ -38,7 +39,7 @@ def send_mail(self: MonitoredTask, email_stage_pk: int, message: Dict[Any, Any]) """Send Email for Email Stage. Retries are scheduled automatically.""" self.save_on_success = False message_id = make_msgid(domain=DNS_NAME) - self.set_uid(message_id) + self.set_uid(slugify(message_id.replace(".", "_").replace("@", "_"))) try: stage: EmailStage = EmailStage.objects.get(pk=email_stage_pk) backend = stage.backend @@ -48,7 +49,8 @@ def send_mail(self: MonitoredTask, email_stage_pk: int, message: Dict[Any, Any]) message_object = EmailMultiAlternatives() for key, value in message.items(): setattr(message_object, key, value) - message_object.from_email = stage.from_address + if not stage.use_global_settings: + message_object.from_email = stage.from_address # Because we use the Message-ID as UID for the task, manually assign it message_object.extra_headers["Message-ID"] = message_id @@ -61,5 +63,6 @@ def send_mail(self: MonitoredTask, email_stage_pk: int, message: Dict[Any, Any]) ) ) except (SMTPException, ConnectionError) as exc: + LOGGER.debug("Error sending email, retrying...", exc=exc) self.set_status(TaskResult(TaskResultStatus.ERROR).with_error(exc)) raise exc diff --git a/authentik/stages/email/templates/stages/email/for_email/account_confirmation.html b/authentik/stages/email/templates/email/account_confirmation.html similarity index 95% rename from authentik/stages/email/templates/stages/email/for_email/account_confirmation.html rename to authentik/stages/email/templates/email/account_confirmation.html index 8c2b353e4..b6e1f7f62 100644 --- a/authentik/stages/email/templates/stages/email/for_email/account_confirmation.html +++ b/authentik/stages/email/templates/email/account_confirmation.html @@ -1,4 +1,4 @@ -{% extends 'stages/email/for_email/base.html' %} +{% extends 'email/base.html' %} {% load authentik_stages_email %} {% load i18n %} diff --git a/authentik/stages/email/templates/email/base.html b/authentik/stages/email/templates/email/base.html new file mode 100644 index 000000000..3797461a1 --- /dev/null +++ b/authentik/stages/email/templates/email/base.html @@ -0,0 +1,34 @@ +{% load authentik_stages_email %} + + + + + + + + + + + + + + + + +
+
+ + {% block content %} + {% endblock %} +
+ +
+
+ + diff --git a/authentik/stages/email/templates/email/generic.html b/authentik/stages/email/templates/email/generic.html new file mode 100644 index 000000000..01a242111 --- /dev/null +++ b/authentik/stages/email/templates/email/generic.html @@ -0,0 +1,20 @@ +{% extends "email/base.html" %} + +{% block content %} + + + {{ title }} + + + + + + + + +
+ {{ body }} +
+ + +{% endblock %} diff --git a/authentik/stages/email/templates/stages/email/for_email/password_reset.html b/authentik/stages/email/templates/email/password_reset.html similarity index 95% rename from authentik/stages/email/templates/stages/email/for_email/password_reset.html rename to authentik/stages/email/templates/email/password_reset.html index d6818daf2..3d6659ad4 100644 --- a/authentik/stages/email/templates/stages/email/for_email/password_reset.html +++ b/authentik/stages/email/templates/email/password_reset.html @@ -1,4 +1,4 @@ -{% extends "stages/email/for_email/base.html" %} +{% extends "email/base.html" %} {% load authentik_utils %} {% load i18n %} diff --git a/authentik/stages/email/templates/email/setup.html b/authentik/stages/email/templates/email/setup.html new file mode 100644 index 000000000..1efc08004 --- /dev/null +++ b/authentik/stages/email/templates/email/setup.html @@ -0,0 +1,25 @@ +{% extends "email/base.html" %} + +{% load authentik_stages_email %} +{% load i18n %} + +{% block content %} + + + {% trans 'authentik Test-Email' %} + + + + + + + + +
+ {% blocktrans %} + This is a test email to inform you, that you've successfully configured authentik emails. + {% endblocktrans %} +
+ + +{% endblock %} diff --git a/authentik/stages/email/templates/stages/email/for_email/base.html b/authentik/stages/email/templates/stages/email/for_email/base.html deleted file mode 100644 index 1261007a9..000000000 --- a/authentik/stages/email/templates/stages/email/for_email/base.html +++ /dev/null @@ -1,65 +0,0 @@ -{% load authentik_stages_email %} -{% load authentik_utils %} -{% load static %} -{% load i18n %} - - - - - - - - - - - - - - {% block pre_header %} - {% endblock %} - - - - - - - - - - - diff --git a/authentik/stages/email/templates/stages/email/for_email/generic_email.html b/authentik/stages/email/templates/stages/email/for_email/generic_email.html deleted file mode 100644 index 8246f93b6..000000000 --- a/authentik/stages/email/templates/stages/email/for_email/generic_email.html +++ /dev/null @@ -1,26 +0,0 @@ -{% extends "stages/email/for_email/base.html" %} - -{% block content %} - - - - - - -
-

{{ title }}!

-
- - - - - - - - -
-

{{ body }}

-
- - -{% endblock %} diff --git a/authentik/stages/email/tests/__init__.py b/authentik/stages/email/tests/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/authentik/stages/email/tests/test_sending.py b/authentik/stages/email/tests/test_sending.py new file mode 100644 index 000000000..b97a8ce7c --- /dev/null +++ b/authentik/stages/email/tests/test_sending.py @@ -0,0 +1,83 @@ +"""email tests""" +from smtplib import SMTPException +from unittest.mock import MagicMock, patch + +from django.core import mail +from django.core.mail.backends.locmem import EmailBackend +from django.shortcuts import reverse +from django.test import Client, TestCase + +from authentik.core.models import User +from authentik.flows.markers import StageMarker +from authentik.flows.models import Flow, FlowDesignation, FlowStageBinding +from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER, FlowPlan +from authentik.flows.views import SESSION_KEY_PLAN +from authentik.stages.email.models import EmailStage + + +class TestEmailStageSending(TestCase): + """Email tests""" + + def setUp(self): + super().setUp() + self.user = User.objects.create_user( + username="unittest", email="test@beryju.org" + ) + self.client = Client() + + self.flow = Flow.objects.create( + name="test-email", + slug="test-email", + designation=FlowDesignation.AUTHENTICATION, + ) + self.stage = EmailStage.objects.create( + name="email", + ) + FlowStageBinding.objects.create(target=self.flow, stage=self.stage, order=2) + + def test_pending_user(self): + """Test with pending user""" + plan = FlowPlan( + flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] + ) + plan.context[PLAN_CONTEXT_PENDING_USER] = self.user + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + + url = reverse( + "authentik_flows:flow-executor", kwargs={"flow_slug": self.flow.slug} + ) + with self.settings( + EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend" + ): + response = self.client.post(url) + self.assertEqual(response.status_code, 200) + self.assertEqual(len(mail.outbox), 1) + self.assertEqual(mail.outbox[0].subject, "authentik") + + def test_send_error(self): + """Test error during sending (sending will be retried)""" + plan = FlowPlan( + flow_pk=self.flow.pk.hex, stages=[self.stage], markers=[StageMarker()] + ) + plan.context[PLAN_CONTEXT_PENDING_USER] = self.user + session = self.client.session + session[SESSION_KEY_PLAN] = plan + session.save() + + url = reverse( + "authentik_flows:flow-executor", kwargs={"flow_slug": self.flow.slug} + ) + with self.settings( + EMAIL_BACKEND="django.core.mail.backends.locmem.EmailBackend" + ): + with patch( + "django.core.mail.backends.locmem.EmailBackend.send_messages", + MagicMock(side_effect=[SMTPException, EmailBackend.send_messages]), + ): + response = self.client.post(url) + response = self.client.post(url) + self.assertEqual(response.status_code, 200) + self.assertTrue(len(mail.outbox) >= 1) + self.assertEqual(mail.outbox[0].subject, "authentik") diff --git a/authentik/stages/email/tests.py b/authentik/stages/email/tests/test_stage.py similarity index 93% rename from authentik/stages/email/tests.py rename to authentik/stages/email/tests/test_stage.py index c71a0b2d5..0a84ecf7b 100644 --- a/authentik/stages/email/tests.py +++ b/authentik/stages/email/tests/test_stage.py @@ -87,6 +87,14 @@ class TestEmailStage(TestCase): self.assertEqual(len(mail.outbox), 1) self.assertEqual(mail.outbox[0].subject, "authentik") + def test_use_global_settings(self): + """Test use_global_settings""" + host = "some-unique-string" + with self.settings( + EMAIL_HOST=host, EMAIL_BACKEND="django.core.mail.backends.smtp.EmailBackend" + ): + self.assertEqual(EmailStage(use_global_settings=True).backend.host, host) + def test_token(self): """Test with token""" # Make sure token exists diff --git a/authentik/stages/email/tests/test_templates.py b/authentik/stages/email/tests/test_templates.py new file mode 100644 index 000000000..3c2c06c93 --- /dev/null +++ b/authentik/stages/email/tests/test_templates.py @@ -0,0 +1,28 @@ +"""email tests""" +from os import unlink +from pathlib import Path +from tempfile import gettempdir, mkstemp +from typing import Any + +from django.conf import settings +from django.test import TestCase + +from authentik.stages.email.models import get_template_choices + + +def get_templates_setting(temp_dir: str) -> dict[str, Any]: + """Patch settings TEMPLATE's dir property""" + templates_setting = settings.TEMPLATES + templates_setting[0]["DIRS"] = [temp_dir] + return templates_setting + + +class TestEmailStageTemplates(TestCase): + """Email tests""" + + def test_custom_template(self): + """Test with custom template""" + with self.settings(TEMPLATES=get_templates_setting(gettempdir())): + _, file = mkstemp(suffix=".html") + self.assertEqual(get_template_choices()[-1][0], Path(file).name) + unlink(file) diff --git a/docker-compose.yml b/docker-compose.yml index b6c0b4659..a3653d32a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -29,6 +29,7 @@ services: AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} volumes: - ./media:/media + - ./custom-templates:/templates ports: - 8000 networks: @@ -57,6 +58,7 @@ services: volumes: - ./backups:/backups - /var/run/docker.sock:/var/run/docker.sock + - ./custom-templates:/templates env_file: - .env static: diff --git a/helm/README.md b/helm/README.md index 5780b8026..a2df9d6cc 100644 --- a/helm/README.md +++ b/helm/README.md @@ -2,9 +2,9 @@ | Name | Default | Description | |-----------------------------------|-------------------------|-------------| -| image.name | beryju/authentik | Image used to run the authentik server and worker | -| image.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) | -| image.tag | 0.14.2-stable | Image tag | +| image.name | beryju/authentik | Image used to run the authentik server and worker | +| image.name_static | beryju/authentik-static | Image used to run the authentik static server (CSS and JS Files) | +| image.tag | 0.14.2-stable | Image tag | | image.pullPolicy | IfNotPresent | Image Pull Policy used for all deployments | | serverReplicas | 1 | Replicas for the Server deployment | | workerReplicas | 1 | Replicas for the Worker deployment | @@ -14,13 +14,21 @@ | config.errorReporting.environment | customer | Environment sent with the error reporting | | config.errorReporting.sendPii | false | Whether to send Personally-identifiable data with the error reporting | | config.logLevel | warning | Log level of authentik | +| config.email.host | localhost | SMTP Host Emails are sent to | +| config.email.port | 25 | SMTP Port Emails are sent to | +| config.email.username | | SMTP Username | +| config.email.password | | SMTP Password | +| config.email.use_tls | false | Enable StartTLS | +| config.email.use_ssl | false | Enable SSL | +| config.email.timeout | 10 | SMTP Timeout | +| config.email.from | authentik@localhost | Email address authentik will send from, should have a correct @domain | | backup.accessKey | | Optionally enable S3 Backup, Access Key | | backup.secretKey | | Optionally enable S3 Backup, Secret Key | | backup.bucket | | Optionally enable S3 Backup, Bucket | | backup.region | | Optionally enable S3 Backup, Region | | backup.host | | Optionally enable S3 Backup, to custom Endpoint like minio | | ingress.annotations | {} | Annotations for the ingress object | -| ingress.hosts | [authentik.k8s.local] | Hosts which the ingress will match | +| ingress.hosts | [authentik.k8s.local] | Hosts which the ingress will match | | ingress.tls | [] | TLS Configuration, same as Ingress objects | | install.postgresql | true | Enables/disables the packaged PostgreSQL Chart | install.redis | true | Enables/disables the packaged Redis Chart diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml index 61af2bf65..6a3a3c796 100644 --- a/helm/templates/configmap.yaml +++ b/helm/templates/configmap.yaml @@ -8,7 +8,6 @@ data: POSTGRESQL__USER: "{{ .Values.postgresql.postgresqlUsername }}" {{- if .Values.backup }} POSTGRESQL__S3_BACKUP__ACCESS_KEY: "{{ .Values.backup.accessKey }}" - POSTGRESQL__S3_BACKUP__SECRET_KEY: "{{ .Values.backup.secretKey }}" POSTGRESQL__S3_BACKUP__BUCKET: "{{ .Values.backup.bucket }}" POSTGRESQL__S3_BACKUP__REGION: "{{ .Values.backup.region }}" POSTGRESQL__S3_BACKUP__HOST: "{{ .Values.backup.host }}" @@ -19,3 +18,10 @@ data: ERROR_REPORTING__SEND_PII: "{{ .Values.config.errorReporting.sendPii }}" LOG_LEVEL: "{{ .Values.config.logLevel }}" OUTPOSTS__DOCKER_IMAGE_BASE: "{{ .Values.image.name_outposts }}" + EMAIL__HOST: "{{ .Values.config.email.host }}" + EMAIL__PORT: "{{ .Values.config.email.port }}" + EMAIL__USERNAM: "{{ .Values.config.email.username }}" + EMAIL__USE_TLS: "{{ .Values.config.email.use_tls }}" + EMAIL__USE_SSL: "{{ .Values.config.email.use_ssl }}" + EMAIL__TIMEOUT: "{{ .Values.config.email.timeout }}" + EMAIL__FROM: "{{ .Values.config.email.from }}" diff --git a/helm/templates/secret.yaml b/helm/templates/secret.yaml index bbe9ff8d5..90a5d1043 100644 --- a/helm/templates/secret.yaml +++ b/helm/templates/secret.yaml @@ -6,7 +6,11 @@ metadata: data: monitoring_username: bW9uaXRvcg== # monitor in base64 {{- if .Values.config.secretKey }} - secret_key: {{ .Values.config.secretKey | b64enc | quote }} + SECRET_KEY: {{ .Values.config.secretKey | b64enc | quote }} {{- else }} - secret_key: {{ randAlphaNum 50 | b64enc | quote}} + SECRET_KEY: {{ randAlphaNum 50 | b64enc | quote}} {{- end }} + {{- if .Values.backup }} + POSTGRESQL__S3_BACKUP__SECRET_KEY: "{{ .Values.backup.secretKey }}" + {{- end}} + EMAIL__PASSWOR: "{{ .Values.config.email.password }}" diff --git a/helm/templates/web-deployment.yaml b/helm/templates/web-deployment.yaml index 179be6251..5a2fb3268 100644 --- a/helm/templates/web-deployment.yaml +++ b/helm/templates/web-deployment.yaml @@ -51,12 +51,10 @@ spec: - configMapRef: name: {{ include "authentik.fullname" . }}-config prefix: AUTHENTIK_ + - secretRef: + name: {{ include "authentik.fullname" . }}-secret-key + prefix: AUTHENTIK_ env: - - name: AUTHENTIK_SECRET_KEY - valueFrom: - secretKeyRef: - name: {{ include "authentik.fullname" . }}-secret-key - key: secret_key - name: AUTHENTIK_REDIS__PASSWORD valueFrom: secretKeyRef: diff --git a/helm/templates/worker-deployment.yaml b/helm/templates/worker-deployment.yaml index af084295b..60fb58f1f 100644 --- a/helm/templates/worker-deployment.yaml +++ b/helm/templates/worker-deployment.yaml @@ -54,12 +54,10 @@ spec: - configMapRef: name: "{{ include "authentik.fullname" . }}-config" prefix: "AUTHENTIK_" + - secretRef: + name: {{ include "authentik.fullname" . }}-secret-key + prefix: AUTHENTIK_ env: - - name: AUTHENTIK_SECRET_KEY - valueFrom: - secretKeyRef: - name: "{{ include "authentik.fullname" . }}-secret-key" - key: secret_key - name: AUTHENTIK_REDIS__PASSWORD valueFrom: secretKeyRef: diff --git a/helm/values.yaml b/helm/values.yaml index be9aab158..d66d2ef38 100644 --- a/helm/values.yaml +++ b/helm/values.yaml @@ -25,6 +25,21 @@ config: # Log level used by web and worker # Can be either debug, info, warning, error logLevel: warning + # Global Email settings + email: + # SMTP Host Emails are sent to + host: localhost + port: 25 + # Optionally authenticate + username: "" + password: "" + # Use StartTLS + useTls: false + # Use SSL + useSsl: false + timeout: 10 + # Email address authentik will send from, should have a correct @domain + from: authentik@localhost # Enable Database Backups to S3 # backup: diff --git a/swagger.yaml b/swagger.yaml index adbc2e5a2..e0305698f 100755 --- a/swagger.yaml +++ b/swagger.yaml @@ -8579,6 +8579,11 @@ definitions: title: Name type: string minLength: 1 + use_global_settings: + title: Use global settings + description: When enabled, global Email connection settings will be used and + connection settings below will be ignored. + type: boolean host: title: Host type: string @@ -8625,8 +8630,8 @@ definitions: title: Template type: string enum: - - stages/email/for_email/password_reset.html - - stages/email/for_email/account_confirmation.html + - email/password_reset.html + - email/account_confirmation.html IdentificationStage: description: IdentificationStage Serializer required: diff --git a/website/docs/flow/stages/email/custom-template.png b/website/docs/flow/stages/email/custom-template.png new file mode 100644 index 0000000000000000000000000000000000000000..072bae3107447b888a8213ab932da70f51e2efde GIT binary patch literal 85201 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%0AbRL)2m6D27v^ow!xK+)&Zjy^-)LF6URCyH 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 literal 0 HcmV?d00001 diff --git a/website/docs/flow/stages/email/index.md b/website/docs/flow/stages/email/index.md index 3eec6474d..8837570af 100644 --- a/website/docs/flow/stages/email/index.md +++ b/website/docs/flow/stages/email/index.md @@ -5,3 +5,19 @@ title: Email stage This stage can be used for email verification. authentik's background worker will send an email using the specified connection details. When an email can't be delivered, delivery is automatically retried periodically. ![](email-recovery.png) + +## Custom Templates + +You can also use custom email templates, to use your own design or layout. + +Place any custom templates in the `custom-templates` Folder, which is in the same folder as your docker-compose file. Afterwards, you'll be able to select the template when creating/editing an Email stage. + +:::info +This is currently only supported for docker-compose installs, and supported starting version 0.15. +::: + +:::info +If you've add the line and created a file, and can't see if, check the logs using `docker-compose logs -f worker`. +::: + +![](custom-template.png) diff --git a/website/docs/index.md b/website/docs/index.md index 1ea964dea..0b2d63055 100755 --- a/website/docs/index.md +++ b/website/docs/index.md @@ -9,7 +9,7 @@ authentik is an open-source Identity Provider focused on flexibility and versati ## Installation -See [Docker-compose](installation/docker-compose.md) or [Kubernetes](installation/kubernetes.md) +See [Docker-compose](installation/docker-compose) or [Kubernetes](installation/kubernetes) ## Screenshots diff --git a/website/docs/installation/docker-compose.md b/website/docs/installation/docker-compose.md index c33f32036..87005f5f2 100644 --- a/website/docs/installation/docker-compose.md +++ b/website/docs/installation/docker-compose.md @@ -9,7 +9,7 @@ This installation method is for test-setups and small-scale productive setups. - docker - docker-compose -## Install +## Preparation Download the latest `docker-compose.yml` from [here](https://raw.githubusercontent.com/BeryJu/authentik/master/docker-compose.yml). Place it in a directory of your choice. @@ -25,6 +25,30 @@ echo "PG_PASS=$(pwgen 40 1)" >> .env echo "AUTHENTIK_SECRET_KEY=$(pwgen 50 1)" >> .env ``` +## Email configuration (optional, but recommended) + +It is also recommended to configure global email credentials. These are used by authentik to notify you about alerts, configuration issues. They can also be used by [Email stages](flow/stages/email/index.md) to send verification/recovery emails. + +Append this block to your `.env` file + +``` +# SMTP Host Emails are sent to +AUTHENTIK_EMAIL__HOST=localhost +AUTHENTIK_EMAIL__PORT=25 +# Optionally authenticate +AUTHENTIK_EMAIL__USERNAME="" +AUTHENTIK_EMAIL__PASSWORD="" +# Use StartTLS +AUTHENTIK_EMAIL__USE_TLS=false +# Use SSL +AUTHENTIK_EMAIL__USE_SSL=false +AUTHENTIK_EMAIL__TIMEOUT=10 +# Email address authentik will send from, should have a correct @domain +AUTHENTIK_EMAIL__FROM=authentik@localhost +``` + +## Startup + Afterwards, run these commands to finish ``` @@ -39,8 +63,6 @@ If you plan to use this setup for production, it is also advised to change the P Now you can pull the Docker images needed by running `docker-compose pull`. After this has finished, run `docker-compose up -d` to start authentik. -authentik will then be reachable via HTTP on port 80, and HTTPS on port 443. You can optionally configure the packaged traefik to use Let's Encrypt certificates for TLS Encryption. - -If you plan to access authentik via a reverse proxy which does SSL Termination, make sure you use the HTTPS port, so authentik is aware of the SSL connection. +authentik will then be reachable HTTPS on port 443. You can optionally configure the packaged traefik to use Let's Encrypt certificates for TLS Encryption. The initial setup process also creates a default admin user, the username and password for which is `akadmin`. It is highly recommended to change this password as soon as you log in. diff --git a/website/docs/installation/kubernetes.md b/website/docs/installation/kubernetes.md index 192e59ec8..79722fc04 100644 --- a/website/docs/installation/kubernetes.md +++ b/website/docs/installation/kubernetes.md @@ -14,6 +14,8 @@ helm install authentik/authentik --devel -f values.yaml This installation automatically applies database migrations on startup. After the installation is done, you can use `akadmin` as username and password. +It is also recommended to configure global email credentials. These are used by authentik to notify you about alerts, configuration issues. They can also be used by [Email stages](flow/stages/email/index.md) to send verification/recovery emails. + ```yaml ################################### # Values directly affecting authentik @@ -41,6 +43,21 @@ config: # Log level used by web and worker # Can be either debug, info, warning, error logLevel: warning + # Global Email settings + email: + # SMTP Host Emails are sent to + host: localhost + port: 25 + # Optionally authenticate + username: "" + password: "" + # Use StartTLS + useTls: false + # Use SSL + useSsl: false + timeout: 10 + # Email address authentik will send from, should have a correct @domain + from: authentik@localhost # Enable Database Backups to S3 # backup: @@ -80,6 +97,4 @@ redis: master: persistence: enabled: false - # https://stackoverflow.com/a/59189742 - disableCommands: [] ``` diff --git a/website/docs/troubleshooting/emails.md b/website/docs/troubleshooting/emails.md new file mode 100644 index 000000000..13323624e --- /dev/null +++ b/website/docs/troubleshooting/emails.md @@ -0,0 +1,23 @@ +--- +title: Troubleshooting Email sending +--- + +To test if an email stage, or the global email settings are configured correctly, you can run the following command: + +```` +./manage.py test_email [-s ] +``` + +If you omit the `-s` parameter, the email will be sent using the global settings. Otherwise, the settings of the specified stage will be used. + +To run this command with docker-compose, use + +``` +docker-compose exec -it worker ./manage.py test_email [...] +``` + +To run this command with Kubernetes, use + +``` +kubectl exec -it authentik-worker-xxxxx -- ./manage.py test_email [...] +``` diff --git a/website/sidebars.js b/website/sidebars.js index 1760bf768..62a3d6f44 100644 --- a/website/sidebars.js +++ b/website/sidebars.js @@ -135,7 +135,10 @@ module.exports = { { type: "category", label: "Troubleshooting", - items: ["troubleshooting/access"], + items: [ + "troubleshooting/access", + "troubleshooting/emails", + ], }, { type: "category", diff --git a/website/static/flows/enrollment-email-verification.pbflow b/website/static/flows/enrollment-email-verification.pbflow index 5a07481a3..b002933a1 100644 --- a/website/static/flows/enrollment-email-verification.pbflow +++ b/website/static/flows/enrollment-email-verification.pbflow @@ -99,7 +99,7 @@ "from_address": "system@authentik.local", "token_expiry": 30, "subject": "authentik", - "template": "stages/email/for_email/account_confirmation.html" + "template": "email/account_confirmation.html" } }, { diff --git a/website/static/flows/recovery-email-verification.pbflow b/website/static/flows/recovery-email-verification.pbflow index 271b5591c..d6b9f65e0 100644 --- a/website/static/flows/recovery-email-verification.pbflow +++ b/website/static/flows/recovery-email-verification.pbflow @@ -92,7 +92,7 @@ "from_address": "system@authentik.local", "token_expiry": 30, "subject": "authentik", - "template": "stages/email/for_email/password_reset.html" + "template": "email/password_reset.html" } }, {