Skip to content

Commit 15f2fbb

Browse files
committed
Add tests to ensure no opts parser mutability
1 parent 434c6bc commit 15f2fbb

2 files changed

+76
-2
lines changed

tests/test_parse_authentication_options.py

+31-1
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,15 @@
11
from email.mime import base
22
from unittest import TestCase
33

4-
from webauthn.helpers import base64url_to_bytes
4+
from webauthn.helpers import base64url_to_bytes, options_to_json
55
from webauthn.helpers.exceptions import InvalidJSONStructure
66
from webauthn.helpers.structs import (
77
AuthenticatorTransport,
88
PublicKeyCredentialDescriptor,
99
UserVerificationRequirement,
1010
)
1111
from webauthn.helpers.parse_authentication_options_json import parse_authentication_options_json
12+
from webauthn.authentication.generate_authentication_options import generate_authentication_options
1213

1314

1415
class TestParseAuthenticationOptionsJSON(TestCase):
@@ -83,6 +84,35 @@ def test_supports_json_string(self) -> None:
8384
self.assertEqual(opts.allow_credentials, [])
8485
self.assertEqual(opts.user_verification, UserVerificationRequirement.PREFERRED)
8586

87+
def test_supports_options_to_json_output(self) -> None:
88+
"""
89+
Test that output from `generate_authentication_options()` that's fed directly into
90+
`options_to_json()` gets parsed back into the original options without any changes along
91+
the way.
92+
"""
93+
opts = generate_authentication_options(
94+
rp_id="example.com",
95+
challenge=b"1234567890",
96+
timeout=12000,
97+
allow_credentials=[
98+
PublicKeyCredentialDescriptor(
99+
id=b"1234567890",
100+
transports=[AuthenticatorTransport.INTERNAL, AuthenticatorTransport.HYBRID],
101+
)
102+
],
103+
user_verification=UserVerificationRequirement.REQUIRED,
104+
)
105+
106+
opts_json = options_to_json(opts)
107+
108+
parsed_opts_json = parse_authentication_options_json(opts_json)
109+
110+
self.assertEqual(parsed_opts_json.rp_id, opts.rp_id)
111+
self.assertEqual(parsed_opts_json.challenge, opts.challenge)
112+
self.assertEqual(parsed_opts_json.allow_credentials, opts.allow_credentials)
113+
self.assertEqual(parsed_opts_json.timeout, opts.timeout)
114+
self.assertEqual(parsed_opts_json.user_verification, opts.user_verification)
115+
86116
def test_raises_on_non_dict_json(self) -> None:
87117
with self.assertRaisesRegex(InvalidJSONStructure, "not a JSON object"):
88118
parse_authentication_options_json("[0]")

tests/test_parse_registration_options_json.py

+45-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
from unittest import TestCase
22

3-
from webauthn.helpers import base64url_to_bytes
3+
from webauthn.helpers import base64url_to_bytes, options_to_json
44
from webauthn.helpers.exceptions import InvalidJSONStructure
55
from webauthn.helpers.structs import (
66
AuthenticatorTransport,
@@ -16,6 +16,7 @@
1616
)
1717
from webauthn.helpers.cose import COSEAlgorithmIdentifier
1818
from webauthn.helpers.parse_registration_options_json import parse_registration_options_json
19+
from webauthn.registration.generate_registration_options import generate_registration_options
1920

2021

2122
class TestParseRegistrationOptionsJSON(TestCase):
@@ -221,6 +222,49 @@ def test_supports_json_string(self) -> None:
221222
)
222223
self.assertEqual(parsed.timeout, 60000)
223224

225+
def test_supports_options_to_json_output(self) -> None:
226+
"""
227+
Test that output from `generate_registration_options()` that's fed directly into
228+
`options_to_json()` gets parsed back into the original options without any changes along
229+
the way.
230+
"""
231+
opts = generate_registration_options(
232+
rp_id="example.com",
233+
rp_name="Example Co",
234+
user_id=bytes([1, 2, 3, 4]),
235+
user_name="lee",
236+
user_display_name="Lee",
237+
attestation=AttestationConveyancePreference.DIRECT,
238+
authenticator_selection=AuthenticatorSelectionCriteria(
239+
authenticator_attachment=AuthenticatorAttachment.PLATFORM,
240+
resident_key=ResidentKeyRequirement.REQUIRED,
241+
require_resident_key=True,
242+
user_verification=UserVerificationRequirement.DISCOURAGED,
243+
),
244+
challenge=bytes([1, 2, 3, 4, 5, 6, 7, 8, 9, 0]),
245+
exclude_credentials=[
246+
PublicKeyCredentialDescriptor(
247+
id=b"1234567890",
248+
transports=[AuthenticatorTransport.INTERNAL, AuthenticatorTransport.HYBRID],
249+
),
250+
],
251+
supported_pub_key_algs=[COSEAlgorithmIdentifier.ECDSA_SHA_512],
252+
timeout=12000,
253+
)
254+
255+
opts_json = options_to_json(opts)
256+
257+
parsed_opts_json = parse_registration_options_json(opts_json)
258+
259+
self.assertEqual(parsed_opts_json.rp, opts.rp)
260+
self.assertEqual(parsed_opts_json.user, opts.user)
261+
self.assertEqual(parsed_opts_json.attestation, opts.attestation)
262+
self.assertEqual(parsed_opts_json.authenticator_selection, opts.authenticator_selection)
263+
self.assertEqual(parsed_opts_json.challenge, opts.challenge)
264+
self.assertEqual(parsed_opts_json.exclude_credentials, opts.exclude_credentials)
265+
self.assertEqual(parsed_opts_json.pub_key_cred_params, opts.pub_key_cred_params)
266+
self.assertEqual(parsed_opts_json.timeout, opts.timeout)
267+
224268
def test_raises_on_non_dict_json(self) -> None:
225269
with self.assertRaisesRegex(InvalidJSONStructure, "not a JSON object"):
226270
parse_registration_options_json("[0]")

0 commit comments

Comments
 (0)