sources/saml: separate verification cert (#5699)

* sources/saml: allow separate verification certificate to be specified

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* add migration to keep current behaviour

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* update strings

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

* keep testing verification

Signed-off-by: Jens Langhammer <jens@goauthentik.io>

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
Jens L 2023-05-21 14:42:17 +02:00 committed by GitHub
parent d8de60b053
commit 5d5938c412
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 952 additions and 1064 deletions

View file

@ -90,6 +90,7 @@ class TestAuthNRequest(TestCase):
issuer="authentik",
pre_authentication_flow=create_test_flow(),
signing_kp=cert,
verification_kp=cert,
)
def test_signed_valid(self):

View file

@ -26,6 +26,7 @@ class SAMLSourceSerializer(SourceSerializer):
"allow_idp_initiated",
"name_id_policy",
"binding_type",
"verification_kp",
"signing_kp",
"digest_algorithm",
"signature_algorithm",
@ -55,6 +56,7 @@ class SAMLSourceViewSet(UsedByMixin, ModelViewSet):
"allow_idp_initiated",
"name_id_policy",
"binding_type",
"verification_kp",
"signing_kp",
"digest_algorithm",
"signature_algorithm",

View file

@ -0,0 +1,53 @@
# Generated by Django 4.1.7 on 2023-05-19 21:55
import django.db.models.deletion
from django.apps.registry import Apps
from django.db import migrations, models
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
def migrate_verification_cert(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
"""Migrate signing cert to verification_kp for backwards compat"""
SAMLSource = apps.get_model("authentik_sources_saml", "samlsource")
for source in SAMLSource.objects.using(schema_editor.connection.alias).all():
source.verification_kp = source.signing_kp
source.save()
class Migration(migrations.Migration):
dependencies = [
("authentik_crypto", "0004_alter_certificatekeypair_name"),
("authentik_sources_saml", "0012_usersamlsourceconnection"),
]
operations = [
migrations.AddField(
model_name="samlsource",
name="verification_kp",
field=models.ForeignKey(
blank=True,
default=None,
help_text="When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
related_name="+",
to="authentik_crypto.certificatekeypair",
verbose_name="Verification Certificate",
),
),
migrations.RunPython(migrate_verification_cert),
migrations.AlterField(
model_name="samlsource",
name="signing_kp",
field=models.ForeignKey(
blank=True,
default=None,
help_text="Keypair used to sign outgoing Responses going to the Identity Provider.",
null=True,
on_delete=django.db.models.deletion.SET_NULL,
to="authentik_crypto.certificatekeypair",
verbose_name="Signing Keypair",
),
),
]

View file

@ -121,16 +121,27 @@ class SAMLSource(Source):
),
)
verification_kp = models.ForeignKey(
CertificateKeyPair,
default=None,
null=True,
blank=True,
help_text=_(
"When selected, incoming assertion's Signatures will be validated against this "
"certificate. To allow unsigned Requests, leave on default."
),
on_delete=models.SET_NULL,
verbose_name=_("Verification Certificate"),
related_name="+",
)
signing_kp = models.ForeignKey(
CertificateKeyPair,
default=None,
blank=True,
null=True,
blank=True,
help_text=_("Keypair used to sign outgoing Responses going to the Identity Provider."),
on_delete=models.SET_NULL,
verbose_name=_("Signing Keypair"),
help_text=_(
"Keypair which is used to sign outgoing requests. Leave empty to disable signing."
),
on_delete=models.SET_DEFAULT,
)
digest_algorithm = models.CharField(

View file

@ -72,7 +72,7 @@ class ResponseProcessor:
self._root_xml = b64decode(raw_response.encode())
self._root = fromstring(self._root_xml)
if self._source.signing_kp:
if self._source.verification_kp:
self._verify_signed()
self._verify_request_id()
self._verify_status()
@ -89,7 +89,7 @@ class ResponseProcessor:
ctx = xmlsec.SignatureContext()
key = xmlsec.Key.from_memory(
self._source.signing_kp.certificate_data,
self._source.verification_kp.certificate_data,
xmlsec.constants.KeyDataFormatCertPem,
)
ctx.key = key

View file

@ -5257,10 +5257,15 @@
],
"title": "Binding type"
},
"verification_kp": {
"type": "integer",
"title": "Verification Certificate",
"description": "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
},
"signing_kp": {
"type": "integer",
"title": "Signing Keypair",
"description": "Keypair which is used to sign outgoing requests. Leave empty to disable signing."
"description": "Keypair used to sign outgoing Responses going to the Identity Provider."
},
"digest_algorithm": {
"type": "string",

View file

@ -8,7 +8,7 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2023-05-18 14:21+0000\n"
"POT-Creation-Date: 2023-05-19 22:00+0000\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
@ -1283,49 +1283,49 @@ msgid ""
"minutes=2;seconds=3)."
msgstr ""
#: authentik/providers/saml/models.py:99 authentik/sources/saml/models.py:139
#: authentik/providers/saml/models.py:99 authentik/sources/saml/models.py:150
msgid "SHA1"
msgstr ""
#: authentik/providers/saml/models.py:100 authentik/sources/saml/models.py:140
#: authentik/providers/saml/models.py:100 authentik/sources/saml/models.py:151
msgid "SHA256"
msgstr ""
#: authentik/providers/saml/models.py:101 authentik/sources/saml/models.py:141
#: authentik/providers/saml/models.py:101 authentik/sources/saml/models.py:152
msgid "SHA384"
msgstr ""
#: authentik/providers/saml/models.py:102 authentik/sources/saml/models.py:142
#: authentik/providers/saml/models.py:102 authentik/sources/saml/models.py:153
msgid "SHA512"
msgstr ""
#: authentik/providers/saml/models.py:109 authentik/sources/saml/models.py:149
#: authentik/providers/saml/models.py:109 authentik/sources/saml/models.py:160
msgid "RSA-SHA1"
msgstr ""
#: authentik/providers/saml/models.py:110 authentik/sources/saml/models.py:150
#: authentik/providers/saml/models.py:110 authentik/sources/saml/models.py:161
msgid "RSA-SHA256"
msgstr ""
#: authentik/providers/saml/models.py:111 authentik/sources/saml/models.py:151
#: authentik/providers/saml/models.py:111 authentik/sources/saml/models.py:162
msgid "RSA-SHA384"
msgstr ""
#: authentik/providers/saml/models.py:112 authentik/sources/saml/models.py:152
#: authentik/providers/saml/models.py:112 authentik/sources/saml/models.py:163
msgid "RSA-SHA512"
msgstr ""
#: authentik/providers/saml/models.py:113 authentik/sources/saml/models.py:153
#: authentik/providers/saml/models.py:113 authentik/sources/saml/models.py:164
msgid "DSA-SHA1"
msgstr ""
#: authentik/providers/saml/models.py:124
#: authentik/providers/saml/models.py:124 authentik/sources/saml/models.py:130
msgid ""
"When selected, incoming assertion's Signatures will be validated against "
"this certificate. To allow unsigned Requests, leave on default."
msgstr ""
#: authentik/providers/saml/models.py:128
#: authentik/providers/saml/models.py:128 authentik/sources/saml/models.py:134
msgid "Verification Certificate"
msgstr ""
@ -1333,7 +1333,7 @@ msgstr ""
msgid "Keypair used to sign outgoing Responses going to the Service Provider."
msgstr ""
#: authentik/providers/saml/models.py:138 authentik/sources/saml/models.py:129
#: authentik/providers/saml/models.py:138 authentik/sources/saml/models.py:144
msgid "Signing Keypair"
msgstr ""
@ -1498,7 +1498,7 @@ msgstr ""
msgid "LDAP Property Mappings"
msgstr ""
#: authentik/sources/ldap/signals.py:56
#: authentik/sources/ldap/signals.py:59
msgid "Password does not match Active Directory Complexity."
msgstr ""
@ -1764,25 +1764,23 @@ msgid ""
"manually. (Format: hours=1;minutes=2;seconds=3)."
msgstr ""
#: authentik/sources/saml/models.py:131
msgid ""
"Keypair which is used to sign outgoing requests. Leave empty to disable "
"signing."
#: authentik/sources/saml/models.py:142
msgid "Keypair used to sign outgoing Responses going to the Identity Provider."
msgstr ""
#: authentik/sources/saml/models.py:215
#: authentik/sources/saml/models.py:226
msgid "SAML Source"
msgstr ""
#: authentik/sources/saml/models.py:216
#: authentik/sources/saml/models.py:227
msgid "SAML Sources"
msgstr ""
#: authentik/sources/saml/models.py:231
#: authentik/sources/saml/models.py:242
msgid "User SAML Source Connection"
msgstr ""
#: authentik/sources/saml/models.py:232
#: authentik/sources/saml/models.py:243
msgid "User SAML Source Connections"
msgstr ""

View file

@ -18450,6 +18450,11 @@ paths:
* `email_deny` - Use the user's email address, but deny enrollment when the email address already exists.
* `username_link` - Link to a user with identical username. Can have security implications when a username is used with another source.
* `username_deny` - Use the user's username, but deny enrollment when the username already exists.
- in: query
name: verification_kp
schema:
type: string
format: uuid
tags:
- sources
security:
@ -37280,13 +37285,20 @@ components:
* `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` - Transient
binding_type:
$ref: '#/components/schemas/BindingTypeEnum'
verification_kp:
type: string
format: uuid
nullable: true
title: Verification Certificate
description: When selected, incoming assertion's Signatures will be validated
against this certificate. To allow unsigned Requests, leave on default.
signing_kp:
type: string
format: uuid
nullable: true
title: Signing Keypair
description: Keypair which is used to sign outgoing requests. Leave empty
to disable signing.
description: Keypair used to sign outgoing Responses going to the Identity
Provider.
digest_algorithm:
$ref: '#/components/schemas/DigestAlgorithmEnum'
signature_algorithm:
@ -39608,13 +39620,20 @@ components:
* `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` - Transient
binding_type:
$ref: '#/components/schemas/BindingTypeEnum'
verification_kp:
type: string
format: uuid
nullable: true
title: Verification Certificate
description: When selected, incoming assertion's Signatures will be validated
against this certificate. To allow unsigned Requests, leave on default.
signing_kp:
type: string
format: uuid
nullable: true
title: Signing Keypair
description: Keypair which is used to sign outgoing requests. Leave empty
to disable signing.
description: Keypair used to sign outgoing Responses going to the Identity
Provider.
digest_algorithm:
$ref: '#/components/schemas/DigestAlgorithmEnum'
signature_algorithm:
@ -39715,13 +39734,20 @@ components:
* `urn:oasis:names:tc:SAML:2.0:nameid-format:transient` - Transient
binding_type:
$ref: '#/components/schemas/BindingTypeEnum'
verification_kp:
type: string
format: uuid
nullable: true
title: Verification Certificate
description: When selected, incoming assertion's Signatures will be validated
against this certificate. To allow unsigned Requests, leave on default.
signing_kp:
type: string
format: uuid
nullable: true
title: Signing Keypair
description: Keypair which is used to sign outgoing requests. Leave empty
to disable signing.
description: Keypair used to sign outgoing Responses going to the Identity
Provider.
digest_algorithm:
$ref: '#/components/schemas/DigestAlgorithmEnum'
signature_algorithm:

View file

@ -304,6 +304,42 @@ export class SAMLSourceForm extends ModelForm<SAMLSource, string> {
${t`Keypair which is used to sign outgoing requests. Leave empty to disable signing.`}
</p>
</ak-form-element-horizontal>
<ak-form-element-horizontal
label=${t`Verification Certificate`}
name="verificationKp"
>
<ak-search-select
.fetchObjects=${async (
query?: string,
): Promise<CertificateKeyPair[]> => {
const args: CryptoCertificatekeypairsListRequest = {
ordering: "name",
includeDetails: false,
};
if (query !== undefined) {
args.search = query;
}
const certificates = await new CryptoApi(
DEFAULT_CONFIG,
).cryptoCertificatekeypairsList(args);
return certificates.results;
}}
.renderElement=${(item: CertificateKeyPair): string => {
return item.name;
}}
.value=${(item: CertificateKeyPair | undefined): string | undefined => {
return item?.pk;
}}
.selected=${(item: CertificateKeyPair): boolean => {
return item.pk === this.instance?.verificationKp;
}}
?blankable=${true}
>
</ak-search-select>
<p class="pf-c-form__helper-text">
${t`When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default.`}
</p>
</ak-form-element-horizontal>
</div>
</ak-form-group>
<ak-form-group>

View file

@ -7766,6 +7766,7 @@ msgid "Verification"
msgstr "Überprüfung"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "Zertifikat zur Überprüfung"
@ -7991,6 +7992,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "Wenn diese Option ausgewählt ist, wird ein Passwortfeld auf derselben Seite statt auf einer separaten Seite angezeigt. Dadurch werden Angriffe auf die Aufzählung von Benutzernamen verhindert."
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "Wenn diese Option ausgewählt ist, werden die Signaturen eingehender Behauptungen anhand dieses Zertifikats validiert. Um nicht signierte Anfragen zuzulassen, belassen Sie die Standardeinstellung."

View file

@ -7930,6 +7930,7 @@ msgid "Verification"
msgstr "Verification"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "Verification Certificate"
@ -8164,6 +8165,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "When selected, a password field is shown on the same page instead of a separate page. This prevents username enumeration attacks."
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."

View file

@ -7742,6 +7742,7 @@ msgid "Verification"
msgstr "Verificación"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "Certificado de verificación"
@ -7967,6 +7968,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "Cuando se selecciona, se muestra un campo de contraseña en la misma página en lugar de en una página separada. Esto evita ataques de enumeración de nombres de usuario."
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "Cuando se selecciona, las firmas de la aserción entrante se validarán con este certificado. Para permitir solicitudes sin firmar, déjelo en el valor predeterminado."

View file

@ -7733,6 +7733,7 @@ msgid "Verification"
msgstr "Vérification"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "Certificat de validation"
@ -7958,6 +7959,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "Si activée, un champ de mot de passe est affiché sur la même page au lieu d'une page séparée. Cela permet d'éviter les attaques par énumération de noms d'utilisateur."
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "Si activée, les signatures des assertions entrantes seront validées par rapport à ce certificat. Pour autoriser les requêtes non signées, laissez la valeur par défaut."

View file

@ -7752,6 +7752,7 @@ msgid "Verification"
msgstr "Weryfikacja"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "Certyfikat weryfikacji"
@ -7979,6 +7980,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "Po wybraniu pole hasła jest wyświetlane na tej samej stronie zamiast na osobnej stronie. Zapobiega to atakom polegającym na wyliczaniu nazw użytkowników."
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "Po wybraniu, przychodzące podpisy asercji będą sprawdzane względem tego certyfikatu. Aby zezwolić na niepodpisane żądania, pozostaw domyślnie."

View file

@ -7888,6 +7888,7 @@ msgid "Verification"
msgstr ""
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr ""
@ -8116,6 +8117,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr ""
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr ""

View file

@ -7742,6 +7742,7 @@ msgid "Verification"
msgstr "Doğrulama"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "Doğrulama Sertifikası"
@ -7967,6 +7968,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "Seçildiğinde, ayrı bir sayfa yerine aynı sayfada bir parola alanı gösterilir. Bu, kullanıcı adı numaralandırma saldırılarını engeller."
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "Seçildiğinde, gelen onaylama öğesinin İmzaları bu sertifikaya göre doğrulanır. İmzasız İsteklere izin vermek için varsayılan olarak bırakın."

File diff suppressed because it is too large Load diff

View file

@ -7750,6 +7750,7 @@ msgid "Verification"
msgstr "验证"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "验证证书"
@ -7977,6 +7978,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "选中后,传入声明的签名将根据此证书进行验证。要允许未签名的请求,请保留默认值。"

View file

@ -7750,6 +7750,7 @@ msgid "Verification"
msgstr "验证"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "Verification Certificate"
msgstr "验证证书"
@ -7977,6 +7978,7 @@ msgid "When selected, a password field is shown on the same page instead of a se
msgstr "选中后,密码字段将显示在同一页面上,而不是单独的页面上。这样可以防止用户名枚举攻击。"
#: src/admin/providers/saml/SAMLProviderForm.ts
#: src/admin/sources/saml/SAMLSourceForm.ts
msgid "When selected, incoming assertion's Signatures will be validated against this certificate. To allow unsigned Requests, leave on default."
msgstr "选中后,传入声明的签名将根据此证书进行验证。要允许未签名的请求,请保留默认值。"