From 7e7fc75e7739c988dd64f92785baae54a975269e Mon Sep 17 00:00:00 2001 From: Marc 'risson' Schmitt Date: Fri, 28 Feb 2025 16:50:14 +0100 Subject: [PATCH] providers/oauth2: properly support P-384 and P-521 keys (#13317) Signed-off-by: Marc 'risson' Schmitt --- authentik/providers/oauth2/models.py | 29 +++++++++++++++++++----- authentik/providers/oauth2/views/jwks.py | 5 +--- 2 files changed, 24 insertions(+), 10 deletions(-) diff --git a/authentik/providers/oauth2/models.py b/authentik/providers/oauth2/models.py index 4c1d1af32fc1..25de2ae5f8d1 100644 --- a/authentik/providers/oauth2/models.py +++ b/authentik/providers/oauth2/models.py @@ -9,7 +9,12 @@ from typing import Any from urllib.parse import urlparse, urlunparse -from cryptography.hazmat.primitives.asymmetric.ec import EllipticCurvePrivateKey +from cryptography.hazmat.primitives.asymmetric.ec import ( + SECP256R1, + SECP384R1, + SECP521R1, + EllipticCurvePrivateKey, +) from cryptography.hazmat.primitives.asymmetric.rsa import RSAPrivateKey from cryptography.hazmat.primitives.asymmetric.types import PrivateKeyTypes from dacite import Config @@ -114,6 +119,22 @@ class JWTAlgorithms(models.TextChoices): HS256 = "HS256", _("HS256 (Symmetric Encryption)") RS256 = "RS256", _("RS256 (Asymmetric Encryption)") ES256 = "ES256", _("ES256 (Asymmetric Encryption)") + ES384 = "ES384", _("ES384 (Asymmetric Encryption)") + ES512 = "ES512", _("ES512 (Asymmetric Encryption)") + + @classmethod + def from_private_key(cls, private_key: PrivateKeyTypes | None) -> str: + if isinstance(private_key, RSAPrivateKey): + return cls.RS256 + if isinstance(private_key, EllipticCurvePrivateKey): + curve = private_key.curve + if isinstance(curve, SECP256R1): + return cls.ES256 + if isinstance(curve, SECP384R1): + return cls.ES384 + if isinstance(curve, SECP521R1): + return cls.ES512 + raise ValueError(f"Invalid private key type: {type(private_key)}") class ScopeMapping(PropertyMapping): @@ -263,11 +284,7 @@ def jwt_key(self) -> tuple[str | PrivateKeyTypes, str]: return self.client_secret, JWTAlgorithms.HS256 key: CertificateKeyPair = self.signing_key private_key = key.private_key - if isinstance(private_key, RSAPrivateKey): - return private_key, JWTAlgorithms.RS256 - if isinstance(private_key, EllipticCurvePrivateKey): - return private_key, JWTAlgorithms.ES256 - raise ValueError(f"Invalid private key type: {type(private_key)}") + return private_key, JWTAlgorithms.from_private_key(private_key) def get_issuer(self, request: HttpRequest) -> str | None: """Get issuer, based on request""" diff --git a/authentik/providers/oauth2/views/jwks.py b/authentik/providers/oauth2/views/jwks.py index 91a13b8df851..f52fc2c4a77a 100644 --- a/authentik/providers/oauth2/views/jwks.py +++ b/authentik/providers/oauth2/views/jwks.py @@ -75,10 +75,7 @@ def get_jwk_for_key(key: CertificateKeyPair, use: str) -> dict | None: key_data = {} if use == "sig": - if isinstance(private_key, RSAPrivateKey): - key_data["alg"] = JWTAlgorithms.RS256 - elif isinstance(private_key, EllipticCurvePrivateKey): - key_data["alg"] = JWTAlgorithms.ES256 + key_data["alg"] = JWTAlgorithms.from_private_key(private_key) elif use == "enc": key_data["alg"] = "RSA-OAEP-256" key_data["enc"] = "A256CBC-HS512"