From 00f9a823fc8dbaf8529ae996b1da0a4dc479fe7e Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Wed, 24 May 2023 11:28:17 +0200 Subject: [PATCH 1/2] feat: support exporting of all credential types --- .schema/openapi/patches/identity.yaml | 8 ++ examples/go/identity/get/main.go | 2 +- ...ord_and_webauthn_credentials_included.json | 40 ++++++++++ ...ty_with_password_credentials_included.json | 36 +++++++++ ...identity_without_credentials_included.json | 33 ++++++++ ...ls-case=include-multi-credential=oidc.json | 10 +++ ...ase=include-multi-credential=password.json | 13 +++ ...ase=include-multi-credential=webauthn.json | 13 +++ ...case=include-webauthn-credential=oidc.json | 10 +++ ...=include-webauthn-credential=password.json | 10 +++ ...=include-webauthn-credential=webauthn.json | 13 +++ ...tials-case=no-include-credential=oidc.json | 10 +++ ...s-case=no-include-credential=password.json | 10 +++ ...s-case=no-include-credential=webauthn.json | 10 +++ identity/credentials.go | 18 +++++ identity/credentials_test.go | 28 +++++++ identity/handler.go | 30 ++++--- identity/handler_test.go | 27 +++++++ identity/identity.go | 79 ++++++++++--------- identity/identity_test.go | 55 +++++++++++++ spec/api.json | 9 ++- spec/swagger.json | 2 +- 22 files changed, 414 insertions(+), 52 deletions(-) create mode 100644 identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json create mode 100644 identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json create mode 100644 identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=oidc.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=password.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=webauthn.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=oidc.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=password.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=webauthn.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=oidc.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=password.json create mode 100644 identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=webauthn.json diff --git a/.schema/openapi/patches/identity.yaml b/.schema/openapi/patches/identity.yaml index 5c3d2a43c705..a227523488cf 100644 --- a/.schema/openapi/patches/identity.yaml +++ b/.schema/openapi/patches/identity.yaml @@ -11,6 +11,14 @@ - oidc - webauthn - lookup_secret +- op: add + path: /paths/~1admin~1identities~1{id}/get/parameters/1/schema/items/enum + value: + - password + - totp + - oidc + - webauthn + - lookup_secret - op: remove path: /components/schemas/updateIdentityBody/properties/metadata_admin/type - op: remove diff --git a/examples/go/identity/get/main.go b/examples/go/identity/get/main.go index 190985847122..865c72c3a1e7 100644 --- a/examples/go/identity/get/main.go +++ b/examples/go/identity/get/main.go @@ -19,7 +19,7 @@ func getIdentity() *ory.Identity { ctx := context.Background() created := pkg.CreateIdentity(client) - identity, res, err := client.IdentityApi.GetIdentity(ctx, created.Id).Execute() + identity, res, err := client.IdentityApi.GetIdentity(ctx, created.Id).IncludeCredential([]string{"password"}).Execute() pkg.SDKExitOnError(err, res) return identity diff --git a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json new file mode 100644 index 000000000000..ae4336a69ff3 --- /dev/null +++ b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_and_webauthn_credentials_included.json @@ -0,0 +1,40 @@ +{ + "credentials": { + "oidc": { + "type": "oidc", + "identifiers": [ + "bar", + "baz" + ], + "version": 0 + }, + "password": { + "type": "password", + "identifiers": [ + "bar", + "zab" + ], + "config": { + "some": "secret" + }, + "version": 0 + }, + "webauthn": { + "type": "webauthn", + "identifiers": [ + "bar", + "foo" + ], + "config": { + "some": "secret", + "user_handle": "rVIFaWRcTTuQLkXFmQWpgA==" + }, + "version": 1 + } + }, + "schema_id": "default", + "state": "active", + "traits": {}, + "metadata_public": null, + "metadata_admin": null +} diff --git a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json new file mode 100644 index 000000000000..0004001d98f5 --- /dev/null +++ b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_with_password_credentials_included.json @@ -0,0 +1,36 @@ +{ + "credentials": { + "oidc": { + "type": "oidc", + "identifiers": [ + "bar", + "baz" + ], + "version": 0 + }, + "password": { + "type": "password", + "identifiers": [ + "bar", + "zab" + ], + "config": { + "some": "secret" + }, + "version": 0 + }, + "webauthn": { + "type": "webauthn", + "identifiers": [ + "bar", + "foo" + ], + "version": 1 + } + }, + "schema_id": "default", + "state": "active", + "traits": {}, + "metadata_public": null, + "metadata_admin": null +} diff --git a/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json new file mode 100644 index 000000000000..967eec6d8f92 --- /dev/null +++ b/identity/.snapshots/TestHandler-suite=create_and_update-case=should_get_identity_with_credentials-case=should_get_identity_without_credentials_included.json @@ -0,0 +1,33 @@ +{ + "credentials": { + "oidc": { + "type": "oidc", + "identifiers": [ + "bar", + "baz" + ], + "version": 0 + }, + "password": { + "type": "password", + "identifiers": [ + "bar", + "zab" + ], + "version": 0 + }, + "webauthn": { + "type": "webauthn", + "identifiers": [ + "bar", + "foo" + ], + "version": 1 + } + }, + "schema_id": "default", + "state": "active", + "traits": {}, + "metadata_public": null, + "metadata_admin": null +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=oidc.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=oidc.json new file mode 100644 index 000000000000..bb7bf6d73d6a --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=oidc.json @@ -0,0 +1,10 @@ +{ + "type": "oidc", + "identifiers": [ + "bar", + "baz" + ], + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=password.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=password.json new file mode 100644 index 000000000000..c3af78515ade --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=password.json @@ -0,0 +1,13 @@ +{ + "type": "password", + "identifiers": [ + "zab", + "bar" + ], + "config": { + "some": "secret" + }, + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=webauthn.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=webauthn.json new file mode 100644 index 000000000000..f3299b48b43e --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-multi-credential=webauthn.json @@ -0,0 +1,13 @@ +{ + "type": "webauthn", + "identifiers": [ + "foo", + "bar" + ], + "config": { + "some": "secret" + }, + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=oidc.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=oidc.json new file mode 100644 index 000000000000..bb7bf6d73d6a --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=oidc.json @@ -0,0 +1,10 @@ +{ + "type": "oidc", + "identifiers": [ + "bar", + "baz" + ], + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=password.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=password.json new file mode 100644 index 000000000000..1939a8fe4f71 --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=password.json @@ -0,0 +1,10 @@ +{ + "type": "password", + "identifiers": [ + "zab", + "bar" + ], + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=webauthn.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=webauthn.json new file mode 100644 index 000000000000..f3299b48b43e --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=include-webauthn-credential=webauthn.json @@ -0,0 +1,13 @@ +{ + "type": "webauthn", + "identifiers": [ + "foo", + "bar" + ], + "config": { + "some": "secret" + }, + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=oidc.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=oidc.json new file mode 100644 index 000000000000..bb7bf6d73d6a --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=oidc.json @@ -0,0 +1,10 @@ +{ + "type": "oidc", + "identifiers": [ + "bar", + "baz" + ], + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=password.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=password.json new file mode 100644 index 000000000000..1939a8fe4f71 --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=password.json @@ -0,0 +1,10 @@ +{ + "type": "password", + "identifiers": [ + "zab", + "bar" + ], + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=webauthn.json b/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=webauthn.json new file mode 100644 index 000000000000..1b7dcd8f6204 --- /dev/null +++ b/identity/.snapshots/TestWithDeclassifiedCredentials-case=no-include-credential=webauthn.json @@ -0,0 +1,10 @@ +{ + "type": "webauthn", + "identifiers": [ + "foo", + "bar" + ], + "version": 0, + "created_at": "0001-01-01T00:00:00Z", + "updated_at": "0001-01-01T00:00:00Z" +} diff --git a/identity/credentials.go b/identity/credentials.go index d44875e9ff99..cebf80cee17a 100644 --- a/identity/credentials.go +++ b/identity/credentials.go @@ -77,6 +77,24 @@ const ( CredentialsTypeRecoveryCode CredentialsType = "code_recovery" ) +// ParseCredentialsType parses a string into a CredentialsType or returns false as the second argument. +func ParseCredentialsType(in string) (CredentialsType, bool) { + for _, t := range []CredentialsType{ + CredentialsTypePassword, + CredentialsTypeOIDC, + CredentialsTypeTOTP, + CredentialsTypeLookup, + CredentialsTypeWebAuthn, + CredentialsTypeRecoveryLink, + CredentialsTypeRecoveryCode, + } { + if t.String() == in { + return t, true + } + } + return "", false +} + // Credentials represents a specific credential type // // swagger:model identityCredentials diff --git a/identity/credentials_test.go b/identity/credentials_test.go index 2d504d70949c..d6d570f8c22d 100644 --- a/identity/credentials_test.go +++ b/identity/credentials_test.go @@ -6,6 +6,8 @@ package identity import ( "testing" + "github.com/stretchr/testify/require" + "github.com/mohae/deepcopy" "github.com/stretchr/testify/assert" @@ -29,3 +31,29 @@ func TestAALOrder(t *testing.T) { assert.True(t, AuthenticatorAssuranceLevel1 < AuthenticatorAssuranceLevel3) assert.True(t, AuthenticatorAssuranceLevel2 < AuthenticatorAssuranceLevel3) } + +func TestParseCredentialsType(t *testing.T) { + for _, tc := range []struct { + input string + expected CredentialsType + }{ + {"password", CredentialsTypePassword}, + {"oidc", CredentialsTypeOIDC}, + {"totp", CredentialsTypeTOTP}, + {"webauthn", CredentialsTypeWebAuthn}, + {"lookup_secret", CredentialsTypeLookup}, + {"link_recovery", CredentialsTypeRecoveryLink}, + {"code_recovery", CredentialsTypeRecoveryCode}, + } { + t.Run("case="+tc.input, func(t *testing.T) { + actual, ok := ParseCredentialsType(tc.input) + require.True(t, ok) + assert.Equal(t, tc.expected, actual) + }) + } + + t.Run("case=unknown", func(t *testing.T) { + _, ok := ParseCredentialsType("unknown") + require.False(t, ok) + }) +} diff --git a/identity/handler.go b/identity/handler.go index ef36a35d35c2..57d9a61499df 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -204,8 +204,8 @@ type getIdentity struct { // Include Credentials in Response // - // Currently, only `oidc` is supported. This will return the initial OAuth 2.0 Access, - // Refresh and (optionally) OpenID Connect ID Token. + // Include any credential, for example `password` or `oidc`, in the response. When set to `oidc`, This will return + // the initial OAuth 2.0 Access Token, OAuth 2.0 Refresh Token and the OpenID Connect ID Token if available. // // required: false // in: query @@ -241,21 +241,25 @@ func (h *Handler) get(w http.ResponseWriter, r *http.Request, ps httprouter.Para return } - if declassify := r.URL.Query().Get("include_credential"); declassify == "oidc" { - emit, err := i.WithDeclassifiedCredentialsOIDC(r.Context(), h.r) - if err != nil { - h.r.Writer().WriteError(w, r, err) + includeCredentials, _ := r.URL.Query()["include_credential"] + var declassify []CredentialsType + for _, v := range includeCredentials { + tc, ok := ParseCredentialsType(v) + if ok { + declassify = append(declassify, tc) + } else { + h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Invalid value `%s` for parameter `include_credential`.", declassify))) return } - h.r.Writer().Write(w, r, WithCredentialsAndAdminMetadataInJSON(*emit)) - return - } else if len(declassify) > 0 { - h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithReasonf("Invalid value `%s` for parameter `include_credential`.", declassify))) - return - } - h.r.Writer().Write(w, r, WithCredentialsMetadataAndAdminMetadataInJSON(*i)) + emit, err := i.WithDeclassifiedCredentials(r.Context(), h.r, declassify) + if err != nil { + h.r.Writer().WriteError(w, r, err) + return + } + h.r.Writer().Write(w, r, WithCredentialsAndAdminMetadataInJSON(*emit)) + return } // Create Identity Parameters diff --git a/identity/handler_test.go b/identity/handler_test.go index f8d0c1891218..06b956fc63be 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -436,6 +436,33 @@ func TestHandler(t *testing.T) { } }) + t.Run("case=should get identity with credentials", func(t *testing.T) { + i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + credentials := map[identity.CredentialsType]identity.Credentials{ + identity.CredentialsTypePassword: {Identifiers: []string{"zab", "bar"}, Type: identity.CredentialsTypePassword, Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, + identity.CredentialsTypeOIDC: {Type: identity.CredentialsTypeOIDC, Identifiers: []string{"bar", "baz"}, Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}")}, + identity.CredentialsTypeWebAuthn: {Type: identity.CredentialsTypeWebAuthn, Identifiers: []string{"foo", "bar"}, Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\", \"user_handle\": \"rVIFaWRcTTuQLkXFmQWpgA==\"}")}, + } + i.Credentials = credentials + require.NoError(t, reg.PrivilegedIdentityPool().CreateIdentity(context.Background(), i)) + + excludeKeys := snapshotx.ExceptNestedKeys("id", "created_at", "updated_at", "schema_url", "state_changed_at") + t.Run("case=should get identity without credentials included", func(t *testing.T) { + res := get(t, adminTS, "/identities/"+i.ID.String(), http.StatusOK) + snapshotx.SnapshotT(t, json.RawMessage(res.Raw), excludeKeys) + }) + + t.Run("case=should get identity with password credentials included", func(t *testing.T) { + res := get(t, adminTS, "/identities/"+i.ID.String()+"?include_credential=password", http.StatusOK) + snapshotx.SnapshotT(t, json.RawMessage(res.Raw), excludeKeys) + }) + + t.Run("case=should get identity with password and webauthn credentials included", func(t *testing.T) { + res := get(t, adminTS, "/identities/"+i.ID.String()+"?include_credential=password&include_credential=webauthn", http.StatusOK) + snapshotx.SnapshotT(t, json.RawMessage(res.Raw), excludeKeys) + }) + }) + t.Run("case=should pass if no oidc credentials are set", func(t *testing.T) { for name, ts := range map[string]*httptest.Server{"public": publicTS, "admin": adminTS} { t.Run("endpoint="+name, func(t *testing.T) { diff --git a/identity/identity.go b/identity/identity.go index 1d794cc24682..59ce0daedab5 100644 --- a/identity/identity.go +++ b/identity/identity.go @@ -388,58 +388,65 @@ func CollectRecoveryAddresses(i []*Identity) (res []RecoveryAddress) { return res } -func (i *Identity) WithDeclassifiedCredentialsOIDC(ctx context.Context, c cipher.Provider) (*Identity, error) { +func (i *Identity) WithDeclassifiedCredentials(ctx context.Context, c cipher.Provider, includeCredentials []CredentialsType) (*Identity, error) { credsToPublish := make(map[CredentialsType]Credentials) for ct, original := range i.Credentials { - if ct != CredentialsTypeOIDC { + if _, found := lo.Find(includeCredentials, func(i CredentialsType) bool { + return i == ct + }); !found { toPublish := original toPublish.Config = []byte{} credsToPublish[ct] = toPublish continue } - toPublish := original - toPublish.Config = []byte{} - - for _, token := range []string{"initial_id_token", "initial_access_token", "initial_refresh_token"} { - var i int - var err error - gjson.GetBytes(original.Config, "providers").ForEach(func(_, v gjson.Result) bool { - key := fmt.Sprintf("%d.%s", i, token) - ciphertext := v.Get(token).String() - - var plaintext []byte - plaintext, err = c.Cipher(ctx).Decrypt(ctx, ciphertext) - if err != nil { - return false - } - - toPublish.Config, err = sjson.SetBytes(toPublish.Config, "providers."+key, string(plaintext)) - if err != nil { - return false - } + switch ct { + case CredentialsTypeOIDC: + toPublish := original + toPublish.Config = []byte{} - toPublish.Config, err = sjson.SetBytes(toPublish.Config, fmt.Sprintf("providers.%d.subject", i), v.Get("subject").String()) - if err != nil { - return false - } + for _, token := range []string{"initial_id_token", "initial_access_token", "initial_refresh_token"} { + var i int + var err error + gjson.GetBytes(original.Config, "providers").ForEach(func(_, v gjson.Result) bool { + key := fmt.Sprintf("%d.%s", i, token) + ciphertext := v.Get(token).String() + + var plaintext []byte + plaintext, err = c.Cipher(ctx).Decrypt(ctx, ciphertext) + if err != nil { + return false + } + + toPublish.Config, err = sjson.SetBytes(toPublish.Config, "providers."+key, string(plaintext)) + if err != nil { + return false + } + + toPublish.Config, err = sjson.SetBytes(toPublish.Config, fmt.Sprintf("providers.%d.subject", i), v.Get("subject").String()) + if err != nil { + return false + } + + toPublish.Config, err = sjson.SetBytes(toPublish.Config, fmt.Sprintf("providers.%d.provider", i), v.Get("provider").String()) + if err != nil { + return false + } + + i++ + return true + }) - toPublish.Config, err = sjson.SetBytes(toPublish.Config, fmt.Sprintf("providers.%d.provider", i), v.Get("provider").String()) if err != nil { - return false + return nil, err } - i++ - return true - }) - - if err != nil { - return nil, err + credsToPublish[ct] = toPublish } + default: + credsToPublish[ct] = original } - - credsToPublish[ct] = toPublish } ii := *i diff --git a/identity/identity_test.go b/identity/identity_test.go index d050d4f71b8e..b20ee23e1652 100644 --- a/identity/identity_test.go +++ b/identity/identity_test.go @@ -313,3 +313,58 @@ func TestVerifiableAddresses(t *testing.T) { assert.Equal(t, addresses, CollectVerifiableAddresses([]*Identity{id1, id2, id3})) } + +func TestWithDeclassifiedCredentials(t *testing.T) { + i := NewIdentity(config.DefaultIdentityTraitsSchemaID) + credentials := map[CredentialsType]Credentials{ + CredentialsTypePassword: { + Identifiers: []string{"zab", "bar"}, + Type: CredentialsTypePassword, + Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}"), + }, + CredentialsTypeOIDC: { + Type: CredentialsTypeOIDC, + Identifiers: []string{"bar", "baz"}, + Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}"), + }, + CredentialsTypeWebAuthn: { + Type: CredentialsTypeWebAuthn, + Identifiers: []string{"foo", "bar"}, + Config: sqlxx.JSONRawMessage("{\"some\" : \"secret\"}"), + }, + } + i.Credentials = credentials + + t.Run("case=no-include", func(t *testing.T) { + actualIdentity, err := i.WithDeclassifiedCredentials(ctx, nil, nil) + require.NoError(t, err) + + for ct, actual := range actualIdentity.Credentials { + t.Run("credential="+string(ct), func(t *testing.T) { + snapshotx.SnapshotT(t, actual) + }) + } + }) + + t.Run("case=include-webauthn", func(t *testing.T) { + actualIdentity, err := i.WithDeclassifiedCredentials(ctx, nil, []CredentialsType{CredentialsTypeWebAuthn}) + require.NoError(t, err) + + for ct, actual := range actualIdentity.Credentials { + t.Run("credential="+string(ct), func(t *testing.T) { + snapshotx.SnapshotT(t, actual) + }) + } + }) + + t.Run("case=include-multi", func(t *testing.T) { + actualIdentity, err := i.WithDeclassifiedCredentials(ctx, nil, []CredentialsType{CredentialsTypeWebAuthn, CredentialsTypePassword}) + require.NoError(t, err) + + for ct, actual := range actualIdentity.Credentials { + t.Run("credential="+string(ct), func(t *testing.T) { + snapshotx.SnapshotT(t, actual) + }) + } + }) +} diff --git a/spec/api.json b/spec/api.json index 3d694a3acc01..a917e964af61 100755 --- a/spec/api.json +++ b/spec/api.json @@ -3507,11 +3507,18 @@ } }, { - "description": "Include Credentials in Response\n\nCurrently, only `oidc` is supported. This will return the initial OAuth 2.0 Access,\nRefresh and (optionally) OpenID Connect ID Token.", + "description": "Include Credentials in Response\n\nInclude any credential, for example `password` or `oidc`, in the response. When set to `oidc`, This will return\nthe initial OAuth 2.0 Access Token, OAuth 2.0 Refresh Token and the OpenID Connect ID Token if available.", "in": "query", "name": "include_credential", "schema": { "items": { + "enum": [ + "password", + "totp", + "oidc", + "webauthn", + "lookup_secret" + ], "type": "string" }, "type": "array" diff --git a/spec/swagger.json b/spec/swagger.json index 142650176c4c..293a648ac869 100755 --- a/spec/swagger.json +++ b/spec/swagger.json @@ -376,7 +376,7 @@ "items": { "type": "string" }, - "description": "Include Credentials in Response\n\nCurrently, only `oidc` is supported. This will return the initial OAuth 2.0 Access,\nRefresh and (optionally) OpenID Connect ID Token.", + "description": "Include Credentials in Response\n\nInclude any credential, for example `password` or `oidc`, in the response. When set to `oidc`, This will return\nthe initial OAuth 2.0 Access Token, OAuth 2.0 Refresh Token and the OpenID Connect ID Token if available.", "name": "include_credential", "in": "query" } From b7382f35f3985ee3ff23aa61f0c0819ef546faa4 Mon Sep 17 00:00:00 2001 From: aeneasr <3372410+aeneasr@users.noreply.github.com> Date: Wed, 24 May 2023 12:33:01 +0200 Subject: [PATCH 2/2] u --- Makefile | 2 +- identity/handler.go | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/Makefile b/Makefile index ebe0bbec16e4..8ededd59d0d3 100644 --- a/Makefile +++ b/Makefile @@ -48,7 +48,7 @@ docs/swagger: npx @redocly/openapi-cli preview-docs spec/swagger.json .bin/golangci-lint: Makefile - curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.50.1 + curl -sSfL https://raw.githubusercontent.com/golangci/golangci-lint/master/install.sh | sh -s -- -d -b .bin v1.52.2 .bin/hydra: Makefile bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -d -b .bin hydra v2.0.2 diff --git a/identity/handler.go b/identity/handler.go index 57d9a61499df..800edfa47572 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -241,7 +241,7 @@ func (h *Handler) get(w http.ResponseWriter, r *http.Request, ps httprouter.Para return } - includeCredentials, _ := r.URL.Query()["include_credential"] + includeCredentials := r.URL.Query()["include_credential"] var declassify []CredentialsType for _, v := range includeCredentials { tc, ok := ParseCredentialsType(v) @@ -259,7 +259,6 @@ func (h *Handler) get(w http.ResponseWriter, r *http.Request, ps httprouter.Para return } h.r.Writer().Write(w, r, WithCredentialsAndAdminMetadataInJSON(*emit)) - return } // Create Identity Parameters