149 lines
5.9 KiB
Django/Jinja
149 lines
5.9 KiB
Django/Jinja
# Noble — **lab** hostname authentication: operator-only, stricter password checks, MFA required (no WebAuthn-PWL skip).
|
|
version: 1
|
|
metadata:
|
|
name: noble-lab-operator-authentication
|
|
labels:
|
|
blueprints.goauthentik.io/instantiate: "true"
|
|
entries:
|
|
- model: authentik_blueprints.metaapplyblueprint
|
|
attrs:
|
|
identifiers:
|
|
name: Default - Password change flow
|
|
required: false
|
|
- model: authentik_stages_password.passwordstage
|
|
id: noble-lab-password-stage
|
|
identifiers:
|
|
name: noble-lab-authentication-password
|
|
attrs:
|
|
backends:
|
|
- authentik.core.auth.InbuiltBackend
|
|
- authentik.sources.kerberos.auth.KerberosBackend
|
|
- authentik.sources.ldap.auth.LDAPBackend
|
|
- authentik.core.auth.TokenBackend
|
|
configure_flow: !Find [authentik_flows.flow, [slug, default-password-change]]
|
|
failed_attempts_before_cancel: {{ noble_authentik_blueprint_lab_password_failed_attempts | int }}
|
|
- model: authentik_stages_authenticator_validate.authenticatorvalidatestage
|
|
id: noble-lab-authenticator-validate-strict
|
|
identifiers:
|
|
name: noble-lab-authenticator-validate-strict
|
|
attrs:
|
|
not_configured_action: {{ noble_authentik_blueprint_lab_mfa_not_configured_action | trim | lower | to_json }}
|
|
{% if noble_authentik_blueprint_lab_mfa_not_configured_action | trim | lower == 'configure' %}
|
|
configuration_stages:
|
|
- !Find [authentik_stages_authenticator_totp.authenticatortotpstage, [name, default-authenticator-totp-setup]]
|
|
{% endif %}
|
|
- model: authentik_flows.flow
|
|
id: flow
|
|
identifiers:
|
|
slug: {{ noble_authentik_blueprint_lab_flow_slug | trim | to_json }}
|
|
attrs:
|
|
name: Noble lab (operators)
|
|
title: Noble lab — operators only
|
|
designation: authentication
|
|
authentication: none
|
|
- id: noble-lab-identification-binding
|
|
model: authentik_flows.flowstagebinding
|
|
identifiers:
|
|
order: 10
|
|
stage: !Find [authentik_stages_identification.identificationstage, [name, default-authentication-identification]]
|
|
target: !KeyOf flow
|
|
- id: noble-lab-password-binding
|
|
model: authentik_flows.flowstagebinding
|
|
identifiers:
|
|
order: 20
|
|
stage: !KeyOf noble-lab-password-stage
|
|
target: !KeyOf flow
|
|
attrs:
|
|
re_evaluate_policies: true
|
|
- id: noble-lab-authenticator-binding
|
|
model: authentik_flows.flowstagebinding
|
|
identifiers:
|
|
order: 30
|
|
stage: !KeyOf noble-lab-authenticator-validate-strict
|
|
target: !KeyOf flow
|
|
- model: authentik_flows.flowstagebinding
|
|
identifiers:
|
|
order: 100
|
|
stage: !Find [authentik_stages_user_login.userloginstage, [name, default-authentication-login]]
|
|
target: !KeyOf flow
|
|
- model: authentik_policies_expression.expressionpolicy
|
|
id: noble-lab-password-optional
|
|
identifiers:
|
|
name: noble-lab-password-optional
|
|
attrs:
|
|
expression: |
|
|
flow_plan = request.context.get("flow_plan")
|
|
if not flow_plan:
|
|
return True
|
|
return not hasattr(flow_plan.context.get("pending_user"), "backend")
|
|
- model: authentik_policies_expression.expressionpolicy
|
|
id: noble-lab-password-strength
|
|
identifiers:
|
|
name: noble-lab-password-strength
|
|
attrs:
|
|
expression: |
|
|
import re
|
|
_zxc = {{ noble_authentik_blueprint_lab_password_policy_check_zxcvbn | bool }}
|
|
_zxc_thr = {{ noble_authentik_blueprint_lab_password_policy_zxcvbn_score_threshold | int }}
|
|
pwd = request.context.get("password")
|
|
if not pwd:
|
|
return True
|
|
msg = {{ noble_authentik_blueprint_lab_password_policy_error_message | trim | to_json }}
|
|
if len(pwd) < {{ noble_authentik_blueprint_lab_password_policy_length_min | int }}:
|
|
ak_message(msg)
|
|
return False
|
|
if len(re.findall(r"[A-Z]", pwd)) < {{ noble_authentik_blueprint_lab_password_policy_amount_uppercase | int }}:
|
|
ak_message(msg)
|
|
return False
|
|
if len(re.findall(r"[a-z]", pwd)) < {{ noble_authentik_blueprint_lab_password_policy_amount_lowercase | int }}:
|
|
ak_message(msg)
|
|
return False
|
|
if len(re.findall(r"[0-9]", pwd)) < {{ noble_authentik_blueprint_lab_password_policy_amount_digits | int }}:
|
|
ak_message(msg)
|
|
return False
|
|
sym = sum(1 for c in pwd if (not c.isalnum()) and (not c.isspace()))
|
|
if sym < {{ noble_authentik_blueprint_lab_password_policy_amount_symbols | int }}:
|
|
ak_message(msg)
|
|
return False
|
|
if _zxc:
|
|
try:
|
|
from zxcvbn import zxcvbn
|
|
if zxcvbn(pwd[:72])["score"] <= _zxc_thr:
|
|
ak_message("Password is too weak for the lab policy.")
|
|
return False
|
|
except Exception:
|
|
pass
|
|
return True
|
|
- model: authentik_policies_expression.expressionpolicy
|
|
id: noble-lab-operators-only
|
|
identifiers:
|
|
name: {{ noble_authentik_blueprint_operator_policy_name | trim | to_json }}
|
|
attrs:
|
|
expression: |
|
|
u = context.get("pending_user")
|
|
if u is None:
|
|
return False
|
|
{% for g in noble_authentik_blueprint_lab_operator_groups | default([]) %}
|
|
if ak_is_group_member(u, name={{ g | trim | to_json }}):
|
|
return True
|
|
{% endfor %}
|
|
ak_message("This login URL is for administrators only. Use the public Authentik hostname instead.")
|
|
return False
|
|
- model: authentik_policies.policybinding
|
|
identifiers:
|
|
order: 5
|
|
target: !KeyOf noble-lab-password-binding
|
|
policy: !KeyOf noble-lab-operators-only
|
|
- model: authentik_policies.policybinding
|
|
identifiers:
|
|
order: 10
|
|
target: !KeyOf noble-lab-password-binding
|
|
policy: !KeyOf noble-lab-password-optional
|
|
attrs:
|
|
failure_result: true
|
|
- model: authentik_policies.policybinding
|
|
identifiers:
|
|
order: 15
|
|
target: !KeyOf noble-lab-password-binding
|
|
policy: !KeyOf noble-lab-password-strength
|