providers/saml: fix ecdsa support (cherry-pick #9537) (#9544)

* providers/saml: fix ecdsa support (#9537)

* crypto: add option to select which alg to use to generate

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

* fix missing ecdsa options for XML signing

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

* bump xml libraries and remove disclaimer

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

* lock djangoframework

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

---------

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

* bump api client

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

---------

Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: Jens L <jens@goauthentik.io>
This commit is contained in:
gcp-cherry-pick-bot[bot]
2024-05-02 16:08:33 +02:00
committed by GitHub
parent 0f6ece5eb7
commit 2900f01976
20 changed files with 1193 additions and 1051 deletions

View File

@ -4,7 +4,7 @@ from django.utils.text import slugify
from authentik.brands.models import Brand from authentik.brands.models import Brand
from authentik.core.models import Group, User from authentik.core.models import Group, User
from authentik.crypto.builder import CertificateBuilder from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.flows.models import Flow, FlowDesignation from authentik.flows.models import Flow, FlowDesignation
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
@ -50,12 +50,10 @@ def create_test_brand(**kwargs) -> Brand:
return Brand.objects.create(domain=uid, default=True, **kwargs) return Brand.objects.create(domain=uid, default=True, **kwargs)
def create_test_cert(use_ec_private_key=False) -> CertificateKeyPair: def create_test_cert(alg=PrivateKeyAlg.RSA) -> CertificateKeyPair:
"""Generate a certificate for testing""" """Generate a certificate for testing"""
builder = CertificateBuilder( builder = CertificateBuilder(f"{generate_id()}.self-signed.goauthentik.io")
name=f"{generate_id()}.self-signed.goauthentik.io", builder.alg = alg
use_ec_private_key=use_ec_private_key,
)
builder.build( builder.build(
subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"], subject_alt_names=[f"{generate_id()}.self-signed.goauthentik.io"],
validity_days=360, validity_days=360,

View File

@ -14,7 +14,13 @@ from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema from drf_spectacular.utils import OpenApiParameter, OpenApiResponse, extend_schema
from rest_framework.decorators import action from rest_framework.decorators import action
from rest_framework.exceptions import ValidationError from rest_framework.exceptions import ValidationError
from rest_framework.fields import CharField, DateTimeField, IntegerField, SerializerMethodField from rest_framework.fields import (
CharField,
ChoiceField,
DateTimeField,
IntegerField,
SerializerMethodField,
)
from rest_framework.filters import OrderingFilter, SearchFilter from rest_framework.filters import OrderingFilter, SearchFilter
from rest_framework.request import Request from rest_framework.request import Request
from rest_framework.response import Response from rest_framework.response import Response
@ -26,7 +32,7 @@ from authentik.api.authorization import SecretKeyFilter
from authentik.core.api.used_by import UsedByMixin from authentik.core.api.used_by import UsedByMixin
from authentik.core.api.utils import PassiveSerializer from authentik.core.api.utils import PassiveSerializer
from authentik.crypto.apps import MANAGED_KEY from authentik.crypto.apps import MANAGED_KEY
from authentik.crypto.builder import CertificateBuilder from authentik.crypto.builder import CertificateBuilder, PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.events.models import Event, EventAction from authentik.events.models import Event, EventAction
from authentik.rbac.decorators import permission_required from authentik.rbac.decorators import permission_required
@ -178,6 +184,7 @@ class CertificateGenerationSerializer(PassiveSerializer):
common_name = CharField() common_name = CharField()
subject_alt_name = CharField(required=False, allow_blank=True, label=_("Subject-alt name")) subject_alt_name = CharField(required=False, allow_blank=True, label=_("Subject-alt name"))
validity_days = IntegerField(initial=365) validity_days = IntegerField(initial=365)
alg = ChoiceField(default=PrivateKeyAlg.RSA, choices=PrivateKeyAlg.choices)
class CertificateKeyPairFilter(FilterSet): class CertificateKeyPairFilter(FilterSet):
@ -240,6 +247,7 @@ class CertificateKeyPairViewSet(UsedByMixin, ModelViewSet):
raw_san = data.validated_data.get("subject_alt_name", "") raw_san = data.validated_data.get("subject_alt_name", "")
sans = raw_san.split(",") if raw_san != "" else [] sans = raw_san.split(",") if raw_san != "" else []
builder = CertificateBuilder(data.validated_data["common_name"]) builder = CertificateBuilder(data.validated_data["common_name"])
builder.alg = data.validated_data["alg"]
builder.build( builder.build(
subject_alt_names=sans, subject_alt_names=sans,
validity_days=int(data.validated_data["validity_days"]), validity_days=int(data.validated_data["validity_days"]),

View File

@ -9,20 +9,28 @@ from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import ec, rsa from cryptography.hazmat.primitives.asymmetric import ec, rsa
from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes
from cryptography.x509.oid import NameOID from cryptography.x509.oid import NameOID
from django.db import models
from django.utils.translation import gettext_lazy as _
from authentik import __version__ from authentik import __version__
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
class PrivateKeyAlg(models.TextChoices):
"""Algorithm to create private key with"""
RSA = "rsa", _("rsa")
ECDSA = "ecdsa", _("ecdsa")
class CertificateBuilder: class CertificateBuilder:
"""Build self-signed certificates""" """Build self-signed certificates"""
common_name: str common_name: str
alg: PrivateKeyAlg
_use_ec_private_key: bool def __init__(self, name: str):
self.alg = PrivateKeyAlg.RSA
def __init__(self, name: str, use_ec_private_key=False):
self._use_ec_private_key = use_ec_private_key
self.__public_key = None self.__public_key = None
self.__private_key = None self.__private_key = None
self.__builder = None self.__builder = None
@ -42,11 +50,13 @@ class CertificateBuilder:
def generate_private_key(self) -> PrivateKeyTypes: def generate_private_key(self) -> PrivateKeyTypes:
"""Generate private key""" """Generate private key"""
if self._use_ec_private_key: if self.alg == PrivateKeyAlg.ECDSA:
return ec.generate_private_key(curve=ec.SECP256R1()) return ec.generate_private_key(curve=ec.SECP256R1())
return rsa.generate_private_key( if self.alg == PrivateKeyAlg.RSA:
public_exponent=65537, key_size=4096, backend=default_backend() return rsa.generate_private_key(
) public_exponent=65537, key_size=4096, backend=default_backend()
)
raise ValueError(f"Invalid alg: {self.alg}")
def build( def build(
self, self,

View File

@ -10,6 +10,7 @@ from jwt import PyJWKSet
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.crypto.builder import PrivateKeyAlg
from authentik.crypto.models import CertificateKeyPair from authentik.crypto.models import CertificateKeyPair
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.providers.oauth2.models import OAuth2Provider from authentik.providers.oauth2.models import OAuth2Provider
@ -82,7 +83,7 @@ class TestJWKS(OAuthTestCase):
client_id="test", client_id="test",
authorization_flow=create_test_flow(), authorization_flow=create_test_flow(),
redirect_uris="http://local.invalid", redirect_uris="http://local.invalid",
signing_key=create_test_cert(use_ec_private_key=True), signing_key=create_test_cert(PrivateKeyAlg.ECDSA),
) )
app = Application.objects.create(name="test", slug="test", provider=provider) app = Application.objects.create(name="test", slug="test", provider=provider)
response = self.client.get( response = self.client.get(

View File

@ -0,0 +1,44 @@
# Generated by Django 5.0.4 on 2024-05-01 15:32
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_providers_saml", "0013_samlprovider_default_relay_state"),
]
operations = [
migrations.AlterField(
model_name="samlprovider",
name="digest_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#sha1", "SHA1"),
("http://www.w3.org/2001/04/xmlenc#sha256", "SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#sha384", "SHA384"),
("http://www.w3.org/2001/04/xmlenc#sha512", "SHA512"),
],
default="http://www.w3.org/2001/04/xmlenc#sha256",
),
),
migrations.AlterField(
model_name="samlprovider",
name="signature_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#rsa-sha1", "RSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "RSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "RSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "RSA-SHA512"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1", "ECDSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", "ECDSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", "ECDSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", "ECDSA-SHA512"),
("http://www.w3.org/2000/09/xmldsig#dsa-sha1", "DSA-SHA1"),
],
default="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
),
),
]

View File

@ -11,6 +11,10 @@ from authentik.crypto.models import CertificateKeyPair
from authentik.lib.utils.time import timedelta_string_validator from authentik.lib.utils.time import timedelta_string_validator
from authentik.sources.saml.processors.constants import ( from authentik.sources.saml.processors.constants import (
DSA_SHA1, DSA_SHA1,
ECDSA_SHA1,
ECDSA_SHA256,
ECDSA_SHA384,
ECDSA_SHA512,
RSA_SHA1, RSA_SHA1,
RSA_SHA256, RSA_SHA256,
RSA_SHA384, RSA_SHA384,
@ -92,8 +96,7 @@ class SAMLProvider(Provider):
), ),
) )
digest_algorithm = models.CharField( digest_algorithm = models.TextField(
max_length=50,
choices=( choices=(
(SHA1, _("SHA1")), (SHA1, _("SHA1")),
(SHA256, _("SHA256")), (SHA256, _("SHA256")),
@ -102,13 +105,16 @@ class SAMLProvider(Provider):
), ),
default=SHA256, default=SHA256,
) )
signature_algorithm = models.CharField( signature_algorithm = models.TextField(
max_length=50,
choices=( choices=(
(RSA_SHA1, _("RSA-SHA1")), (RSA_SHA1, _("RSA-SHA1")),
(RSA_SHA256, _("RSA-SHA256")), (RSA_SHA256, _("RSA-SHA256")),
(RSA_SHA384, _("RSA-SHA384")), (RSA_SHA384, _("RSA-SHA384")),
(RSA_SHA512, _("RSA-SHA512")), (RSA_SHA512, _("RSA-SHA512")),
(ECDSA_SHA1, _("ECDSA-SHA1")),
(ECDSA_SHA256, _("ECDSA-SHA256")),
(ECDSA_SHA384, _("ECDSA-SHA384")),
(ECDSA_SHA512, _("ECDSA-SHA512")),
(DSA_SHA1, _("DSA-SHA1")), (DSA_SHA1, _("DSA-SHA1")),
), ),
default=RSA_SHA256, default=RSA_SHA256,

View File

@ -7,13 +7,14 @@ from lxml import etree # nosec
from authentik.core.models import Application from authentik.core.models import Application
from authentik.core.tests.utils import create_test_cert, create_test_flow from authentik.core.tests.utils import create_test_cert, create_test_flow
from authentik.crypto.builder import PrivateKeyAlg
from authentik.lib.generators import generate_id from authentik.lib.generators import generate_id
from authentik.lib.tests.utils import load_fixture from authentik.lib.tests.utils import load_fixture
from authentik.lib.xml import lxml_from_string from authentik.lib.xml import lxml_from_string
from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider from authentik.providers.saml.models import SAMLBindings, SAMLPropertyMapping, SAMLProvider
from authentik.providers.saml.processors.metadata import MetadataProcessor from authentik.providers.saml.processors.metadata import MetadataProcessor
from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser from authentik.providers.saml.processors.metadata_parser import ServiceProviderMetadataParser
from authentik.sources.saml.processors.constants import NS_MAP, NS_SAML_METADATA from authentik.sources.saml.processors.constants import ECDSA_SHA256, NS_MAP, NS_SAML_METADATA
class TestServiceProviderMetadataParser(TestCase): class TestServiceProviderMetadataParser(TestCase):
@ -107,12 +108,41 @@ class TestServiceProviderMetadataParser(TestCase):
load_fixture("fixtures/cert.xml").replace("/apps/user_saml", "") load_fixture("fixtures/cert.xml").replace("/apps/user_saml", "")
) )
def test_signature(self): def test_signature_rsa(self):
"""Test signature validation""" """Test signature validation (RSA)"""
provider = SAMLProvider.objects.create( provider = SAMLProvider.objects.create(
name=generate_id(), name=generate_id(),
authorization_flow=self.flow, authorization_flow=self.flow,
signing_kp=create_test_cert(), signing_kp=create_test_cert(PrivateKeyAlg.RSA),
)
Application.objects.create(
name=generate_id(),
slug=generate_id(),
provider=provider,
)
request = self.factory.get("/")
metadata = MetadataProcessor(provider, request).build_entity_descriptor()
root = fromstring(metadata.encode())
xmlsec.tree.add_ids(root, ["ID"])
signature_nodes = root.xpath("/md:EntityDescriptor/ds:Signature", namespaces=NS_MAP)
signature_node = signature_nodes[0]
ctx = xmlsec.SignatureContext()
key = xmlsec.Key.from_memory(
provider.signing_kp.certificate_data,
xmlsec.constants.KeyDataFormatCertPem,
None,
)
ctx.key = key
ctx.verify(signature_node)
def test_signature_ecdsa(self):
"""Test signature validation (ECDSA)"""
provider = SAMLProvider.objects.create(
name=generate_id(),
authorization_flow=self.flow,
signing_kp=create_test_cert(PrivateKeyAlg.ECDSA),
signature_algorithm=ECDSA_SHA256,
) )
Application.objects.create( Application.objects.create(
name=generate_id(), name=generate_id(),

View File

@ -0,0 +1,44 @@
# Generated by Django 5.0.4 on 2024-05-01 15:44
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_sources_saml", "0013_samlsource_verification_kp_and_more"),
]
operations = [
migrations.AlterField(
model_name="samlsource",
name="digest_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#sha1", "SHA1"),
("http://www.w3.org/2001/04/xmlenc#sha256", "SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#sha384", "SHA384"),
("http://www.w3.org/2001/04/xmlenc#sha512", "SHA512"),
],
default="http://www.w3.org/2001/04/xmlenc#sha256",
),
),
migrations.AlterField(
model_name="samlsource",
name="signature_algorithm",
field=models.TextField(
choices=[
("http://www.w3.org/2000/09/xmldsig#rsa-sha1", "RSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "RSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "RSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "RSA-SHA512"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1", "ECDSA-SHA1"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256", "ECDSA-SHA256"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384", "ECDSA-SHA384"),
("http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512", "ECDSA-SHA512"),
("http://www.w3.org/2000/09/xmldsig#dsa-sha1", "DSA-SHA1"),
],
default="http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
),
),
]

View File

@ -15,6 +15,10 @@ from authentik.flows.models import Flow
from authentik.lib.utils.time import timedelta_string_validator from authentik.lib.utils.time import timedelta_string_validator
from authentik.sources.saml.processors.constants import ( from authentik.sources.saml.processors.constants import (
DSA_SHA1, DSA_SHA1,
ECDSA_SHA1,
ECDSA_SHA256,
ECDSA_SHA384,
ECDSA_SHA512,
RSA_SHA1, RSA_SHA1,
RSA_SHA256, RSA_SHA256,
RSA_SHA384, RSA_SHA384,
@ -143,8 +147,7 @@ class SAMLSource(Source):
verbose_name=_("Signing Keypair"), verbose_name=_("Signing Keypair"),
) )
digest_algorithm = models.CharField( digest_algorithm = models.TextField(
max_length=50,
choices=( choices=(
(SHA1, _("SHA1")), (SHA1, _("SHA1")),
(SHA256, _("SHA256")), (SHA256, _("SHA256")),
@ -153,13 +156,16 @@ class SAMLSource(Source):
), ),
default=SHA256, default=SHA256,
) )
signature_algorithm = models.CharField( signature_algorithm = models.TextField(
max_length=50,
choices=( choices=(
(RSA_SHA1, _("RSA-SHA1")), (RSA_SHA1, _("RSA-SHA1")),
(RSA_SHA256, _("RSA-SHA256")), (RSA_SHA256, _("RSA-SHA256")),
(RSA_SHA384, _("RSA-SHA384")), (RSA_SHA384, _("RSA-SHA384")),
(RSA_SHA512, _("RSA-SHA512")), (RSA_SHA512, _("RSA-SHA512")),
(ECDSA_SHA1, _("ECDSA-SHA1")),
(ECDSA_SHA256, _("ECDSA-SHA256")),
(ECDSA_SHA384, _("ECDSA-SHA384")),
(ECDSA_SHA512, _("ECDSA-SHA512")),
(DSA_SHA1, _("DSA-SHA1")), (DSA_SHA1, _("DSA-SHA1")),
), ),
default=RSA_SHA256, default=RSA_SHA256,

View File

@ -26,9 +26,16 @@ SAML_BINDING_REDIRECT = "urn:oasis:names:tc:SAML:2.0:bindings:HTTP-Redirect"
DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1" DSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1" RSA_SHA1 = "http://www.w3.org/2000/09/xmldsig#rsa-sha1"
# https://datatracker.ietf.org/doc/html/rfc4051#section-2.3.2
RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256" RSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256"
RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384" RSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384"
RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512" RSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512"
# https://datatracker.ietf.org/doc/html/rfc4051#section-2.3.6
ECDSA_SHA1 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1"
ECDSA_SHA224 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224"
ECDSA_SHA256 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256"
ECDSA_SHA384 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384"
ECDSA_SHA512 = "http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512"
SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1" SHA1 = "http://www.w3.org/2000/09/xmldsig#sha1"
SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256" SHA256 = "http://www.w3.org/2001/04/xmlenc#sha256"
@ -41,6 +48,11 @@ SIGN_ALGORITHM_TRANSFORM_MAP = {
RSA_SHA256: xmlsec.constants.TransformRsaSha256, RSA_SHA256: xmlsec.constants.TransformRsaSha256,
RSA_SHA384: xmlsec.constants.TransformRsaSha384, RSA_SHA384: xmlsec.constants.TransformRsaSha384,
RSA_SHA512: xmlsec.constants.TransformRsaSha512, RSA_SHA512: xmlsec.constants.TransformRsaSha512,
ECDSA_SHA1: xmlsec.constants.TransformEcdsaSha1,
ECDSA_SHA224: xmlsec.constants.TransformEcdsaSha224,
ECDSA_SHA256: xmlsec.constants.TransformEcdsaSha256,
ECDSA_SHA384: xmlsec.constants.TransformEcdsaSha384,
ECDSA_SHA512: xmlsec.constants.TransformEcdsaSha512,
} }
DIGEST_ALGORITHM_TRANSLATION_MAP = { DIGEST_ALGORITHM_TRANSLATION_MAP = {

View File

@ -0,0 +1,23 @@
# Generated by Django 5.0.4 on 2024-05-01 15:32
import authentik.lib.utils.time
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("authentik_tenants", "0002_tenant_default_token_duration_and_more"),
]
operations = [
migrations.AlterField(
model_name="tenant",
name="default_token_duration",
field=models.TextField(
default="days=1",
help_text="Default token duration",
validators=[authentik.lib.utils.time.timedelta_string_validator],
),
),
]

View File

@ -4131,6 +4131,10 @@
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
"http://www.w3.org/2000/09/xmldsig#dsa-sha1" "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
], ],
"title": "Signature algorithm" "title": "Signature algorithm"
@ -4935,6 +4939,10 @@
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha256", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha384", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#rsa-sha512", "http://www.w3.org/2001/04/xmldsig-more#rsa-sha512",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384",
"http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512",
"http://www.w3.org/2000/09/xmldsig#dsa-sha1" "http://www.w3.org/2000/09/xmldsig#dsa-sha1"
], ],
"title": "Signature algorithm" "title": "Signature algorithm"

1914
poetry.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -89,6 +89,7 @@ channels = { version = "*", extras = ["daphne"] }
channels-redis = "*" channels-redis = "*"
codespell = "*" codespell = "*"
colorama = "*" colorama = "*"
cryptography = "*"
dacite = "*" dacite = "*"
deepmerge = "*" deepmerge = "*"
defusedxml = "*" defusedxml = "*"
@ -101,7 +102,7 @@ django-redis = "*"
django-storages = { extras = ["s3"], version = "*" } django-storages = { extras = ["s3"], version = "*" }
# See https://github.com/django-tenants/django-tenants/pull/997 # See https://github.com/django-tenants/django-tenants/pull/997
django-tenants = { git = "https://github.com/rissson/django-tenants.git", branch="authentik-fixes" } django-tenants = { git = "https://github.com/rissson/django-tenants.git", branch="authentik-fixes" }
djangorestframework = "*" djangorestframework = "3.14.0"
djangorestframework-guardian = "*" djangorestframework-guardian = "*"
docker = "*" docker = "*"
drf-spectacular = "*" drf-spectacular = "*"
@ -115,17 +116,11 @@ gunicorn = "*"
jsonpatch = "*" jsonpatch = "*"
kubernetes = "*" kubernetes = "*"
ldap3 = "*" ldap3 = "*"
lxml = [ lxml = "*"
# 5.0.0 works with libxml2 2.11.x, which is standard on brew
{ version = "5.0.0", platform = "darwin" },
# 4.9.x works with previous libxml2 versions, which is what we get on linux
{ version = "4.9.4", platform = "linux" },
]
opencontainers = { extras = ["reggie"], version = "*" } opencontainers = { extras = ["reggie"], version = "*" }
packaging = "*" packaging = "*"
paramiko = "*" paramiko = "*"
psycopg = { extras = ["c"], version = "*" } psycopg = { extras = ["c"], version = "*" }
pycryptodome = "*"
pydantic = "*" pydantic = "*"
pydantic-scim = "*" pydantic-scim = "*"
pyjwt = "*" pyjwt = "*"

View File

@ -17051,6 +17051,10 @@ paths:
enum: enum:
- http://www.w3.org/2000/09/xmldsig#dsa-sha1 - http://www.w3.org/2000/09/xmldsig#dsa-sha1
- http://www.w3.org/2000/09/xmldsig#rsa-sha1 - http://www.w3.org/2000/09/xmldsig#rsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
@ -20910,6 +20914,10 @@ paths:
enum: enum:
- http://www.w3.org/2000/09/xmldsig#dsa-sha1 - http://www.w3.org/2000/09/xmldsig#dsa-sha1
- http://www.w3.org/2000/09/xmldsig#rsa-sha1 - http://www.w3.org/2000/09/xmldsig#rsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
@ -30450,6 +30458,11 @@ components:
- pending_user - pending_user
- pending_user_avatar - pending_user_avatar
- type - type
AlgEnum:
enum:
- rsa
- ecdsa
type: string
App: App:
type: object type: object
description: Serialize Application info description: Serialize Application info
@ -32107,6 +32120,10 @@ components:
type: string type: string
validity_days: validity_days:
type: integer type: integer
alg:
allOf:
- $ref: '#/components/schemas/AlgEnum'
default: rsa
required: required:
- common_name - common_name
- validity_days - validity_days
@ -43658,6 +43675,10 @@ components:
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha256 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha384 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#rsa-sha512 - http://www.w3.org/2001/04/xmldsig-more#rsa-sha512
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384
- http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512
- http://www.w3.org/2000/09/xmldsig#dsa-sha1 - http://www.w3.org/2000/09/xmldsig#dsa-sha1
type: string type: string
Source: Source:

8
web/package-lock.json generated
View File

@ -17,7 +17,7 @@
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.5.5", "@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.2", "@fortawesome/fontawesome-free": "^6.5.2",
"@goauthentik/api": "^2024.2.3-1713441634", "@goauthentik/api": "^2024.4.1-1714655911",
"@lit-labs/task": "^3.1.0", "@lit-labs/task": "^3.1.0",
"@lit/context": "^1.1.1", "@lit/context": "^1.1.1",
"@lit/localize": "^0.12.1", "@lit/localize": "^0.12.1",
@ -2671,9 +2671,9 @@
} }
}, },
"node_modules/@goauthentik/api": { "node_modules/@goauthentik/api": {
"version": "2024.2.3-1713441634", "version": "2024.4.1-1714655911",
"resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.2.3-1713441634.tgz", "resolved": "https://registry.npmjs.org/@goauthentik/api/-/api-2024.4.1-1714655911.tgz",
"integrity": "sha512-mgwHVzmbjByIjeQW7yf52BL2bhpfFnWEp+NH3+uTf3po9D5a6ZF/q77PMsaoiPNCTotfh6XBuNwsCP6jZc1JTw==" "integrity": "sha512-x7ViXuDh928e7B4dbQlOJXCtFnWJGGmOQcGI4IG6eWafUcq9+jgDnFrd0qqkDGcipqjKiY52B4RSdRNRxRsucA=="
}, },
"node_modules/@hcaptcha/types": { "node_modules/@hcaptcha/types": {
"version": "1.0.3", "version": "1.0.3",

View File

@ -38,7 +38,7 @@
"@codemirror/theme-one-dark": "^6.1.2", "@codemirror/theme-one-dark": "^6.1.2",
"@formatjs/intl-listformat": "^7.5.5", "@formatjs/intl-listformat": "^7.5.5",
"@fortawesome/fontawesome-free": "^6.5.2", "@fortawesome/fontawesome-free": "^6.5.2",
"@goauthentik/api": "^2024.2.3-1713441634", "@goauthentik/api": "^2024.4.1-1714655911",
"@lit-labs/task": "^3.1.0", "@lit-labs/task": "^3.1.0",
"@lit/context": "^1.1.1", "@lit/context": "^1.1.1",
"@lit/localize": "^0.12.1", "@lit/localize": "^0.12.1",

View File

@ -29,5 +29,9 @@ export const signatureAlgorithmOptions = toOptions([
["RSA-SHA256", SignatureAlgorithmEnum._200104XmldsigMorersaSha256, true], ["RSA-SHA256", SignatureAlgorithmEnum._200104XmldsigMorersaSha256, true],
["RSA-SHA384", SignatureAlgorithmEnum._200104XmldsigMorersaSha384], ["RSA-SHA384", SignatureAlgorithmEnum._200104XmldsigMorersaSha384],
["RSA-SHA512", SignatureAlgorithmEnum._200104XmldsigMorersaSha512], ["RSA-SHA512", SignatureAlgorithmEnum._200104XmldsigMorersaSha512],
["ECDSA-SHA1", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha1],
["ECDSA-SHA256", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha256],
["ECDSA-SHA384", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha384],
["ECDSA-SHA512", SignatureAlgorithmEnum._200104XmldsigMoreecdsaSha512],
["DSA-SHA1", SignatureAlgorithmEnum._200009XmldsigdsaSha1], ["DSA-SHA1", SignatureAlgorithmEnum._200009XmldsigdsaSha1],
]); ]);

View File

@ -6,7 +6,12 @@ import { msg } from "@lit/localize";
import { TemplateResult, html } from "lit"; import { TemplateResult, html } from "lit";
import { customElement } from "lit/decorators.js"; import { customElement } from "lit/decorators.js";
import { CertificateGenerationRequest, CertificateKeyPair, CryptoApi } from "@goauthentik/api"; import {
AlgEnum,
CertificateGenerationRequest,
CertificateKeyPair,
CryptoApi,
} from "@goauthentik/api";
@customElement("ak-crypto-certificate-generate-form") @customElement("ak-crypto-certificate-generate-form")
export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> { export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
@ -40,6 +45,29 @@ export class CertificateKeyPairForm extends Form<CertificateGenerationRequest> {
?required=${true} ?required=${true}
> >
<input class="pf-c-form-control" type="number" value="365" /> <input class="pf-c-form-control" type="number" value="365" />
</ak-form-element-horizontal>`; </ak-form-element-horizontal>
<ak-form-element-horizontal
label=${msg("Private key Algorithm")}
?required=${true}
name="alg"
>
<ak-radio
.options=${[
{
label: msg("RSA"),
value: AlgEnum.Rsa,
default: true,
},
{
label: msg("ECDSA"),
value: AlgEnum.Ecdsa,
},
]}
>
</ak-radio>
<p class="pf-c-form__helper-text">
${msg("Algorithm used to generate the private key.")}
</p>
</ak-form-element-horizontal> `;
} }
} }

View File

@ -26,10 +26,6 @@ If you use locally installed databases, the PostgreSQL credentials given to auth
Depending on your platform, some native dependencies might be required. On macOS, run `brew install libxmlsec1 libpq`, and for the CLI tools `brew install postgresql redis node@20` Depending on your platform, some native dependencies might be required. On macOS, run `brew install libxmlsec1 libpq`, and for the CLI tools `brew install postgresql redis node@20`
::: :::
:::info
As long as [this issue](https://github.com/xmlsec/python-xmlsec/issues/252) about `libxmlsec-1.3.0` is open, a workaround is required to install a compatible version of `libxmlsec1` with brew, see [this comment](https://github.com/xmlsec/python-xmlsec/issues/254#issuecomment-1612005910).
:::
1. Create an isolated Python environment. To create the environment and install dependencies, run the following commands in the same directory as your local authentik git repository: 1. Create an isolated Python environment. To create the environment and install dependencies, run the following commands in the same directory as your local authentik git repository:
```shell ```shell