Refactor User.webauthn_credentials into a ModelList

This saves a bit of repetition, and lets us attach other methods to the
collection, rather than having multiple methods on the user object
prefixed with the same name, or random functions floating about.
This commit is contained in:
Chris Hill-Scott
2021-06-08 09:41:39 +01:00
parent 9344eabceb
commit f6aa5bdfb8
6 changed files with 56 additions and 42 deletions

View File

@@ -243,10 +243,6 @@ def user_profile_security_keys():
)
def get_key_from_list_of_keys(key_id, list_of_keys):
return next((key for key in list_of_keys if key.id == key_id), None)
@main.route(
"/user-profile/security-keys/<uuid:key_id>/manage",
methods=['GET', 'POST'],
@@ -259,8 +255,7 @@ def get_key_from_list_of_keys(key_id, list_of_keys):
)
@user_is_platform_admin
def user_profile_manage_security_key(key_id):
security_keys = current_user.webauthn_credentials
security_key = get_key_from_list_of_keys(key_id, security_keys)
security_key = current_user.webauthn_credentials.by_id(key_id)
if not security_key:
abort(404)

View File

@@ -28,7 +28,7 @@ def webauthn_begin_register():
"name": current_user.email_address,
"displayName": current_user.name,
},
credentials=current_user.webauthn_credentials_as_cbor,
credentials=current_user.webauthn_credentials.as_cbor,
user_verification="discouraged", # don't ask for PIN
authenticator_attachment="cross-platform",
)
@@ -85,7 +85,7 @@ def webauthn_begin_authentication():
abort(403)
authentication_data, state = current_app.webauthn_server.authenticate_begin(
credentials=user_to_login.webauthn_credentials_as_cbor,
credentials=user_to_login.webauthn_credentials.as_cbor,
user_verification="discouraged", # don't ask for PIN
)
session["webauthn_authentication_state"] = state
@@ -144,7 +144,7 @@ def _verify_webauthn_authentication(user):
try:
current_app.webauthn_server.authenticate_complete(
state=state,
credentials=user.webauthn_credentials_as_cbor,
credentials=user.webauthn_credentials.as_cbor,
credential_id=request_data['credentialId'],
client_data=ClientData(request_data['clientDataJSON']),
auth_data=AuthenticatorData(request_data['authenticatorData']),

View File

@@ -10,7 +10,7 @@ from app.models.roles_and_permissions import (
all_permissions,
translate_permissions_from_db_to_admin_roles,
)
from app.models.webauthn_credential import WebAuthnCredential
from app.models.webauthn_credential import WebAuthnCredentials
from app.notify_client import InviteTokenError
from app.notify_client.invite_api_client import invite_api_client
from app.notify_client.org_invite_api_client import org_invite_api_client
@@ -350,15 +350,7 @@ class User(JSONModel, UserMixin):
@property
def webauthn_credentials(self):
return [WebAuthnCredential(json) for json in
user_api_client.get_webauthn_credentials_for_user(self.id)]
@property
def webauthn_credentials_as_cbor(self):
return [
credential.to_credential_data()
for credential in self.webauthn_credentials
]
return WebAuthnCredentials(self.id)
def create_webauthn_credential(self, credential):
user_api_client.create_webauthn_credential_for_user(

View File

@@ -6,7 +6,8 @@ from fido2.cose import UnsupportedKey
from fido2.ctap2 import AttestationObject, AttestedCredentialData
from flask import current_app
from app.models import JSONModel
from app.models import JSONModel, ModelList
from app.notify_client.user_api_client import user_api_client
class RegistrationError(Exception):
@@ -60,3 +61,16 @@ class WebAuthnCredential(JSONModel):
'credential_data': self.credential_data,
'registration_response': self.registration_response,
}
class WebAuthnCredentials(ModelList):
model = WebAuthnCredential
client_method = user_api_client.get_webauthn_credentials_for_user
@property
def as_cbor(self):
return [credential.to_credential_data() for credential in self]
def by_id(self, key_id):
return next((key for key in self if key.id == key_id), None)