core: bump webauthn from 1.11.1 to 2.0.0 (#8134)

* core: bump webauthn from 1.11.1 to 2.0.0

Bumps [webauthn](https://github.com/duo-labs/py_webauthn) from 1.11.1 to 2.0.0.
- [Release notes](https://github.com/duo-labs/py_webauthn/releases)
- [Changelog](https://github.com/duo-labs/py_webauthn/blob/master/CHANGELOG.md)
- [Commits](https://github.com/duo-labs/py_webauthn/compare/v1.11.1...v2.0.0)

---
updated-dependencies:
- dependency-name: webauthn
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>

* fix?

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

* actually fix

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

---------

Signed-off-by: dependabot[bot] <support@github.com>
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
dependabot[bot] 2024-01-12 17:19:12 +01:00 committed by GitHub
parent be66ee52cd
commit f77c2e8254
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 22 additions and 32 deletions

View File

@ -1,4 +1,5 @@
"""Validation stage challenge checking""" """Validation stage challenge checking"""
from json import loads
from typing import Optional from typing import Optional
from urllib.parse import urlencode from urllib.parse import urlencode
@ -10,11 +11,12 @@ from django.utils.translation import gettext_lazy as _
from rest_framework.fields import CharField from rest_framework.fields import CharField
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from structlog.stdlib import get_logger from structlog.stdlib import get_logger
from webauthn import options_to_json
from webauthn.authentication.generate_authentication_options import generate_authentication_options from webauthn.authentication.generate_authentication_options import generate_authentication_options
from webauthn.authentication.verify_authentication_response import verify_authentication_response from webauthn.authentication.verify_authentication_response import verify_authentication_response
from webauthn.helpers.base64url_to_bytes import base64url_to_bytes from webauthn.helpers.base64url_to_bytes import base64url_to_bytes
from webauthn.helpers.exceptions import InvalidAuthenticationResponse from webauthn.helpers.exceptions import InvalidAuthenticationResponse
from webauthn.helpers.structs import AuthenticationCredential from webauthn.helpers.structs import UserVerificationRequirement
from authentik.core.api.utils import JSONDictField, PassiveSerializer from authentik.core.api.utils import JSONDictField, PassiveSerializer
from authentik.core.models import Application, User from authentik.core.models import Application, User
@ -66,12 +68,7 @@ def get_webauthn_challenge_without_user(
) )
request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = authentication_options.challenge request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = authentication_options.challenge
return authentication_options.model_dump( return loads(options_to_json(authentication_options))
mode="json",
by_alias=True,
exclude_unset=False,
exclude_none=True,
)
def get_webauthn_challenge( def get_webauthn_challenge(
@ -91,17 +88,12 @@ def get_webauthn_challenge(
authentication_options = generate_authentication_options( authentication_options = generate_authentication_options(
rp_id=get_rp_id(request), rp_id=get_rp_id(request),
allow_credentials=allowed_credentials, allow_credentials=allowed_credentials,
user_verification=stage.webauthn_user_verification, user_verification=UserVerificationRequirement(stage.webauthn_user_verification),
) )
request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = authentication_options.challenge request.session[SESSION_KEY_WEBAUTHN_CHALLENGE] = authentication_options.challenge
return authentication_options.model_dump( return loads(options_to_json(authentication_options))
mode="json",
by_alias=True,
exclude_unset=False,
exclude_none=True,
)
def select_challenge(request: HttpRequest, device: Device): def select_challenge(request: HttpRequest, device: Device):
@ -152,7 +144,7 @@ def validate_challenge_webauthn(data: dict, stage_view: StageView, user: User) -
try: try:
authentication_verification = verify_authentication_response( authentication_verification = verify_authentication_response(
credential=AuthenticationCredential.model_validate(data), credential=data,
expected_challenge=challenge, expected_challenge=challenge,
expected_rp_id=get_rp_id(request), expected_rp_id=get_rp_id(request),
expected_origin=get_origin(request), expected_origin=get_origin(request),

View File

@ -1,14 +1,18 @@
"""WebAuthn stage""" """WebAuthn stage"""
from json import loads
from django.http import HttpRequest, HttpResponse from django.http import HttpRequest, HttpResponse
from django.http.request import QueryDict from django.http.request import QueryDict
from rest_framework.fields import CharField from rest_framework.fields import CharField
from rest_framework.serializers import ValidationError from rest_framework.serializers import ValidationError
from webauthn import options_to_json
from webauthn.helpers.bytes_to_base64url import bytes_to_base64url from webauthn.helpers.bytes_to_base64url import bytes_to_base64url
from webauthn.helpers.exceptions import InvalidRegistrationResponse from webauthn.helpers.exceptions import InvalidRegistrationResponse
from webauthn.helpers.structs import ( from webauthn.helpers.structs import (
AuthenticatorSelectionCriteria, AuthenticatorSelectionCriteria,
PublicKeyCredentialCreationOptions, PublicKeyCredentialCreationOptions,
RegistrationCredential, ResidentKeyRequirement,
UserVerificationRequirement,
) )
from webauthn.registration.generate_registration_options import generate_registration_options from webauthn.registration.generate_registration_options import generate_registration_options
from webauthn.registration.verify_registration_response import ( from webauthn.registration.verify_registration_response import (
@ -53,7 +57,7 @@ class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse):
try: try:
registration: VerifiedRegistration = verify_registration_response( registration: VerifiedRegistration = verify_registration_response(
credential=RegistrationCredential.model_validate(response), credential=response,
expected_challenge=challenge, expected_challenge=challenge,
expected_rp_id=get_rp_id(self.request), expected_rp_id=get_rp_id(self.request),
expected_origin=get_origin(self.request), expected_origin=get_origin(self.request),
@ -91,12 +95,12 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
registration_options: PublicKeyCredentialCreationOptions = generate_registration_options( registration_options: PublicKeyCredentialCreationOptions = generate_registration_options(
rp_id=get_rp_id(self.request), rp_id=get_rp_id(self.request),
rp_name=self.request.tenant.branding_title, rp_name=self.request.tenant.branding_title,
user_id=user.uid, user_id=user.uid.encode("utf-8"),
user_name=user.username, user_name=user.username,
user_display_name=user.name, user_display_name=user.name,
authenticator_selection=AuthenticatorSelectionCriteria( authenticator_selection=AuthenticatorSelectionCriteria(
resident_key=str(stage.resident_key_requirement), resident_key=ResidentKeyRequirement(str(stage.resident_key_requirement)),
user_verification=str(stage.user_verification), user_verification=UserVerificationRequirement(str(stage.user_verification)),
authenticator_attachment=authenticator_attachment, authenticator_attachment=authenticator_attachment,
), ),
) )
@ -106,12 +110,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView):
return AuthenticatorWebAuthnChallenge( return AuthenticatorWebAuthnChallenge(
data={ data={
"type": ChallengeTypes.NATIVE.value, "type": ChallengeTypes.NATIVE.value,
"registration": registration_options.model_dump( "registration": loads(options_to_json(registration_options)),
mode="json",
by_alias=True,
exclude_unset=False,
exclude_none=True,
),
} }
) )

11
poetry.lock generated
View File

@ -4153,21 +4153,20 @@ files = [
[[package]] [[package]]
name = "webauthn" name = "webauthn"
version = "1.11.1" version = "2.0.0"
description = "Pythonic WebAuthn" description = "Pythonic WebAuthn"
optional = false optional = false
python-versions = "*" python-versions = "*"
files = [ files = [
{file = "webauthn-1.11.1-py3-none-any.whl", hash = "sha256:13592ee71489b571cb6e4a5d8b3c34f7b040cd3539a9d94b6b7d23fa88df5dfb"}, {file = "webauthn-2.0.0-py3-none-any.whl", hash = "sha256:644dc68af5caaade06be6a2a2278775e85116e92dd755ad7a49d992d51c82033"},
{file = "webauthn-1.11.1.tar.gz", hash = "sha256:24eda57903897369797f52a377f8c470e7057e79da5525779d0720a9fcc11926"}, {file = "webauthn-2.0.0.tar.gz", hash = "sha256:12cc1759da98668b8242badc37c4129df300f89d89f5c183fac80e7b33c41dfd"},
] ]
[package.dependencies] [package.dependencies]
asn1crypto = ">=1.4.0" asn1crypto = ">=1.4.0"
cbor2 = ">=5.4.6" cbor2 = ">=5.4.6"
cryptography = ">=41.0.4" cryptography = ">=41.0.7"
pydantic = ">=1.10.11" pyOpenSSL = ">=23.3.0"
pyOpenSSL = ">=23.2.0"
[[package]] [[package]]
name = "websocket-client" name = "websocket-client"