Skip to content

Commit 83bfb2d

Browse files
authored
fix: error handling on identity import (#3520)
When importing identities without any traits, or with malformed traits, 500s are returned. This improves the error handling and messaging.
1 parent a37f6bd commit 83bfb2d

File tree

7 files changed

+45
-12
lines changed

7 files changed

+45
-12
lines changed

go.mod

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,6 @@ require (
146146
github.com/felixge/httpsnoop v1.0.3 // indirect
147147
github.com/fsnotify/fsnotify v1.6.0 // indirect
148148
github.com/fxamacker/cbor/v2 v2.4.0 // indirect
149-
github.com/go-bindata/go-bindata v3.1.2+incompatible // indirect
150149
github.com/go-crypt/x v0.2.1 // indirect
151150
github.com/go-jose/go-jose/v3 v3.0.0 // indirect
152151
github.com/go-logr/logr v1.2.3 // indirect

go.sum

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,6 @@ github.com/fxamacker/cbor/v2 v2.4.0 h1:ri0ArlOR+5XunOP8CRUowT0pSJOwhW098ZCUyskZD
212212
github.com/fxamacker/cbor/v2 v2.4.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo=
213213
github.com/ghodss/yaml v1.0.0 h1:wQHKEahhL6wmXdzwWG11gIVCkOv05bNOh+Rxn0yngAk=
214214
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
215-
github.com/go-bindata/go-bindata v3.1.2+incompatible h1:5vjJMVhowQdPzjE1LdxyFF7YFTXg5IgGVW4gBr5IbvE=
216-
github.com/go-bindata/go-bindata v3.1.2+incompatible/go.mod h1:xK8Dsgwmeed+BBsSy2XTopBn/8uK2HWuGSnA11C3Joo=
217215
github.com/go-crypt/crypt v0.2.9 h1:5gWWTId2Qyqs9ROIsegt5pnqo9wUSRLbhpkR6JSftjg=
218216
github.com/go-crypt/crypt v0.2.9/go.mod h1:JjzdTYE2mArb6nBoIvvpF7o46/rK/1pfmlArCRMTFUk=
219217
github.com/go-crypt/x v0.2.1 h1:OGw78Bswme9lffCOX6tyuC280ouU5391glsvThMtM5U=
@@ -849,8 +847,6 @@ github.com/ory/nosurf v1.2.7 h1:YrHrbSensQyU6r6HT/V5+HPdVEgrOTMJiLoJABSBOp4=
849847
github.com/ory/nosurf v1.2.7/go.mod h1:d4L3ZBa7Amv55bqxCBtCs63wSlyaiCkWVl4vKf3OUxA=
850848
github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2 h1:zm6sDvHy/U9XrGpixwHiuAwpp0Ock6khSVHkrv6lQQU=
851849
github.com/ory/sessions v1.2.2-0.20220110165800-b09c17334dc2/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM=
852-
github.com/ory/x v0.0.588 h1:3qoC1d7qTKnMLwS3Os7KVbDLeSOUHXON8hUFuGUoScQ=
853-
github.com/ory/x v0.0.588/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM=
854850
github.com/ory/x v0.0.589 h1:ZNQ+nBzTCm3jI2ZZY/1kGWSE4jEtyvDYWu0ScfLgzac=
855851
github.com/ory/x v0.0.589/go.mod h1:ksLBEd6iW6czGpE6eNA0gCIxO1FFeqIxCZgsgwNrzMM=
856852
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"schema_id": "default",
3+
"state": "active",
4+
"traits": {},
5+
"metadata_public": null,
6+
"metadata_admin": null
7+
}

identity/handler.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -409,7 +409,7 @@ type AdminCreateIdentityImportCredentialsOidcProvider struct {
409409
func (h *Handler) create(w http.ResponseWriter, r *http.Request, _ httprouter.Params) {
410410
var cr CreateIdentityBody
411411
if err := jsonx.NewStrictDecoder(r.Body).Decode(&cr); err != nil {
412-
h.r.Writer().WriteErrorCode(w, r, http.StatusBadRequest, errors.WithStack(err))
412+
h.r.Writer().WriteError(w, r, errors.WithStack(herodot.ErrBadRequest.WithError(err.Error())))
413413
return
414414
}
415415

identity/handler_test.go

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -89,9 +89,15 @@ func TestHandler(t *testing.T) {
8989
send := func(t *testing.T, base *httptest.Server, method, href string, expectCode int, send interface{}) gjson.Result {
9090
t.Helper()
9191
var b bytes.Buffer
92-
if send != nil {
93-
require.NoError(t, json.NewEncoder(&b).Encode(send))
92+
switch raw := send.(type) {
93+
case json.RawMessage:
94+
b = *bytes.NewBuffer(raw)
95+
default:
96+
if send != nil {
97+
require.NoError(t, json.NewEncoder(&b).Encode(send))
98+
}
9499
}
100+
95101
req, err := http.NewRequest(method, base.URL+href, &b)
96102
require.NoError(t, err)
97103
req.Header.Set("Content-Type", "application/json")
@@ -190,7 +196,19 @@ func TestHandler(t *testing.T) {
190196
actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String()))
191197
require.NoError(t, err)
192198

193-
snapshotx.SnapshotTExceptMatchingKeys(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), ignoreDefault)
199+
snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...))
200+
})
201+
202+
t.Run("without traits", func(t *testing.T) {
203+
res := send(t, adminTS, "POST", "/identities", http.StatusCreated, json.RawMessage("{}"))
204+
actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String()))
205+
require.NoError(t, err)
206+
207+
snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...))
208+
})
209+
210+
t.Run("with malformed traits", func(t *testing.T) {
211+
send(t, adminTS, "POST", "/identities", http.StatusBadRequest, json.RawMessage(`{"traits": not valid JSON}`))
194212
})
195213

196214
t.Run("with cleartext password and oidc credentials", func(t *testing.T) {
@@ -276,7 +294,7 @@ func TestHandler(t *testing.T) {
276294
actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String()))
277295
require.NoError(t, err)
278296

279-
snapshotx.SnapshotTExceptMatchingKeys(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), append(ignoreDefault, "hashed_password"))
297+
snapshotx.SnapshotT(t, identity.WithCredentialsAndAdminMetadataInJSON(*actual), snapshotx.ExceptNestedKeys(ignoreDefault...), snapshotx.ExceptNestedKeys("hashed_password"))
280298

281299
require.NoError(t, hash.Compare(ctx, []byte(tt.pass), []byte(gjson.GetBytes(actual.Credentials[identity.CredentialsTypePassword].Config, "hashed_password").String())))
282300
})

identity/validator.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@ package identity
66
import (
77
"context"
88

9+
"github.com/pkg/errors"
10+
11+
"github.com/ory/herodot"
12+
913
"github.com/tidwall/sjson"
1014

1115
"github.com/ory/kratos/driver/config"
@@ -47,9 +51,13 @@ func (v *Validator) ValidateWithRunner(ctx context.Context, i *Identity, runners
4751
return err
4852
}
4953

54+
if len(i.Traits) == 0 {
55+
i.Traits = []byte(`{}`)
56+
}
57+
5058
traits, err := sjson.SetRawBytes([]byte(`{}`), "traits", i.Traits)
5159
if err != nil {
52-
return err
60+
return errors.WithStack(herodot.ErrBadRequest.WithError(err.Error()))
5361
}
5462

5563
return v.v.Validate(ctx, s.URL.String(), traits, schema.WithExtensionRunner(runner))

schema/validator.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,12 @@ func (v *Validator) Validate(
6868
return errors.WithStack(herodot.ErrInternalServerError.WithReasonf("Unable to parse validate JSON object against JSON schema.").WithDebugf("%s", err))
6969
}
7070

71-
if err := schema.Validate(bytes.NewBuffer(document)); err != nil {
71+
// we decode explicitly here, so we can handle the error, and it is not lost in the schema validation
72+
dec, err := jsonschema.DecodeJSON(bytes.NewBuffer(document))
73+
if err != nil {
74+
return errors.WithStack(herodot.ErrBadRequest.WithReasonf("Unable to parse validate JSON object against JSON schema.").WithDebugf("%s", err))
75+
}
76+
if err := schema.ValidateInterface(dec); err != nil {
7277
return errors.WithStack(err)
7378
}
7479

0 commit comments

Comments
 (0)