From 0062d45b6c9a6323f9dccb10f63dce752836c29e Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Wed, 27 Nov 2024 12:31:49 +0100 Subject: [PATCH 1/3] docs: improve SecurityError error message for ory elements local (#4205) --- internal/client-go/go.sum | 1 + ...Login-flow=passwordless-case=passkey_button_exists.json | 2 +- ...resh-case=refresh_passwordless_credentials-browser.json | 2 +- ...=refresh-case=refresh_passwordless_credentials-spa.json | 2 +- ...tings-case=a_device_is_shown_which_can_be_unlinked.json | 2 +- ...pleteSettings-case=one_activation_element_is_shown.json | 2 +- ...ormHydration-method=PopulateLoginMethodFirstFactor.json | 2 +- ...ation-method=PopulateLoginMethodFirstFactorRefresh.json | 2 +- ...d=PopulateLoginMethodIdentifierFirstIdentification.json | 2 +- ...estRegistration-case=passkey_button_exists-browser.json | 2 +- .../TestRegistration-case=passkey_button_exists-spa.json | 2 +- ...webauthn_payload_is_set_when_identity_has_webauthn.json | 2 +- ...uld_fail_if_webauthn_login_is_invalid-type=browser.json | 2 +- ...=should_fail_if_webauthn_login_is_invalid-type=spa.json | 2 +- ...less_enabled=false-case=mfa_v0_credentials-browser.json | 2 +- ...wordless_enabled=false-case=mfa_v0_credentials-spa.json | 2 +- ...less_enabled=false-case=mfa_v1_credentials-browser.json | 2 +- ...wordless_enabled=false-case=mfa_v1_credentials-spa.json | 2 +- ...enabled=true-case=passwordless_credentials-browser.json | 2 +- ...ess_enabled=true-case=passwordless_credentials-spa.json | 2 +- ...tings-case=a_device_is_shown_which_can_be_unlinked.json | 2 +- ...pleteSettings-case=one_activation_element_is_shown.json | 2 +- ...resh-case=mfa_enabled_and_user_has_mfa_credentials.json | 2 +- ...less_enabled_and_user_has_passwordless_credentials.json | 2 +- ...d=PopulateLoginMethodSecondFactor-case=mfa_enabled.json | 2 +- ...stRegistration-case=webauthn_button_exists-browser.json | 2 +- .../TestRegistration-case=webauthn_button_exists-spa.json | 2 +- x/webauthnx/js/webauthn.js | 7 ++++++- 28 files changed, 33 insertions(+), 27 deletions(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index c966c8ddfd0d..6cc3f5911d11 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,6 +4,7 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=passwordless-case=passkey_button_exists.json b/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=passwordless-case=passkey_button_exists.json index 8e6ca347223f..39b1e8a8ca59 100644 --- a/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=passwordless-case=passkey_button_exists.json +++ b/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=passwordless-case=passkey_button_exists.json @@ -38,7 +38,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-browser.json b/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-browser.json index 83a0dab00cf1..269754d1dbd0 100644 --- a/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-browser.json +++ b/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-browser.json @@ -30,7 +30,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-spa.json b/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-spa.json index 83a0dab00cf1..269754d1dbd0 100644 --- a/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-spa.json +++ b/selfservice/strategy/passkey/.snapshots/TestCompleteLogin-flow=refresh-case=refresh_passwordless_credentials-spa.json @@ -30,7 +30,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json b/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json index b8193ddec074..354fdfab6feb 100644 --- a/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json +++ b/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json @@ -110,7 +110,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json b/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json index f670fa605662..3065bddabb0f 100644 --- a/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json +++ b/selfservice/strategy/passkey/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json @@ -62,7 +62,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactor.json b/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactor.json index 5ca8b52290f1..9ea8913db0aa 100644 --- a/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactor.json +++ b/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactor.json @@ -52,7 +52,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "id": "webauthn_script", "node_type": "script" diff --git a/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactorRefresh.json b/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactorRefresh.json index d2838777ddb8..0d33b6d7d9fb 100644 --- a/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactorRefresh.json +++ b/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodFirstFactorRefresh.json @@ -18,7 +18,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "id": "webauthn_script", "node_type": "script" diff --git a/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodIdentifierFirstIdentification.json b/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodIdentifierFirstIdentification.json index 1fe32d3cd487..911497b207da 100644 --- a/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodIdentifierFirstIdentification.json +++ b/selfservice/strategy/passkey/.snapshots/TestFormHydration-method=PopulateLoginMethodIdentifierFirstIdentification.json @@ -52,7 +52,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "id": "webauthn_script", "node_type": "script" diff --git a/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-browser.json b/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-browser.json index bba362f0c308..c0d75cd7cd1d 100644 --- a/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-browser.json +++ b/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-browser.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-spa.json b/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-spa.json index bba362f0c308..c0d75cd7cd1d 100644 --- a/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-spa.json +++ b/selfservice/strategy/passkey/.snapshots/TestRegistration-case=passkey_button_exists-spa.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json index 08d46bc5ee98..4d8766c503b9 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=mfa-case=webauthn_payload_is_set_when_identity_has_webauthn.json @@ -42,7 +42,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json index 68c962a81650..d26936d42077 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=browser.json @@ -37,7 +37,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "node_type": "script" }, diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json index 68c962a81650..d26936d42077 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=passwordless-case=should_fail_if_webauthn_login_is_invalid-type=spa.json @@ -37,7 +37,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "node_type": "script" }, diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-browser.json index a3dd14c42d98..a17789700612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-browser.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-spa.json index a3dd14c42d98..a17789700612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v0_credentials-spa.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-browser.json index a3dd14c42d98..a17789700612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-browser.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-spa.json index a3dd14c42d98..a17789700612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=false-case=mfa_v1_credentials-spa.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-browser.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-browser.json index a3dd14c42d98..a17789700612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-browser.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-spa.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-spa.json index a3dd14c42d98..a17789700612 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteLogin-flow=refresh-case=passwordless-passwordless_enabled=true-case=passwordless_credentials-spa.json @@ -43,7 +43,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json index c905ffda56b7..1d38764e30a6 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=a_device_is_shown_which_can_be_unlinked.json @@ -116,7 +116,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json index e6fb889e7262..628b00fd8b5f 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json +++ b/selfservice/strategy/webauthn/.snapshots/TestCompleteSettings-case=one_activation_element_is_shown.json @@ -68,7 +68,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=mfa_enabled_and_user_has_mfa_credentials.json b/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=mfa_enabled_and_user_has_mfa_credentials.json index e4ca52133186..bd8b5253db96 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=mfa_enabled_and_user_has_mfa_credentials.json +++ b/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=mfa_enabled_and_user_has_mfa_credentials.json @@ -31,7 +31,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "id": "webauthn_script", "node_type": "script" diff --git a/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=passwordless_enabled_and_user_has_passwordless_credentials.json b/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=passwordless_enabled_and_user_has_passwordless_credentials.json index e4ca52133186..bd8b5253db96 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=passwordless_enabled_and_user_has_passwordless_credentials.json +++ b/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodRefresh-case=passwordless_enabled_and_user_has_passwordless_credentials.json @@ -31,7 +31,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "id": "webauthn_script", "node_type": "script" diff --git a/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodSecondFactor-case=mfa_enabled.json b/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodSecondFactor-case=mfa_enabled.json index e4ca52133186..bd8b5253db96 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodSecondFactor-case=mfa_enabled.json +++ b/selfservice/strategy/webauthn/.snapshots/TestFormHydration-method=PopulateLoginMethodSecondFactor-case=mfa_enabled.json @@ -31,7 +31,7 @@ "async": true, "referrerpolicy": "no-referrer", "crossorigin": "anonymous", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "type": "text/javascript", "id": "webauthn_script", "node_type": "script" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json index d1236c755981..4d51e6ea1536 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-browser.json @@ -94,7 +94,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json index d1236c755981..4d51e6ea1536 100644 --- a/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json +++ b/selfservice/strategy/webauthn/.snapshots/TestRegistration-case=webauthn_button_exists-spa.json @@ -94,7 +94,7 @@ "async": true, "crossorigin": "anonymous", "id": "webauthn_script", - "integrity": "sha512-tNeczCRytwdJg3Ncuj/DqWtyToUJS9Nnvt0FUbtglMgj8rowm19qLRKdWebaaDhpxiWxIi/6piZrgEUjOu/MCA==", + "integrity": "sha512-3Z1fDRo1yulzEUWcPb/35UhuKYyNgM/z70Pnidfr1pQGtRZz2xaFinaEyIiolwRTx+0B43ATFQcMsyaDJxC0tA==", "node_type": "script", "referrerpolicy": "no-referrer", "type": "text/javascript" diff --git a/x/webauthnx/js/webauthn.js b/x/webauthnx/js/webauthn.js index 052ce7f355c5..4bc0d4427aa9 100644 --- a/x/webauthnx/js/webauthn.js +++ b/x/webauthnx/js/webauthn.js @@ -272,7 +272,12 @@ }) .catch((err) => { // Calling this again will enable the autocomplete once again. - console.error(err) + if (err instanceof DOMException && err.name === "SecurityError") { + console.error(`A security exception occurred while loading Passkeys / WebAuthn. To troubleshoot, please head over to https://www.ory.sh/docs/troubleshooting/passkeys-webauthn-security-error. The original error message is: ${err.message}`) + } else { + console.error("[Ory/Passkey] An unknown error occurred while getting passkey credentials", err) + } + console.trace(err) window.abortPasskeyConditionalUI && __oryPasskeyLoginAutocompleteInit() }) From a82d288014411ae4eb82c718bfe825ca55b4fab0 Mon Sep 17 00:00:00 2001 From: hackerman <3372410+aeneasr@users.noreply.github.com> Date: Wed, 27 Nov 2024 12:32:07 +0100 Subject: [PATCH 2/3] feat: support android webauthn origins (#4155) This patch adds the ability to verify Android APK origins used during WebAuthn/Passkey exchange. Upgrades go-webauthn and includes fixes for Go 1.23 and workarounds for Swagger. --- .docker/Dockerfile-build | 2 +- .docker/Dockerfile-debug | 2 +- .github/workflows/ci.yaml | 8 +- .github/workflows/format.yml | 2 +- .github/workflows/licenses.yml | 2 +- .golangci.yml | 1 + .schema/openapi/patches/selfservice.yaml | 58 +++++++---- driver/config/config.go | 1 + embedx/config.schema.json | 1 - go.mod | 18 ++-- go.sum | 28 +++--- hash/hash_comparator.go | 11 +-- identity/credentials_webauthn.go | 97 ++++++++++++++++--- identity/credentials_webauthn_test.go | 10 +- identity/handler_test.go | 8 +- internal/client-go/model_login_flow_state.go | 2 +- .../client-go/model_recovery_flow_state.go | 2 +- .../model_registration_flow_state.go | 2 +- .../client-go/model_settings_flow_state.go | 2 +- .../model_verification_flow_state.go | 2 +- internal/httpclient/model_login_flow_state.go | 2 +- .../httpclient/model_recovery_flow_state.go | 2 +- .../model_registration_flow_state.go | 2 +- .../httpclient/model_settings_flow_state.go | 2 +- .../model_verification_flow_state.go | 2 +- schema/handler.go | 13 ++- schema/handler_test.go | 2 +- .../success/android/internal_context.json | 7 ++ .../success/android/response.json | 9 ++ .../success/{ => browser}/identity.json | 0 .../{ => browser}/internal_context.json | 0 .../success/{ => browser}/response.json | 0 selfservice/strategy/passkey/passkey_login.go | 3 +- .../passkey/passkey_registration_test.go | 65 ++++++++++++- .../strategy/passkey/testfixture_test.go | 33 +++++-- selfservice/strategy/webauthn/login.go | 4 +- spec/api.json | 22 ++--- spec/swagger.json | 25 ----- test/e2e/mock/httptarget/go.mod | 2 +- 39 files changed, 308 insertions(+), 146 deletions(-) create mode 100644 selfservice/strategy/passkey/fixtures/registration/success/android/internal_context.json create mode 100644 selfservice/strategy/passkey/fixtures/registration/success/android/response.json rename selfservice/strategy/passkey/fixtures/registration/success/{ => browser}/identity.json (100%) rename selfservice/strategy/passkey/fixtures/registration/success/{ => browser}/internal_context.json (100%) rename selfservice/strategy/passkey/fixtures/registration/success/{ => browser}/response.json (100%) diff --git a/.docker/Dockerfile-build b/.docker/Dockerfile-build index bd619930f0a9..687d8834012f 100644 --- a/.docker/Dockerfile-build +++ b/.docker/Dockerfile-build @@ -1,5 +1,5 @@ # syntax = docker/dockerfile:1-experimental -FROM golang:1.22-bullseye AS builder +FROM golang:1.23-bullseye AS builder RUN apt-get update && apt-get upgrade -y &&\ mkdir -p /var/lib/sqlite diff --git a/.docker/Dockerfile-debug b/.docker/Dockerfile-debug index a309b5ad92bb..97a0e2b72525 100644 --- a/.docker/Dockerfile-debug +++ b/.docker/Dockerfile-debug @@ -1,4 +1,4 @@ -FROM golang:1.22-bullseye +FROM golang:1.23-bullseye ENV CGO_ENABLED 1 RUN apt-get update && apt-get install -y --no-install-recommends inotify-tools psmisc diff --git a/.github/workflows/ci.yaml b/.github/workflows/ci.yaml index e7c488f0d496..9fc74bd6397f 100644 --- a/.github/workflows/ci.yaml +++ b/.github/workflows/ci.yaml @@ -79,7 +79,7 @@ jobs: fetch-depth: 2 - uses: actions/setup-go@v4 with: - go-version: "1.22" + go-version: "1.23" - run: go list -json > go.list - name: Run nancy uses: sonatype-nexus-community/nancy-github-action@v1.0.2 @@ -93,7 +93,7 @@ jobs: GOGC: 100 with: args: --timeout 10m0s - version: v1.59.1 + version: v1.61.0 - name: Build Kratos run: make install - name: Run go-acc (tests) @@ -169,7 +169,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.22" + go-version: "1.23" - name: Install selfservice-ui-react-native uses: actions/checkout@v3 @@ -273,7 +273,7 @@ jobs: - name: Setup Go uses: actions/setup-go@v4 with: - go-version: "1.22" + go-version: "1.23" - run: go build -tags sqlite,json1 . - name: Install selfservice-ui-react-native diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 7e243923b8ca..bb107819d849 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v3 - uses: actions/setup-go@v3 with: - go-version: "1.22" + go-version: "1.23" - run: make format - name: Indicate formatting issues run: git diff HEAD --exit-code --color diff --git a/.github/workflows/licenses.yml b/.github/workflows/licenses.yml index 8a86486031de..9d1589506da2 100644 --- a/.github/workflows/licenses.yml +++ b/.github/workflows/licenses.yml @@ -14,7 +14,7 @@ jobs: - uses: actions/checkout@v2 - uses: actions/setup-go@v2 with: - go-version: "1.22" + go-version: "1.23" - uses: actions/setup-node@v2 with: node-version: "18" diff --git a/.golangci.yml b/.golangci.yml index e83dd5a56a2e..81b4a23960df 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -29,3 +29,4 @@ issues: - "Set is deprecated: use context-based WithConfigValue instead" - "SetDefaultIdentitySchemaFromRaw is deprecated: Use context-based WithDefaultIdentitySchemaFromRaw instead" - "SetDefaultIdentitySchema is deprecated: Use context-based WithDefaultIdentitySchema instead" + - "G115" diff --git a/.schema/openapi/patches/selfservice.yaml b/.schema/openapi/patches/selfservice.yaml index 3fe24b62fb5a..39a329bf5928 100644 --- a/.schema/openapi/patches/selfservice.yaml +++ b/.schema/openapi/patches/selfservice.yaml @@ -32,11 +32,15 @@ passkey: "#/components/schemas/updateRegistrationFlowWithPasskeyMethod" profile: "#/components/schemas/updateRegistrationFlowWithProfileMethod" - op: add - path: /components/schemas/registrationFlowState/enum + path: /components/schemas/registrationFlowState value: - - choose_method - - sent_email - - passed_challenge + title: Registration flow state (experimental) + description: The experimental state represents the state of a registration flow. This field is EXPERIMENTAL and subject to change! + type: string + enum: + - choose_method + - sent_email + - passed_challenge # end # All modifications for the login flow @@ -67,11 +71,15 @@ passkey: "#/components/schemas/updateLoginFlowWithPasskeyMethod" identifier_first: "#/components/schemas/updateLoginFlowWithIdentifierFirstMethod" - op: add - path: /components/schemas/loginFlowState/enum + path: /components/schemas/loginFlowState value: - - choose_method - - sent_email - - passed_challenge + title: Login flow state (experimental) + description: The experimental state represents the state of a login flow. This field is EXPERIMENTAL and subject to change! + type: string + enum: + - choose_method + - sent_email + - passed_challenge # end # All modifications for the recovery flow @@ -90,11 +98,15 @@ link: "#/components/schemas/updateRecoveryFlowWithLinkMethod" code: "#/components/schemas/updateRecoveryFlowWithCodeMethod" - op: add - path: /components/schemas/recoveryFlowState/enum + path: /components/schemas/recoveryFlowState + type: string value: - - choose_method - - sent_email - - passed_challenge + title: Recovery flow state (experimental) + description: The experimental state represents the state of a recovery flow. This field is EXPERIMENTAL and subject to change! + enum: + - choose_method + - sent_email + - passed_challenge # End # All modifications for the verification flow @@ -113,11 +125,15 @@ link: "#/components/schemas/updateVerificationFlowWithLinkMethod" code: "#/components/schemas/updateVerificationFlowWithCodeMethod" - op: add - path: /components/schemas/verificationFlowState/enum + path: /components/schemas/verificationFlowState + type: string value: - - choose_method - - sent_email - - passed_challenge + title: Verification flow state (experimental) + description: The experimental state represents the state of a verification flow. This field is EXPERIMENTAL and subject to change! + enum: + - choose_method + - sent_email + - passed_challenge # End # All modifications for the settings flow @@ -146,10 +162,14 @@ passkey: "#/components/schemas/updateSettingsFlowWithPasskeyMethod" lookup_secret: "#/components/schemas/updateSettingsFlowWithLookupMethod" - op: add - path: /components/schemas/settingsFlowState/enum + path: /components/schemas/settingsFlowState value: - - show_form - - success + title: Settings flow state (experimental) + description: The experimental state represents the state of a settings flow. This field is EXPERIMENTAL and subject to change! + type: string + enum: + - show_form + - success # end # Some issues with AdditionalProperties diff --git a/driver/config/config.go b/driver/config/config.go index 4eb0566963d2..b1e16e393f13 100644 --- a/driver/config/config.go +++ b/driver/config/config.go @@ -1531,6 +1531,7 @@ func (p *Config) PasskeyConfig(ctx context.Context) *webauthn.Config { AuthenticatorSelection: protocol.AuthenticatorSelection{ AuthenticatorAttachment: "platform", RequireResidentKey: pointerx.Ptr(true), + ResidentKey: protocol.ResidentKeyRequirementRequired, UserVerification: protocol.VerificationPreferred, }, EncodeUserIDAsString: false, diff --git a/embedx/config.schema.json b/embedx/config.schema.json index 48bda1c3d7f7..5fcf826f4c2a 100644 --- a/embedx/config.schema.json +++ b/embedx/config.schema.json @@ -1903,7 +1903,6 @@ "description": "A list of explicit RP origins. If left empty, this defaults to either `origin` or `id`, prepended with the current protocol schema (HTTP or HTTPS).", "items": { "type": "string", - "format": "uri", "examples": [ "https://www.ory.sh", "https://auth.ory.sh" diff --git a/go.mod b/go.mod index 96d6e9b287ba..61b7fc71dfd7 100644 --- a/go.mod +++ b/go.mod @@ -1,8 +1,12 @@ module github.com/ory/kratos -go 1.22 +go 1.23 + +toolchain go1.23.2 replace ( + github.com/go-swagger/go-swagger => github.com/aeneasr/go-swagger v0.19.1-0.20241013070044-bccef3a12e26 // See https://github.com/go-swagger/go-swagger/issues/3131 + // github.com/go-swagger/go-swagger => ../../go-swagger/go-swagger // https://github.com/gobuffalo/pop/pull/833 github.com/gobuffalo/pop/v6 => github.com/ory/pop/v6 v6.2.1-0.20241121111754-e5dfc0f3344b @@ -34,7 +38,7 @@ require ( github.com/go-openapi/strfmt v0.23.0 github.com/go-playground/validator/v10 v10.22.0 github.com/go-swagger/go-swagger v0.31.0 - github.com/go-webauthn/webauthn v0.10.2 // DO NOT UPGRADE TO 0.11.0 WITHOUT ADDRESSING ory/kratos#4034 + github.com/go-webauthn/webauthn v0.11.2 github.com/gobuffalo/httptest v1.5.2 github.com/gobuffalo/pop/v6 v6.1.2-0.20230318123913-c85387acc9a0 github.com/gofrs/uuid v4.4.0+incompatible @@ -91,12 +95,12 @@ require ( go.opentelemetry.io/otel v1.28.0 go.opentelemetry.io/otel/sdk v1.28.0 go.opentelemetry.io/otel/trace v1.28.0 - golang.org/x/crypto v0.25.0 + golang.org/x/crypto v0.26.0 golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 golang.org/x/net v0.27.0 golang.org/x/oauth2 v0.21.0 - golang.org/x/sync v0.7.0 - golang.org/x/text v0.16.0 + golang.org/x/sync v0.8.0 + golang.org/x/text v0.17.0 google.golang.org/grpc v1.65.0 ) @@ -111,7 +115,7 @@ require ( github.com/cortesi/termlog v0.0.0-20210222042314-a1eec763abec // indirect github.com/jackc/pgx/v5 v5.6.0 // indirect github.com/rjeczalik/notify v0.9.3 // indirect - golang.org/x/term v0.22.0 // indirect + golang.org/x/term v0.23.0 // indirect gopkg.in/alecthomas/kingpin.v2 v2.2.6 // indirect mvdan.cc/sh/v3 v3.6.0 // indirect ) @@ -164,7 +168,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-sql-driver/mysql v1.8.1 // indirect - github.com/go-webauthn/x v0.1.12 // indirect + github.com/go-webauthn/x v0.1.14 // indirect github.com/gobuffalo/envy v1.10.2 // indirect github.com/gobuffalo/fizz v1.14.4 // indirect github.com/gobuffalo/flect v1.0.2 // indirect diff --git a/go.sum b/go.sum index 54629e85036f..7acd5b069c70 100644 --- a/go.sum +++ b/go.sum @@ -53,6 +53,8 @@ github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERo github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5 h1:TngWCqHvy9oXAN6lEVMRuU21PR1EtLVZJmdB18Gu3Rw= github.com/Nvveen/Gotty v0.0.0-20120604004816-cd527374f1e5/go.mod h1:lmUJ/7eu/Q8D7ML55dXQrVaamCz2vxCfdQBasLZfHKk= +github.com/aeneasr/go-swagger v0.19.1-0.20241013070044-bccef3a12e26 h1:rwCKVbnpzxQ0F/AhO9FkXnrKqRmqej4epjhe1CpNkB0= +github.com/aeneasr/go-swagger v0.19.1-0.20241013070044-bccef3a12e26/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751 h1:JYp7IbQjafoB+tBA3gMyHYHrpOtNuDiK/uB5uXxq5wM= github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -232,14 +234,12 @@ github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LB github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-swagger/go-swagger v0.31.0 h1:H8eOYQnY2u7vNKWDNykv2xJP3pBhRG/R+SOCAmKrLlc= -github.com/go-swagger/go-swagger v0.31.0/go.mod h1:WSigRRWEig8zV6t6Sm8Y+EmUjlzA/HoaZJ5edupq7po= github.com/go-test/deep v1.0.4 h1:u2CU3YKy9I2pmu9pX0eq50wCgjfGIt539SqR7FbHiho= github.com/go-test/deep v1.0.4/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= -github.com/go-webauthn/webauthn v0.10.2 h1:OG7B+DyuTytrEPFmTX503K77fqs3HDK/0Iv+z8UYbq4= -github.com/go-webauthn/webauthn v0.10.2/go.mod h1:Gd1IDsGAybuvK1NkwUTLbGmeksxuRJjVN2PE/xsPxHs= -github.com/go-webauthn/x v0.1.12 h1:RjQ5cvApzyU/xLCiP+rub0PE4HBZsLggbxGR5ZpUf/A= -github.com/go-webauthn/x v0.1.12/go.mod h1:XlRcGkNH8PT45TfeJYc6gqpOtiOendHhVmnOxh+5yHs= +github.com/go-webauthn/webauthn v0.11.2 h1:Fgx0/wlmkClTKlnOsdOQ+K5HcHDsDcYIvtYmfhEOSUc= +github.com/go-webauthn/webauthn v0.11.2/go.mod h1:aOtudaF94pM71g3jRwTYYwQTG1KyTILTcZqN1srkmD0= +github.com/go-webauthn/x v0.1.14 h1:1wrB8jzXAofojJPAaRxnZhRgagvLGnLjhCAwg3kTpT0= +github.com/go-webauthn/x v0.1.14/go.mod h1:UuVvFZ8/NbOnkDz3y1NaxtUN87pmtpC1PQ+/5BBQRdc= github.com/gobuffalo/envy v1.10.2 h1:EIi03p9c3yeuRCFPOKcSfajzkLb3hrRjEpHGI8I2Wo4= github.com/gobuffalo/envy v1.10.2/go.mod h1:qGAGwdvDsaEtPhfBzb3o0SfDea8ByGn9j8bKmVft9z8= github.com/gobuffalo/fizz v1.14.4 h1:8uume7joF6niTNWN582IQ2jhGTUoa9g1fiV/tIoGdBs= @@ -864,8 +864,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.4.0/go.mod h1:3quD/ATkf6oY+rnes5c3ExXTbLc8mueNue5/DoinL80= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.25.0 h1:ypSNr+bnYL2YhwoMt2zPxHFmbAN1KZs/njMG3hxUp30= -golang.org/x/crypto v0.25.0/go.mod h1:T+wALwcMOSE0kXgUAnPAHqTLW+XHgcELELW8VaDgm/M= +golang.org/x/crypto v0.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw= +golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -979,8 +979,8 @@ golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20220929204114-8fcdb60fdcc0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= -golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M= -golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= +golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= @@ -1058,8 +1058,8 @@ golang.org/x/term v0.7.0/go.mod h1:P32HKFT3hSsZrRxla30E9HqToFYAQPCMs/zFMBUFqPY= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.22.0 h1:BbsgPEJULsl2fV/AT3v15Mjva5yXKQDyKf+TbDz7QJk= -golang.org/x/term v0.22.0/go.mod h1:F3qCibpT5AMpCRfhfT53vVJwhLtIVHhB9XDjfFvnMI4= +golang.org/x/term v0.23.0 h1:F6D4vR+EHoL9/sWAWgAR1H2DcHr4PareCbAaCo1RpuU= +golang.org/x/term v0.23.0/go.mod h1:DgV24QBUrK6jhZXl+20l6UWznPlwAHm1Q1mGHtydmSk= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1072,8 +1072,8 @@ golang.org/x/text v0.5.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= -golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4= -golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI= +golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= +golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= diff --git a/hash/hash_comparator.go b/hash/hash_comparator.go index 2e51af5ddca5..ca23fc4abfd4 100644 --- a/hash/hash_comparator.go +++ b/hash/hash_comparator.go @@ -9,8 +9,8 @@ import ( "crypto/aes" "crypto/cipher" "crypto/hmac" - "crypto/md5" //#nosec G501 -- compatibility for imported passwords - "crypto/sha1" //#nosec G505 -- compatibility for imported passwords + "crypto/md5" //nolint:all // System compatibility for imported passwords + "crypto/sha1" //nolint:all // System compatibility for imported passwords "crypto/sha256" "crypto/sha512" "crypto/subtle" @@ -21,6 +21,9 @@ import ( "regexp" "strings" + "github.com/go-crypt/crypt" + "github.com/go-crypt/crypt/algorithm/md5crypt" + "github.com/go-crypt/crypt/algorithm/shacrypt" "github.com/pkg/errors" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" @@ -33,10 +36,6 @@ import ( "golang.org/x/crypto/pbkdf2" "golang.org/x/crypto/scrypt" - "github.com/go-crypt/crypt" - "github.com/go-crypt/crypt/algorithm/md5crypt" - "github.com/go-crypt/crypt/algorithm/shacrypt" - "github.com/ory/kratos/driver/config" ) diff --git a/identity/credentials_webauthn.go b/identity/credentials_webauthn.go index 0816046d23e4..ae6b2e34cb77 100644 --- a/identity/credentials_webauthn.go +++ b/identity/credentials_webauthn.go @@ -6,6 +6,8 @@ package identity import ( "time" + "github.com/go-webauthn/webauthn/protocol" + "github.com/go-webauthn/webauthn/webauthn" "github.com/ory/kratos/x/webauthnx/aaguid" @@ -27,11 +29,17 @@ func CredentialFromWebAuthn(credential *webauthn.Credential, isPasswordless bool IsPasswordless: isPasswordless, AttestationType: credential.AttestationType, AddedAt: time.Now().UTC().Round(time.Second), - Authenticator: AuthenticatorWebAuthn{ + Authenticator: &AuthenticatorWebAuthn{ AAGUID: credential.Authenticator.AAGUID, SignCount: credential.Authenticator.SignCount, CloneWarning: credential.Authenticator.CloneWarning, }, + Flags: &CredentialWebAuthnFlags{ + UserPresent: credential.Flags.UserPresent, + UserVerified: credential.Flags.UserVerified, + BackupEligible: credential.Flags.BackupEligible, + BackupState: credential.Flags.BackupState, + }, } id := aaguid.Lookup(credential.Authenticator.AAGUID) if id != nil { @@ -49,8 +57,16 @@ func (c CredentialsWebAuthn) ToWebAuthn() (result []webauthn.Credential) { } // PasswordlessOnly returns only passwordless credentials. -func (c CredentialsWebAuthn) PasswordlessOnly() (result []webauthn.Credential) { +func (c CredentialsWebAuthn) PasswordlessOnly(authenticatorResponseFlags *protocol.AuthenticatorFlags) (result []webauthn.Credential) { for k, cc := range c { + // Upgrade path for legacy webauthn credentials. Only possible if we are handling a response from an authenticator. + if c[k].Flags == nil && authenticatorResponseFlags != nil { + c[k].Flags = &CredentialWebAuthnFlags{ + BackupEligible: authenticatorResponseFlags.HasBackupEligible(), + BackupState: authenticatorResponseFlags.HasBackupState(), + } + } + if cc.IsPasswordless { result = append(result, *c[k].ToWebAuthn()) } @@ -61,38 +77,91 @@ func (c CredentialsWebAuthn) PasswordlessOnly() (result []webauthn.Credential) { // ToWebAuthnFiltered returns only the appropriate credentials for the requested // AAL. For AAL1, only passwordless credentials are returned, for AAL2, only // non-passwordless credentials are returned. -func (c CredentialsWebAuthn) ToWebAuthnFiltered(aal AuthenticatorAssuranceLevel) (result []webauthn.Credential) { +// +// authenticatorResponseFlags should be passed if the response is from an authenticator. It will be used to +// upgrade legacy webauthn credentials' BackupEligible and BackupState flags. +func (c CredentialsWebAuthn) ToWebAuthnFiltered(aal AuthenticatorAssuranceLevel, authenticatorResponseFlags *protocol.AuthenticatorFlags) (result []webauthn.Credential) { for k, cc := range c { + // Upgrade path for legacy webauthn credentials. Only possible if we are handling a response from an authenticator. + if c[k].Flags == nil && authenticatorResponseFlags != nil { + c[k].Flags = &CredentialWebAuthnFlags{ + BackupEligible: authenticatorResponseFlags.HasBackupEligible(), + BackupState: authenticatorResponseFlags.HasBackupState(), + } + } + if (aal == AuthenticatorAssuranceLevel1 && cc.IsPasswordless) || (aal == AuthenticatorAssuranceLevel2 && !cc.IsPasswordless) { result = append(result, *c[k].ToWebAuthn()) } - } return result } func (c *CredentialWebAuthn) ToWebAuthn() *webauthn.Credential { - return &webauthn.Credential{ + wc := &webauthn.Credential{ ID: c.ID, PublicKey: c.PublicKey, AttestationType: c.AttestationType, - Authenticator: webauthn.Authenticator{ + Transport: c.Transport, + } + + if c.Authenticator != nil { + wc.Authenticator = webauthn.Authenticator{ AAGUID: c.Authenticator.AAGUID, SignCount: c.Authenticator.SignCount, CloneWarning: c.Authenticator.CloneWarning, - }, + } } + + if c.Flags != nil { + wc.Flags = webauthn.CredentialFlags{ + UserPresent: c.Flags.UserPresent, + UserVerified: c.Flags.UserVerified, + BackupEligible: c.Flags.BackupEligible, + BackupState: c.Flags.BackupState, + } + } + + if c.Attestation != nil { + wc.Attestation = webauthn.CredentialAttestation{ + ClientDataJSON: c.Attestation.ClientDataJSON, + ClientDataHash: c.Attestation.ClientDataHash, + AuthenticatorData: c.Attestation.AuthenticatorData, + PublicKeyAlgorithm: c.Attestation.PublicKeyAlgorithm, + Object: c.Attestation.Object, + } + } + + return wc } type CredentialWebAuthn struct { - ID []byte `json:"id"` - PublicKey []byte `json:"public_key"` - AttestationType string `json:"attestation_type"` - Authenticator AuthenticatorWebAuthn `json:"authenticator"` - DisplayName string `json:"display_name"` - AddedAt time.Time `json:"added_at"` - IsPasswordless bool `json:"is_passwordless"` + ID []byte `json:"id"` + PublicKey []byte `json:"public_key"` + AttestationType string `json:"attestation_type"` + Authenticator *AuthenticatorWebAuthn `json:"authenticator,omitempty"` + DisplayName string `json:"display_name"` + AddedAt time.Time `json:"added_at"` + IsPasswordless bool `json:"is_passwordless"` + Flags *CredentialWebAuthnFlags `json:"flags,omitempty"` + Transport []protocol.AuthenticatorTransport `json:"transport,omitempty"` + Attestation *CredentialWebAuthnAttestation `json:"attestation,omitempty"` +} + +type CredentialWebAuthnFlags struct { + UserPresent bool `json:"user_present"` + UserVerified bool `json:"user_verified"` + BackupEligible bool `json:"backup_eligible"` + BackupState bool `json:"backup_state"` +} + +type CredentialWebAuthnAttestation struct { + ClientDataJSON []byte `json:"client_dataJSON"` + ClientDataHash []byte `json:"client_data_hash"` + AuthenticatorData []byte `json:"authenticator_data"` + PublicKeyAlgorithm int64 `json:"public_key_algorithm"` + Object []byte `json:"object"` } type AuthenticatorWebAuthn struct { diff --git a/identity/credentials_webauthn_test.go b/identity/credentials_webauthn_test.go index ed3dc9689a7b..8918898e71be 100644 --- a/identity/credentials_webauthn_test.go +++ b/identity/credentials_webauthn_test.go @@ -28,16 +28,16 @@ func TestCredentialConversion(t *testing.T) { actual := CredentialFromWebAuthn(expected, false).ToWebAuthn() assert.Equal(t, expected, actual) - actualList := CredentialsWebAuthn{*CredentialFromWebAuthn(expected, false)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel2) + actualList := CredentialsWebAuthn{*CredentialFromWebAuthn(expected, false)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel2, nil) assert.Equal(t, []webauthn.Credential{*expected}, actualList) - actualList = CredentialsWebAuthn{*CredentialFromWebAuthn(expected, true)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel1) + actualList = CredentialsWebAuthn{*CredentialFromWebAuthn(expected, true)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel1, nil) assert.Equal(t, []webauthn.Credential{*expected}, actualList) - actualList = CredentialsWebAuthn{*CredentialFromWebAuthn(expected, true)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel2) + actualList = CredentialsWebAuthn{*CredentialFromWebAuthn(expected, true)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel2, nil) assert.Len(t, actualList, 0) - actualList = CredentialsWebAuthn{*CredentialFromWebAuthn(expected, false)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel1) + actualList = CredentialsWebAuthn{*CredentialFromWebAuthn(expected, false)}.ToWebAuthnFiltered(AuthenticatorAssuranceLevel1, nil) assert.Len(t, actualList, 0) fromWebAuthn := CredentialFromWebAuthn(expected, true) @@ -58,7 +58,7 @@ func TestPasswordlessOnly(t *testing.T) { e := *CredentialFromWebAuthn(&webauthn.Credential{ID: []byte("e")}, true) expected := CredentialsWebAuthn{a, b, c, d, e} - actual := expected.PasswordlessOnly() + actual := expected.PasswordlessOnly(nil) require.Len(t, actual, 2) assert.Equal(t, []webauthn.Credential{*c.ToWebAuthn(), *e.ToWebAuthn()}, actual) } diff --git a/identity/handler_test.go b/identity/handler_test.go index 6ff1080ee256..e3362a6ecf94 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -1702,7 +1702,7 @@ func TestHandler(t *testing.T) { AddedAt: time.Date(2022, 12, 16, 14, 11, 55, 0, time.UTC), PublicKey: []byte("pQECAyYgASFYIMJLQhJxQRzhnKPTcPCUODOmxYDYo2obrm9bhp5lvSZ3IlggXjhZvJaPUqF9PXqZqTdWYPR7R+b2n/Wi+IxKKXsS4rU="), DisplayName: "test", - Authenticator: identity.AuthenticatorWebAuthn{ + Authenticator: &identity.AuthenticatorWebAuthn{ AAGUID: []byte("rc4AAjW8xgpkiwsl8fBVAw=="), SignCount: 0, CloneWarning: false, @@ -1715,7 +1715,7 @@ func TestHandler(t *testing.T) { AddedAt: time.Date(2022, 12, 16, 14, 11, 55, 0, time.UTC), PublicKey: []byte("pQECAyYgASFYIMJLQhJxQRzhnKPTcPCUODOmxYDYo2obrm9bhp5lvSZ3IlggXjhZvJaPUqF9PXqZqTdWYPR7R+b2n/Wi+IxKKXsS4rU="), DisplayName: "test", - Authenticator: identity.AuthenticatorWebAuthn{ + Authenticator: &identity.AuthenticatorWebAuthn{ AAGUID: []byte("rc4AAjW8xgpkiwsl8fBVAw=="), SignCount: 0, CloneWarning: false, @@ -1728,7 +1728,7 @@ func TestHandler(t *testing.T) { AddedAt: time.Date(2022, 12, 16, 14, 11, 55, 0, time.UTC), PublicKey: []byte("pQECAyYgASFYIMJLQhJxQRzhnKPTcPCUODOmxYDYo2obrm9bhp5lvSZ3IlggXjhZvJaPUqF9PXqZqTdWYPR7R+b2n/Wi+IxKKXsS4rU="), DisplayName: "test", - Authenticator: identity.AuthenticatorWebAuthn{ + Authenticator: &identity.AuthenticatorWebAuthn{ AAGUID: []byte("rc4AAjW8xgpkiwsl8fBVAw=="), SignCount: 0, CloneWarning: false, @@ -1741,7 +1741,7 @@ func TestHandler(t *testing.T) { AddedAt: time.Date(2022, 12, 16, 14, 11, 55, 0, time.UTC), PublicKey: []byte("pQECAyYgASFYIMJLQhJxQRzhnKPTcPCUODOmxYDYo2obrm9bhp5lvSZ3IlggXjhZvJaPUqF9PXqZqTdWYPR7R+b2n/Wi+IxKKXsS4rU="), DisplayName: "test", - Authenticator: identity.AuthenticatorWebAuthn{ + Authenticator: &identity.AuthenticatorWebAuthn{ AAGUID: []byte("rc4AAjW8xgpkiwsl8fBVAw=="), SignCount: 0, CloneWarning: false, diff --git a/internal/client-go/model_login_flow_state.go b/internal/client-go/model_login_flow_state.go index ce5570b79032..58af057c612f 100644 --- a/internal/client-go/model_login_flow_state.go +++ b/internal/client-go/model_login_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// LoginFlowState The state represents the state of the login flow. choose_method: ask the user to choose a method (e.g. login account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. +// LoginFlowState The experimental state represents the state of a login flow. This field is EXPERIMENTAL and subject to change! type LoginFlowState string // List of loginFlowState diff --git a/internal/client-go/model_recovery_flow_state.go b/internal/client-go/model_recovery_flow_state.go index 1c660ba043b9..d1fa3618882a 100644 --- a/internal/client-go/model_recovery_flow_state.go +++ b/internal/client-go/model_recovery_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// RecoveryFlowState The state represents the state of the recovery flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. +// RecoveryFlowState The experimental state represents the state of a recovery flow. This field is EXPERIMENTAL and subject to change! type RecoveryFlowState string // List of recoveryFlowState diff --git a/internal/client-go/model_registration_flow_state.go b/internal/client-go/model_registration_flow_state.go index 86f3fd38cff0..15fd9f532d4b 100644 --- a/internal/client-go/model_registration_flow_state.go +++ b/internal/client-go/model_registration_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// RegistrationFlowState choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. +// RegistrationFlowState The experimental state represents the state of a registration flow. This field is EXPERIMENTAL and subject to change! type RegistrationFlowState string // List of registrationFlowState diff --git a/internal/client-go/model_settings_flow_state.go b/internal/client-go/model_settings_flow_state.go index f994c786a2d8..70093c9c4a03 100644 --- a/internal/client-go/model_settings_flow_state.go +++ b/internal/client-go/model_settings_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// SettingsFlowState show_form: No user data has been collected, or it is invalid, and thus the form should be shown. success: Indicates that the settings flow has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a flow with invalid (e.g. \"please use a valid phone number\") data was sent. +// SettingsFlowState The experimental state represents the state of a settings flow. This field is EXPERIMENTAL and subject to change! type SettingsFlowState string // List of settingsFlowState diff --git a/internal/client-go/model_verification_flow_state.go b/internal/client-go/model_verification_flow_state.go index bea74568c94d..56b65e0c0a5b 100644 --- a/internal/client-go/model_verification_flow_state.go +++ b/internal/client-go/model_verification_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// VerificationFlowState The state represents the state of the verification flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. +// VerificationFlowState The experimental state represents the state of a verification flow. This field is EXPERIMENTAL and subject to change! type VerificationFlowState string // List of verificationFlowState diff --git a/internal/httpclient/model_login_flow_state.go b/internal/httpclient/model_login_flow_state.go index ce5570b79032..58af057c612f 100644 --- a/internal/httpclient/model_login_flow_state.go +++ b/internal/httpclient/model_login_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// LoginFlowState The state represents the state of the login flow. choose_method: ask the user to choose a method (e.g. login account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the login challenge was passed. +// LoginFlowState The experimental state represents the state of a login flow. This field is EXPERIMENTAL and subject to change! type LoginFlowState string // List of loginFlowState diff --git a/internal/httpclient/model_recovery_flow_state.go b/internal/httpclient/model_recovery_flow_state.go index 1c660ba043b9..d1fa3618882a 100644 --- a/internal/httpclient/model_recovery_flow_state.go +++ b/internal/httpclient/model_recovery_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// RecoveryFlowState The state represents the state of the recovery flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. +// RecoveryFlowState The experimental state represents the state of a recovery flow. This field is EXPERIMENTAL and subject to change! type RecoveryFlowState string // List of recoveryFlowState diff --git a/internal/httpclient/model_registration_flow_state.go b/internal/httpclient/model_registration_flow_state.go index 86f3fd38cff0..15fd9f532d4b 100644 --- a/internal/httpclient/model_registration_flow_state.go +++ b/internal/httpclient/model_registration_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// RegistrationFlowState choose_method: ask the user to choose a method (e.g. registration with email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the registration challenge was passed. +// RegistrationFlowState The experimental state represents the state of a registration flow. This field is EXPERIMENTAL and subject to change! type RegistrationFlowState string // List of registrationFlowState diff --git a/internal/httpclient/model_settings_flow_state.go b/internal/httpclient/model_settings_flow_state.go index f994c786a2d8..70093c9c4a03 100644 --- a/internal/httpclient/model_settings_flow_state.go +++ b/internal/httpclient/model_settings_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// SettingsFlowState show_form: No user data has been collected, or it is invalid, and thus the form should be shown. success: Indicates that the settings flow has been updated successfully with the provided data. Done will stay true when repeatedly checking. If set to true, done will revert back to false only when a flow with invalid (e.g. \"please use a valid phone number\") data was sent. +// SettingsFlowState The experimental state represents the state of a settings flow. This field is EXPERIMENTAL and subject to change! type SettingsFlowState string // List of settingsFlowState diff --git a/internal/httpclient/model_verification_flow_state.go b/internal/httpclient/model_verification_flow_state.go index bea74568c94d..56b65e0c0a5b 100644 --- a/internal/httpclient/model_verification_flow_state.go +++ b/internal/httpclient/model_verification_flow_state.go @@ -16,7 +16,7 @@ import ( "fmt" ) -// VerificationFlowState The state represents the state of the verification flow. choose_method: ask the user to choose a method (e.g. recover account via email) sent_email: the email has been sent to the user passed_challenge: the request was successful and the recovery challenge was passed. +// VerificationFlowState The experimental state represents the state of a verification flow. This field is EXPERIMENTAL and subject to change! type VerificationFlowState string // List of verificationFlowState diff --git a/schema/handler.go b/schema/handler.go index fe2842b14a56..acf6a0dc786a 100644 --- a/schema/handler.go +++ b/schema/handler.go @@ -69,7 +69,16 @@ func (h *Handler) RegisterAdminRoutes(admin *x.RouterAdmin) { // //nolint:deadcode,unused //lint:ignore U1000 Used to generate Swagger and OpenAPI definitions -type identitySchema = json.RawMessage +type identitySchema json.RawMessage + +func (m identitySchema) MarshalJSON() ([]byte, error) { + return json.RawMessage(m).MarshalJSON() +} + +func (m *identitySchema) UnmarshalJSON(data []byte) error { + mm := json.RawMessage(*m) + return mm.UnmarshalJSON(data) +} // Get Identity JSON Schema Response // @@ -151,7 +160,7 @@ type identitySchemaContainer struct { // The ID of the Identity JSON Schema ID string `json:"id"` // The actual Identity JSON Schema - Schema identitySchema `json:"schema"` + Schema json.RawMessage `json:"schema"` } // List Identity JSON Schemas Response diff --git a/schema/handler_test.go b/schema/handler_test.go index 615d8092269d..36aeb3aea75d 100644 --- a/schema/handler_test.go +++ b/schema/handler_test.go @@ -189,7 +189,7 @@ func TestHandler(t *testing.T) { body := getFromTSPaginated(t, 0, 2, http.StatusOK) var result []client.IdentitySchemaContainer - require.NoError(t, json.Unmarshal(body, &result)) + require.NoError(t, json.Unmarshal(body, &result), "%s", body) ids_orig := []string{} for _, s := range schemas { diff --git a/selfservice/strategy/passkey/fixtures/registration/success/android/internal_context.json b/selfservice/strategy/passkey/fixtures/registration/success/android/internal_context.json new file mode 100644 index 000000000000..cd9949ce0093 --- /dev/null +++ b/selfservice/strategy/passkey/fixtures/registration/success/android/internal_context.json @@ -0,0 +1,7 @@ +{ + "passkey_session_data": { + "challenge": "mFtAwmtDDdwcO6200I2H6oWjzOiF21lZhQVlrC4tdaU", + "user_id": "d29OeDNJVjdYR2NRa09RVHhNVG1ZbHE1ejBDYzM1dGV3UWxFT25yaUJKcTUyb0VOR0pUMk5PeXExRXp3Z2M2dg", + "userVerification": "" + } +} diff --git a/selfservice/strategy/passkey/fixtures/registration/success/android/response.json b/selfservice/strategy/passkey/fixtures/registration/success/android/response.json new file mode 100644 index 000000000000..8b480b356790 --- /dev/null +++ b/selfservice/strategy/passkey/fixtures/registration/success/android/response.json @@ -0,0 +1,9 @@ +{ + "id": "mK2RV0b2NUGDsj8QqH0XtQ", + "rawId": "mK2RV0b2NUGDsj8QqH0XtQ", + "response": { + "attestationObject": "o2NmbXRkbm9uZWdhdHRTdG10oGhhdXRoRGF0YViUJYVxRmHaAcJuz7n2X5FJILFPwxIhVpoURyBRglMxnFpdAAAAAOqbjWZNAR0hPOS2tIy1ddQAEJitkVdG9jVBg7I_EKh9F7WlAQIDJiABIVggjEkfDDjIm8yAYfth4u0EV7ApX4kclQONhpK5BLc7W6wiWCCHiHhRNqf8Qhc7bjoIFTqw4lafiC7yrXvojU_WMNcutA", + "clientDataJson": "eyJ0eXBlIjoid2ViYXV0aG4uY3JlYXRlIiwiY2hhbGxlbmdlIjoibUZ0QXdtdEREZHdjTzYyMDBJMkg2b1dqek9pRjIxbFpoUVZsckM0dGRhVSIsIm9yaWdpbiI6ImFuZHJvaWQ6YXBrLWtleS1oYXNoOlMyUmZOWWdKbVFpS2dkNi1zZGJqVzdwaGNMX09UUDR2R0U4TDUxUTJHQjAiLCJhbmRyb2lkUGFja2FnZU5hbWUiOiJjb20udHJwLmFuZC5wZXJzb25hbC5xbCJ9" + }, + "type": "public-key" +} diff --git a/selfservice/strategy/passkey/fixtures/registration/success/identity.json b/selfservice/strategy/passkey/fixtures/registration/success/browser/identity.json similarity index 100% rename from selfservice/strategy/passkey/fixtures/registration/success/identity.json rename to selfservice/strategy/passkey/fixtures/registration/success/browser/identity.json diff --git a/selfservice/strategy/passkey/fixtures/registration/success/internal_context.json b/selfservice/strategy/passkey/fixtures/registration/success/browser/internal_context.json similarity index 100% rename from selfservice/strategy/passkey/fixtures/registration/success/internal_context.json rename to selfservice/strategy/passkey/fixtures/registration/success/browser/internal_context.json diff --git a/selfservice/strategy/passkey/fixtures/registration/success/response.json b/selfservice/strategy/passkey/fixtures/registration/success/browser/response.json similarity index 100% rename from selfservice/strategy/passkey/fixtures/registration/success/response.json rename to selfservice/strategy/passkey/fixtures/registration/success/browser/response.json diff --git a/selfservice/strategy/passkey/passkey_login.go b/selfservice/strategy/passkey/passkey_login.go index b7957a85ad74..5fffcdaac3c3 100644 --- a/selfservice/strategy/passkey/passkey_login.go +++ b/selfservice/strategy/passkey/passkey_login.go @@ -266,8 +266,7 @@ func (s *Strategy) loginAuthenticate(ctx context.Context, r *http.Request, f *lo WithWrap(err))) } - webAuthCreds := o.Credentials.PasswordlessOnly() - + webAuthCreds := o.Credentials.PasswordlessOnly(&webAuthnResponse.Response.AuthenticatorData.Flags) _, err = web.ValidateDiscoverableLogin( func(rawID, userHandle []byte) (user webauthn.User, err error) { return webauthnx.NewUser(userHandle, webAuthCreds, web.Config), nil diff --git a/selfservice/strategy/passkey/passkey_registration_test.go b/selfservice/strategy/passkey/passkey_registration_test.go index 86a7a7992e68..3e0338dcc357 100644 --- a/selfservice/strategy/passkey/passkey_registration_test.go +++ b/selfservice/strategy/passkey/passkey_registration_test.go @@ -8,6 +8,8 @@ import ( "net/url" "testing" + "github.com/ory/x/assertx" + "github.com/ory/kratos/selfservice/flow" "github.com/stretchr/testify/assert" @@ -28,12 +30,21 @@ import ( var ( flows = []string{"spa", "browser"} - //go:embed fixtures/registration/success/response.json + //go:embed fixtures/registration/success/browser/response.json registrationFixtureSuccessResponse []byte - //go:embed fixtures/registration/success/internal_context.json - registrationFixtureSuccessInternalContext []byte + + //go:embed fixtures/registration/success/browser/internal_context.json + registrationFixtureSuccessBrowserInternalContext []byte + + //go:embed fixtures/registration/success/android/response.json + registrationFixtureSuccessAndroidResponse []byte + + //go:embed fixtures/registration/success/android/internal_context.json + registrationFixtureSuccessAndroidInternalContext []byte + //go:embed fixtures/registration/failure/internal_context_missing_user_id.json registrationFixtureFailureInternalContextMissingUserID []byte + //go:embed fixtures/registration/failure/internal_context_wrong_user_id.json registrationFixtureFailureInternalContextWrongUserID []byte ) @@ -180,7 +191,7 @@ func TestRegistration(t *testing.T) { for _, f := range flows { t.Run("type="+f, func(t *testing.T) { - actual, _, _ := fix.submitPasskeyRegistration(t, f, testhelpers.NewClientWithCookies(t), values) + actual, _, _ := fix.submitPasskeyBrowserRegistration(t, f, testhelpers.NewClientWithCookies(t), values) assert.NotEmpty(t, gjson.Get(actual, "id").String(), "%s", actual) assert.Contains(t, gjson.Get(actual, "ui.action").String(), fix.publicTS.URL+registration.RouteSubmitFlow, "%s", actual) registrationhelpers.CheckFormContent(t, []byte(actual), node.PasskeyRegister, "csrf_token", "traits.username", "traits.foobar") @@ -220,7 +231,7 @@ func TestRegistration(t *testing.T) { for _, f := range flows { t.Run("type="+f, func(t *testing.T) { - actual, _, _ := fix.submitPasskeyRegistration(t, f, testhelpers.NewClientWithCookies(t), values, + actual, _, _ := fix.submitPasskeyBrowserRegistration(t, f, testhelpers.NewClientWithCookies(t), values, withInternalContext(sqlxx.JSONRawMessage(tc.internalContext))) if flowIsSPA(f) { assert.Equal(t, "Internal Server Error", gjson.Get(actual, "error.status").String(), "%s", actual) @@ -415,5 +426,49 @@ func TestRegistration(t *testing.T) { }) } }) + + t.Run("case=should create the identity when using android", func(t *testing.T) { + fix.useRedirNoSessionTS() + t.Cleanup(fix.useRedirTS) + fix.disableSessionAfterRegistration() + + prevRPID := fix.conf.GetProvider(fix.ctx).String(config.ViperKeyPasskeyRPID) + prevOrigins := fix.conf.GetProvider(fix.ctx).String(config.ViperKeyPasskeyRPOrigins) + + fix.conf.MustSet(fix.ctx, config.ViperKeyPasskeyRPID, "www.troweprice.com") + fix.conf.MustSet(fix.ctx, config.ViperKeyPasskeyRPOrigins, []string{"android:apk-key-hash:S2RfNYgJmQiKgd6-sdbjW7phcL_OTP4vGE8L51Q2GB0"}) + t.Cleanup(func() { + fix.conf.MustSet(fix.ctx, config.ViperKeyPasskeyRPID, prevRPID) + fix.conf.MustSet(fix.ctx, config.ViperKeyPasskeyRPOrigins, prevOrigins) + }) + + for _, f := range flows { + t.Run("type="+f, func(t *testing.T) { + email := f + "-" + testhelpers.RandomEmail() + userID := f + "-user-" + randx.MustString(8, randx.AlphaNum) + + expectReturnTo := fix.redirNoSessionTS.URL + "/registration-return-ts" + actual, res, _ := fix.submitPasskeyAndroidRegistration(t, f, testhelpers.NewClientWithCookies(t), func(v url.Values) { + values(email)(v) + v.Set(node.PasskeyRegister, string(registrationFixtureSuccessAndroidResponse)) + }, withUserID(userID)) + + if f == "spa" { + expectReturnTo = fix.publicTS.URL + assert.Equal(t, email, gjson.Get(actual, "identity.traits.username").String(), "%s", actual) + assert.False(t, gjson.Get(actual, "session").Exists(), "because the registration yielded no session, the user is not expected to be signed in: %s", actual) + } else { + assert.Equal(t, "null\n", actual, "because the registration yielded no session, the user is not expected to be signed in: %s", actual) + } + + assert.Contains(t, res.Request.URL.String(), expectReturnTo, "%+v\n\t%s", res.Request, assertx.PrettifyJSONPayload(t, actual)) + + i, _, err := fix.reg.PrivilegedIdentityPool().FindByCredentialsIdentifier(fix.ctx, identity.CredentialsTypePasskey, userID) + require.NoError(t, err) + assert.Equal(t, "aal1", i.InternalAvailableAAL.String) + assert.Equal(t, email, gjson.GetBytes(i.Traits, "username").String(), "%s", actual) + }) + } + }) }) } diff --git a/selfservice/strategy/passkey/testfixture_test.go b/selfservice/strategy/passkey/testfixture_test.go index 1f3090177341..3f0fadfd2387 100644 --- a/selfservice/strategy/passkey/testfixture_test.go +++ b/selfservice/strategy/passkey/testfixture_test.go @@ -241,12 +241,6 @@ type submitPasskeyOpt struct { internalContext sqlxx.JSONRawMessage } -func newSubmitPasskeyOpt() *submitPasskeyOpt { - return &submitPasskeyOpt{ - internalContext: registrationFixtureSuccessInternalContext, - } -} - type submitPasskeyOption func(o *submitPasskeyOpt) func withUserID(id string) submitPasskeyOption { @@ -261,6 +255,29 @@ func withInternalContext(ic sqlxx.JSONRawMessage) submitPasskeyOption { } } +func (fix *fixture) submitPasskeyBrowserRegistration( + t *testing.T, + flowType string, + client *http.Client, + cb func(values url.Values), + opts ...submitPasskeyOption, +) (string, *http.Response, *kratos.RegistrationFlow) { + return fix.submitPasskeyRegistration(t, flowType, client, cb, append([]submitPasskeyOption{withInternalContext(registrationFixtureSuccessBrowserInternalContext)}, opts...)...) +} + +func (fix *fixture) submitPasskeyAndroidRegistration( + t *testing.T, + flowType string, + client *http.Client, + cb func(values url.Values), + opts ...submitPasskeyOption, +) (string, *http.Response, *kratos.RegistrationFlow) { + return fix.submitPasskeyRegistration(t, flowType, client, cb, + append([]submitPasskeyOption{withInternalContext( + registrationFixtureSuccessAndroidInternalContext, + )}, opts...)...) +} + func (fix *fixture) submitPasskeyRegistration( t *testing.T, flowType string, @@ -268,7 +285,7 @@ func (fix *fixture) submitPasskeyRegistration( cb func(values url.Values), opts ...submitPasskeyOption, ) (string, *http.Response, *kratos.RegistrationFlow) { - o := newSubmitPasskeyOpt() + o := &submitPasskeyOpt{} for _, fn := range opts { fn(o) } @@ -302,7 +319,7 @@ func (fix *fixture) submitPasskeyRegistration( } func (fix *fixture) makeRegistration(t *testing.T, flowType string, values func(v url.Values), opts ...submitPasskeyOption) (actual string, res *http.Response, fetchedFlow *registration.Flow) { - actual, res, actualFlow := fix.submitPasskeyRegistration(t, flowType, testhelpers.NewClientWithCookies(t), values, opts...) + actual, res, actualFlow := fix.submitPasskeyBrowserRegistration(t, flowType, testhelpers.NewClientWithCookies(t), values, opts...) fetchedFlow, err := fix.reg.RegistrationFlowPersister().GetRegistrationFlow(fix.ctx, uuid.FromStringOrNil(actualFlow.Id)) require.NoError(t, err) diff --git a/selfservice/strategy/webauthn/login.go b/selfservice/strategy/webauthn/login.go index 4279ed48bc96..97fdd1190ab2 100644 --- a/selfservice/strategy/webauthn/login.go +++ b/selfservice/strategy/webauthn/login.go @@ -71,7 +71,7 @@ func (s *Strategy) populateLoginMethod(r *http.Request, sr *login.Flow, i *ident return errors.WithStack(err) } - webAuthCreds := conf.Credentials.ToWebAuthnFiltered(aal) + webAuthCreds := conf.Credentials.ToWebAuthnFiltered(aal, nil) if len(webAuthCreds) == 0 { // Identity has no webauthn return webauthnx.ErrNoCredentials @@ -283,7 +283,7 @@ func (s *Strategy) loginAuthenticate(ctx context.Context, r *http.Request, f *lo return nil, s.handleLoginError(r, f, errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Expected WebAuthN in internal context to be an object but got: %s", err))) } - webAuthCreds := o.Credentials.ToWebAuthnFiltered(aal) + webAuthCreds := o.Credentials.ToWebAuthnFiltered(aal, &webAuthnResponse.Response.AuthenticatorData.Flags) if f.IsRefresh() { webAuthCreds = o.Credentials.ToWebAuthn() } diff --git a/spec/api.json b/spec/api.json index 954aecaab228..907845a46f7c 100644 --- a/spec/api.json +++ b/spec/api.json @@ -1425,13 +1425,13 @@ "type": "object" }, "loginFlowState": { - "description": "The state represents the state of the login flow.\n\nchoose_method: ask the user to choose a method (e.g. login account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the login challenge was passed.", + "description": "The experimental state represents the state of a login flow. This field is EXPERIMENTAL and subject to change!", "enum": [ "choose_method", "sent_email", "passed_challenge" ], - "title": "Login Flow State", + "title": "Login flow state (experimental)", "type": "string" }, "logoutFlow": { @@ -1723,14 +1723,13 @@ "type": "object" }, "recoveryFlowState": { - "description": "The state represents the state of the recovery flow.\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed.", + "description": "The experimental state represents the state of a recovery flow. This field is EXPERIMENTAL and subject to change!", "enum": [ "choose_method", "sent_email", "passed_challenge" ], - "title": "Recovery Flow State", - "type": "string" + "title": "Recovery flow state (experimental)" }, "recoveryIdentityAddress": { "properties": { @@ -1863,13 +1862,13 @@ "type": "object" }, "registrationFlowState": { - "description": "choose_method: ask the user to choose a method (e.g. registration with email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the registration challenge was passed.", + "description": "The experimental state represents the state of a registration flow. This field is EXPERIMENTAL and subject to change!", "enum": [ "choose_method", "sent_email", "passed_challenge" ], - "title": "State represents the state of this request:", + "title": "Registration flow state (experimental)", "type": "string" }, "selfServiceFlowExpiredError": { @@ -2092,12 +2091,12 @@ "type": "object" }, "settingsFlowState": { - "description": "show_form: No user data has been collected, or it is invalid, and thus the form should be shown.\nsuccess: Indicates that the settings flow has been updated successfully with the provided data.\nDone will stay true when repeatedly checking. If set to true, done will revert back to false only\nwhen a flow with invalid (e.g. \"please use a valid phone number\") data was sent.", + "description": "The experimental state represents the state of a settings flow. This field is EXPERIMENTAL and subject to change!", "enum": [ "show_form", "success" ], - "title": "State represents the state of this flow. It knows two states:", + "title": "Settings flow state (experimental)", "type": "string" }, "successfulCodeExchangeResponse": { @@ -3729,14 +3728,13 @@ "type": "object" }, "verificationFlowState": { - "description": "The state represents the state of the verification flow.\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed.", + "description": "The experimental state represents the state of a verification flow. This field is EXPERIMENTAL and subject to change!", "enum": [ "choose_method", "sent_email", "passed_challenge" ], - "title": "Verification Flow State", - "type": "string" + "title": "Verification flow state (experimental)" }, "version": { "properties": { diff --git a/spec/swagger.json b/spec/swagger.json index 8b3d47305a96..031ad06841ba 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -4575,11 +4575,6 @@ } } }, - "loginFlowState": { - "description": "The state represents the state of the login flow.\n\nchoose_method: ask the user to choose a method (e.g. login account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the login challenge was passed.", - "type": "string", - "title": "Login Flow State" - }, "logoutFlow": { "description": "Logout Flow", "type": "object", @@ -4859,11 +4854,6 @@ } } }, - "recoveryFlowState": { - "description": "The state represents the state of the recovery flow.\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed.", - "type": "string", - "title": "Recovery Flow State" - }, "recoveryIdentityAddress": { "type": "object", "required": [ @@ -4994,11 +4984,6 @@ } } }, - "registrationFlowState": { - "description": "choose_method: ask the user to choose a method (e.g. registration with email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the registration challenge was passed.", - "type": "string", - "title": "State represents the state of this request:" - }, "selfServiceFlowExpiredError": { "description": "Is sent when a flow is expired", "type": "object", @@ -5220,11 +5205,6 @@ } } }, - "settingsFlowState": { - "description": "show_form: No user data has been collected, or it is invalid, and thus the form should be shown.\nsuccess: Indicates that the settings flow has been updated successfully with the provided data.\nDone will stay true when repeatedly checking. If set to true, done will revert back to false only\nwhen a flow with invalid (e.g. \"please use a valid phone number\") data was sent.", - "type": "string", - "title": "State represents the state of this flow. It knows two states:" - }, "successfulCodeExchangeResponse": { "description": "The Response for Registration Flows via API", "type": "object", @@ -6698,11 +6678,6 @@ } } }, - "verificationFlowState": { - "description": "The state represents the state of the verification flow.\n\nchoose_method: ask the user to choose a method (e.g. recover account via email)\nsent_email: the email has been sent to the user\npassed_challenge: the request was successful and the recovery challenge was passed.", - "type": "string", - "title": "Verification Flow State" - }, "version": { "type": "object", "properties": { diff --git a/test/e2e/mock/httptarget/go.mod b/test/e2e/mock/httptarget/go.mod index 2d66a9ff4f48..a82d636fb196 100644 --- a/test/e2e/mock/httptarget/go.mod +++ b/test/e2e/mock/httptarget/go.mod @@ -1,6 +1,6 @@ module github.com/ory/mock -go 1.22.1 +go 1.23.1 require ( github.com/julienschmidt/httprouter v1.3.0 From 7093c3b05f1f46b6efbaf60b0291c99ba113dbcd Mon Sep 17 00:00:00 2001 From: ory-bot <60093411+ory-bot@users.noreply.github.com> Date: Wed, 27 Nov 2024 11:35:04 +0000 Subject: [PATCH 3/3] autogen(openapi): regenerate swagger spec and internal client [skip ci] --- internal/client-go/go.sum | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/client-go/go.sum b/internal/client-go/go.sum index 6cc3f5911d11..c966c8ddfd0d 100644 --- a/internal/client-go/go.sum +++ b/internal/client-go/go.sum @@ -4,7 +4,6 @@ github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5y golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e h1:bRhVy7zSSasaqNksaRZiA5EEI+Ei4I1nO5Jh72wfHlg= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4 h1:YUO/7uOKsKeq9UokNS62b8FYywz3ker1l1vDZRCRefw= golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=