Skip to content
Snippets Groups Projects
Commit 565b05bb authored by Julian's avatar Julian
Browse files

Support for python3-fido2 v0.9.x (Debian Bullseye)

parent caf09ca2
No related branches found
No related tags found
No related merge requests found
...@@ -103,13 +103,24 @@ def delete_totp(id): #pylint: disable=redefined-builtin ...@@ -103,13 +103,24 @@ def delete_totp(id): #pylint: disable=redefined-builtin
return redirect(url_for('mfa.setup')) return redirect(url_for('mfa.setup'))
# WebAuthn support is optional because fido2 has a pretty unstable # WebAuthn support is optional because fido2 has a pretty unstable
# interface (v0.5.0 on buster and current version are completely # interface and might be difficult to install with the correct version
# incompatible) and might be difficult to install with the correct version
try: try:
import fido2
if fido2.__version__.startswith('0.5.'):
from fido2.client import ClientData from fido2.client import ClientData
from fido2.server import Fido2Server, RelyingParty from fido2.server import Fido2Server, RelyingParty as PublicKeyCredentialRpEntity
from fido2.ctap2 import AttestationObject, AuthenticatorData from fido2.ctap2 import AttestationObject, AuthenticatorData
from fido2 import cbor from fido2 import cbor
cbor.encode = cbor.dumps
cbor.decode = lambda arg: cbor.loads(arg)[0]
elif fido2.__version__.startswith('0.9.'):
from fido2.client import ClientData
from fido2.webauthn import PublicKeyCredentialRpEntity
from fido2.server import Fido2Server
from fido2.ctap2 import AttestationObject, AuthenticatorData
from fido2 import cbor
else:
raise ImportError(f'Unsupported fido2 version: {fido2.__version__}')
WEBAUTHN_SUPPORTED = True WEBAUTHN_SUPPORTED = True
except ImportError as err: except ImportError as err:
warn(_('2FA WebAuthn support disabled because import of the fido2 module failed (%s)')%err) warn(_('2FA WebAuthn support disabled because import of the fido2 module failed (%s)')%err)
...@@ -119,7 +130,9 @@ bp.add_app_template_global(WEBAUTHN_SUPPORTED, name='webauthn_supported') ...@@ -119,7 +130,9 @@ bp.add_app_template_global(WEBAUTHN_SUPPORTED, name='webauthn_supported')
if WEBAUTHN_SUPPORTED: if WEBAUTHN_SUPPORTED:
def get_webauthn_server(): def get_webauthn_server():
return Fido2Server(RelyingParty(current_app.config.get('MFA_RP_ID', urllib.parse.urlsplit(request.url).hostname), current_app.config['MFA_RP_NAME'])) hostname = urllib.parse.urlsplit(request.url).hostname
return Fido2Server(PublicKeyCredentialRpEntity(current_app.config.get('MFA_RP_ID', hostname),
current_app.config['MFA_RP_NAME']))
@bp.route('/setup/webauthn/begin', methods=['POST']) @bp.route('/setup/webauthn/begin', methods=['POST'])
@login_required() @login_required()
...@@ -140,14 +153,14 @@ if WEBAUTHN_SUPPORTED: ...@@ -140,14 +153,14 @@ if WEBAUTHN_SUPPORTED:
user_verification='discouraged', user_verification='discouraged',
) )
session["webauthn-state"] = state session["webauthn-state"] = state
return cbor.dumps(registration_data) return cbor.encode(registration_data)
@bp.route('/setup/webauthn/complete', methods=['POST']) @bp.route('/setup/webauthn/complete', methods=['POST'])
@login_required() @login_required()
@csrf_protect(blueprint=bp) @csrf_protect(blueprint=bp)
def setup_webauthn_complete(): def setup_webauthn_complete():
server = get_webauthn_server() server = get_webauthn_server()
data = cbor.loads(request.get_data())[0] data = cbor.decode(request.get_data())
client_data = ClientData(data["clientDataJSON"]) client_data = ClientData(data["clientDataJSON"])
att_obj = AttestationObject(data["attestationObject"]) att_obj = AttestationObject(data["attestationObject"])
auth_data = server.register_complete(session["webauthn-state"], client_data, att_obj) auth_data = server.register_complete(session["webauthn-state"], client_data, att_obj)
...@@ -156,7 +169,7 @@ if WEBAUTHN_SUPPORTED: ...@@ -156,7 +169,7 @@ if WEBAUTHN_SUPPORTED:
db.session.commit() db.session.commit()
request.user.update_groups() request.user.update_groups()
ldap.session.commit() ldap.session.commit()
return cbor.dumps({"status": "OK"}) return cbor.encode({"status": "OK"})
@bp.route("/auth/webauthn/begin", methods=["POST"]) @bp.route("/auth/webauthn/begin", methods=["POST"])
@login_required_pre_mfa(no_redirect=True) @login_required_pre_mfa(no_redirect=True)
...@@ -167,7 +180,7 @@ if WEBAUTHN_SUPPORTED: ...@@ -167,7 +180,7 @@ if WEBAUTHN_SUPPORTED:
abort(404) abort(404)
auth_data, state = server.authenticate_begin(creds, user_verification='discouraged') auth_data, state = server.authenticate_begin(creds, user_verification='discouraged')
session["webauthn-state"] = state session["webauthn-state"] = state
return cbor.dumps(auth_data) return cbor.encode(auth_data)
@bp.route("/auth/webauthn/complete", methods=["POST"]) @bp.route("/auth/webauthn/complete", methods=["POST"])
@login_required_pre_mfa(no_redirect=True) @login_required_pre_mfa(no_redirect=True)
...@@ -176,7 +189,7 @@ if WEBAUTHN_SUPPORTED: ...@@ -176,7 +189,7 @@ if WEBAUTHN_SUPPORTED:
creds = [method.cred for method in request.user_pre_mfa.mfa_webauthn_methods] creds = [method.cred for method in request.user_pre_mfa.mfa_webauthn_methods]
if not creds: if not creds:
abort(404) abort(404)
data = cbor.loads(request.get_data())[0] data = cbor.decode(request.get_data())
credential_id = data["credentialId"] credential_id = data["credentialId"]
client_data = ClientData(data["clientDataJSON"]) client_data = ClientData(data["clientDataJSON"])
auth_data = AuthenticatorData(data["authenticatorData"]) auth_data = AuthenticatorData(data["authenticatorData"])
...@@ -193,7 +206,7 @@ if WEBAUTHN_SUPPORTED: ...@@ -193,7 +206,7 @@ if WEBAUTHN_SUPPORTED:
) )
session['user_mfa'] = True session['user_mfa'] = True
set_request_user() set_request_user()
return cbor.dumps({"status": "OK"}) return cbor.encode({"status": "OK"})
@bp.route('/setup/webauthn/<int:id>/delete') @bp.route('/setup/webauthn/<int:id>/delete')
@login_required() @login_required()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment