duo-labs / py_webauthn

Pythonic WebAuthn 🐍
https://duo-labs.github.io/py_webauthn
BSD 3-Clause "New" or "Revised" License
856 stars 171 forks source link

Add methods to help parse registration and authentication options JSON #210

Closed MasterKale closed 6 months ago

MasterKale commented 6 months ago

While trying to update https://webauthn.io to use webauthn==2.0.0 I discovered I needed to write logic to map JSON-serialized registration and authentication options to instances of this library's PublicKeyCredentialCreationOptions and PublicKeyCredentialRequestOptions. Moving away from Pydantic lost me the ability to call .parse_obj() on these objects to parse instances of these objects I pulled out of Redis as plain dict's, so manual mapping was required.

In v2.0.0 of this library, though, I added parse_registration_credential_json() and parse_authentication_credential_json() helpers to do this for WebAuthn responses. Now I need to do the same for their corresponding options. I've already begun this work and will put it up as a PR shortly.

Refactor guidance

Taking an example from registration: imagine a pre-v2.0.0 scenario in which a project using this library wanted to retrieve output from generate_registration_options(), serialized to JSON using webauthn.helpers.options_to_json() and then stored out of a cache or DB, and turn it back into an instance of PublicKeyCredentialCreationOptions:

# webauthn==1.11.1
json_reg_options: dict = get_stored_registration_options(session_id)
parsed_reg_options = PublicKeyCredentialCreationOptions.parse_obj(
    json_reg_options,
)

py_webauthn v2.0.0+ removed use of Pydantic, though, so .parse_obj() is no longer available on PublicKeyCredentialCreationOptions. It will become possible to refactor away use of .parse_obj() with one of the helpers in this PR:

# webauthn==2.1.0
from webauthn.helpers import parse_registration_options_json

json_reg_options: dict = get_stored_registration_options(session_id)
parsed_reg_options: PublicKeyCredentialCreationOptions = parse_registration_options_json(
    json_reg_options,
)