diff --git a/authentik/stages/authenticator_webauthn/stage.py b/authentik/stages/authenticator_webauthn/stage.py index 1b3ff2bfb..305f8a106 100644 --- a/authentik/stages/authenticator_webauthn/stage.py +++ b/authentik/stages/authenticator_webauthn/stage.py @@ -18,7 +18,7 @@ from authentik.flows.planner import PLAN_CONTEXT_PENDING_USER from authentik.flows.stage import ChallengeStageView from authentik.lib.templatetags.authentik_utils import avatar from authentik.stages.authenticator_webauthn.models import WebAuthnDevice -from authentik.stages.authenticator_webauthn.utils import generate_challenge +from authentik.stages.authenticator_webauthn.utils import generate_challenge, get_origin, get_rp_id RP_NAME = "authentik" @@ -52,8 +52,8 @@ class AuthenticatorWebAuthnChallengeResponse(ChallengeResponse): none_attestation_permitted = True webauthn_registration_response = WebAuthnRegistrationResponse( - self.request.get_host(), - self.request.build_absolute_uri("/"), + get_rp_id(self.request), + get_origin(self.request), response, challenge, trusted_attestation_cert_required=trusted_attestation_cert_required, @@ -110,7 +110,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView): make_credential_options = WebAuthnMakeCredentialOptions( challenge, RP_NAME, - self.request.get_host(), + get_rp_id(self.request), user.uid, user.username, user.name, @@ -154,7 +154,7 @@ class AuthenticatorWebAuthnStageView(ChallengeStageView): public_key=webauthn_credential.public_key, credential_id=webauthn_credential.credential_id, sign_count=webauthn_credential.sign_count, - rp_id=self.request.get_host(), + rp_id=get_rp_id(self.request), ) else: return self.executor.stage_invalid( diff --git a/authentik/stages/authenticator_webauthn/utils.py b/authentik/stages/authenticator_webauthn/utils.py index 217f685e4..6c0509e07 100644 --- a/authentik/stages/authenticator_webauthn/utils.py +++ b/authentik/stages/authenticator_webauthn/utils.py @@ -1,6 +1,7 @@ """webauthn utils""" import base64 import os +from django.http import HttpRequest CHALLENGE_DEFAULT_BYTE_LEN = 32 @@ -21,3 +22,16 @@ def generate_challenge(challenge_len=CHALLENGE_DEFAULT_BYTE_LEN): if not isinstance(challenge_base64, str): challenge_base64 = challenge_base64.decode("utf-8") return challenge_base64 + +def get_rp_id(request: HttpRequest) -> str: + """Get hostname from http request, without port""" + host = request.get_host() + if ":" in host: + return host.split(":")[0] + return host + +def get_origin(request: HttpRequest) -> str: + """Return Origin by building an absolute URL and removing the + trailing slash""" + full_url = request.build_absolute_uri("/") + return full_url[:-1]