From 1a8b256cca33aa9cbb143e7e8fc1efc8217e9b8a Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Mon, 28 Feb 2022 19:10:22 +0100 Subject: [PATCH] feat: add `webauthn` to list of identifiers This patch adds the key `webauthn` to the list of possible identifiers in the Identity JSON Schema. Use this key to specify what field is used to find the WebAuthn credentials on passwordless login flows. --- identity/extension_credentials.go | 17 ++++++++++++++ identity/extension_credentials_test.go | 23 +++++++++++++++++-- .../credentials/webauthn.schema.json | 19 +++++++++++++++ schema/extension.go | 3 +++ 4 files changed, 60 insertions(+), 2 deletions(-) create mode 100644 identity/stub/extension/credentials/webauthn.schema.json diff --git a/identity/extension_credentials.go b/identity/extension_credentials.go index 578b0c383528..7c07af9bd120 100644 --- a/identity/extension_credentials.go +++ b/identity/extension_credentials.go @@ -25,6 +25,7 @@ func NewSchemaExtensionCredentials(i *Identity) *SchemaExtensionCredentials { func (r *SchemaExtensionCredentials) Run(_ jsonschema.ValidationContext, s schema.ExtensionConfig, value interface{}) error { r.l.Lock() defer r.l.Unlock() + if s.Credentials.Password.Identifier { cred, ok := r.i.GetCredentials(CredentialsTypePassword) if !ok { @@ -39,6 +40,22 @@ func (r *SchemaExtensionCredentials) Run(_ jsonschema.ValidationContext, s schem cred.Identifiers = r.v r.i.SetCredentials(CredentialsTypePassword, *cred) } + + if s.Credentials.WebAuthn.Identifier { + cred, ok := r.i.GetCredentials(CredentialsTypeWebAuthn) + if !ok { + cred = &Credentials{ + Type: CredentialsTypeWebAuthn, + Identifiers: []string{}, + Config: sqlxx.JSONRawMessage{}, + } + } + + r.v = stringslice.Unique(append(r.v, strings.ToLower(fmt.Sprintf("%s", value)))) + cred.Identifiers = r.v + r.i.SetCredentials(CredentialsTypeWebAuthn, *cred) + } + return nil } diff --git a/identity/extension_credentials_test.go b/identity/extension_credentials_test.go index aea8d13b90ca..3d21b87ad345 100644 --- a/identity/extension_credentials_test.go +++ b/identity/extension_credentials_test.go @@ -25,16 +25,19 @@ func TestSchemaExtensionCredentials(t *testing.T) { doc string expect []string existing *identity.Credentials + ct identity.CredentialsType }{ { doc: `{"email":"foo@ory.sh"}`, schema: "file://./stub/extension/credentials/schema.json", expect: []string{"foo@ory.sh"}, + ct: identity.CredentialsTypePassword, }, { doc: `{"emails":["foo@ory.sh","foo@ory.sh","bar@ory.sh"], "username": "foobar"}`, schema: "file://./stub/extension/credentials/multi.schema.json", expect: []string{"foo@ory.sh", "bar@ory.sh", "foobar"}, + ct: identity.CredentialsTypePassword, }, { doc: `{"emails":["foo@ory.sh","bar@ory.sh"], "username": "foobar"}`, @@ -43,6 +46,22 @@ func TestSchemaExtensionCredentials(t *testing.T) { existing: &identity.Credentials{ Identifiers: []string{"not-foo@ory.sh"}, }, + ct: identity.CredentialsTypePassword, + }, + { + doc: `{"email":"foo@ory.sh"}`, + schema: "file://./stub/extension/credentials/webauthn.schema.json", + expect: []string{"foo@ory.sh"}, + ct: identity.CredentialsTypeWebAuthn, + }, + { + doc: `{"email":"foo@ory.sh"}`, + schema: "file://./stub/extension/credentials/webauthn.schema.json", + expect: []string{"foo@ory.sh"}, + existing: &identity.Credentials{ + Identifiers: []string{"not-foo@ory.sh"}, + }, + ct: identity.CredentialsTypeWebAuthn, }, } { t.Run(fmt.Sprintf("case=%d", k), func(t *testing.T) { @@ -53,7 +72,7 @@ func TestSchemaExtensionCredentials(t *testing.T) { i := new(identity.Identity) e := identity.NewSchemaExtensionCredentials(i) if tc.existing != nil { - i.SetCredentials(identity.CredentialsTypePassword, *tc.existing) + i.SetCredentials(tc.ct, *tc.existing) } runner.AddRunner(e).Register(c) @@ -63,7 +82,7 @@ func TestSchemaExtensionCredentials(t *testing.T) { } require.NoError(t, e.Finish()) - credentials, ok := i.GetCredentials(identity.CredentialsTypePassword) + credentials, ok := i.GetCredentials(tc.ct) require.True(t, ok) assert.ElementsMatch(t, tc.expect, credentials.Identifiers) }) diff --git a/identity/stub/extension/credentials/webauthn.schema.json b/identity/stub/extension/credentials/webauthn.schema.json new file mode 100644 index 000000000000..63e07592bfb6 --- /dev/null +++ b/identity/stub/extension/credentials/webauthn.schema.json @@ -0,0 +1,19 @@ +{ + "type": "object", + "properties": { + "email": { + "type": "string", + "format": "email", + "ory.sh/kratos": { + "credentials": { + "password": { + "identifier": true + }, + "webauthn": { + "identifier": true + } + } + } + } + } +} diff --git a/schema/extension.go b/schema/extension.go index a0427475c1c6..d4a7770ec1b9 100644 --- a/schema/extension.go +++ b/schema/extension.go @@ -21,6 +21,9 @@ type ( Password struct { Identifier bool `json:"identifier"` } `json:"password"` + WebAuthn struct { + Identifier bool `json:"identifier"` + } `json:"webauthn"` TOTP struct { AccountName bool `json:"account_name"` } `json:"totp"`