diff --git a/identity/handler.go b/identity/handler.go index c09ad6a82822..301d5564d9fc 100644 --- a/identity/handler.go +++ b/identity/handler.go @@ -233,14 +233,20 @@ type AdminCreateIdentityBody struct { // swagger:model adminIdentityImportCredentials type AdminIdentityImportCredentials struct { // Password if set will import a password credential. - Password *AdminIdentityImportCredentialsPassword `json:"password,omitempty"` + Password *AdminIdentityImportCredentialsPassword `json:"password"` // OIDC if set will import an OIDC credential. - OIDC *AdminIdentityImportCredentialsOIDC `json:"oidc,omitempty"` + OIDC *AdminIdentityImportCredentialsOIDC `json:"oidc"` } // swagger:model adminCreateIdentityImportCredentialsPassword type AdminIdentityImportCredentialsPassword struct { + // Configuration options for the import. + Config AdminIdentityImportCredentialsPasswordConfig `json:"config"` +} + +// swagger:model adminCreateIdentityImportCredentialsPasswordConfig +type AdminIdentityImportCredentialsPasswordConfig struct { // The hashed password in [PHC format]( https://www.ory.sh/docs/kratos/concepts/credentials/username-email-password#hashed-password-format) HashedPassword string `json:"hashed_password"` @@ -250,6 +256,14 @@ type AdminIdentityImportCredentialsPassword struct { // swagger:model adminCreateIdentityImportCredentialsOidc type AdminIdentityImportCredentialsOIDC struct { + // Configuration options for the import. + Config AdminIdentityImportCredentialsOIDCConfig `json:"config"` +} + +// swagger:model adminCreateIdentityImportCredentialsOidcConfig +type AdminIdentityImportCredentialsOIDCConfig struct { + // Configuration options for the import. + Config AdminIdentityImportCredentialsPasswordConfig `json:"config"` // A list of OpenID Connect Providers Providers []AdminCreateIdentityImportCredentialsOidcProvider `json:"providers"` } diff --git a/identity/handler_import.go b/identity/handler_import.go index e6007275bbe5..e0835f6de710 100644 --- a/identity/handler_import.go +++ b/identity/handler_import.go @@ -34,15 +34,15 @@ func (h *Handler) importCredentials(ctx context.Context, i *Identity, creds *Adm func (h *Handler) importPasswordCredentials(ctx context.Context, i *Identity, creds *AdminIdentityImportCredentialsPassword) (err error) { // In here we deliberately ignore any password policies as the point here is to import passwords, even if they // are not matching the policy, as the user needs to able to sign in with their old password. - hashed := []byte(creds.HashedPassword) - if len(creds.Password) > 0 { + hashed := []byte(creds.Config.HashedPassword) + if len(creds.Config.Password) > 0 { // Importing a clear text password - hashed, err = h.r.Hasher().Generate(ctx, []byte(creds.Password)) + hashed, err = h.r.Hasher().Generate(ctx, []byte(creds.Config.Password)) if err != nil { return err } - creds.HashedPassword = string(hashed) + creds.Config.HashedPassword = string(hashed) } if !(hash.IsArgon2idHash(hashed) || hash.IsBcryptHash(hashed) || hash.IsPbkdf2Hash(hashed)) { @@ -58,7 +58,7 @@ func (h *Handler) importOIDCCredentials(_ context.Context, i *Identity, creds *A if !ok { var providers []CredentialsOIDCProvider var ids []string - for _, p := range creds.Providers { + for _, p := range creds.Config.Providers { ids = append(ids, OIDCUniqueID(p.Provider, p.Subject)) providers = append(providers, CredentialsOIDCProvider{ Subject: p.Subject, @@ -77,7 +77,7 @@ func (h *Handler) importOIDCCredentials(_ context.Context, i *Identity, creds *A return errors.WithStack(x.PseudoPanic.WithWrap(err)) } - for _, p := range creds.Providers { + for _, p := range creds.Config.Providers { c.Identifiers = append(c.Identifiers, OIDCUniqueID(p.Provider, p.Subject)) target.Providers = append(target.Providers, CredentialsOIDCProvider{ Subject: p.Subject, diff --git a/identity/handler_test.go b/identity/handler_test.go index 1681c313634b..32b7b7bcd26d 100644 --- a/identity/handler_test.go +++ b/identity/handler_test.go @@ -165,12 +165,16 @@ func TestHandler(t *testing.T) { res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.AdminCreateIdentityBody{Traits: []byte(`{"email": "import-2@ory.sh"}`), Credentials: &identity.AdminIdentityImportCredentials{ Password: &identity.AdminIdentityImportCredentialsPassword{ - Password: "123456", + Config: identity.AdminIdentityImportCredentialsPasswordConfig{ + Password: "123456", + }, }, OIDC: &identity.AdminIdentityImportCredentialsOIDC{ - Providers: []identity.AdminCreateIdentityImportCredentialsOidcProvider{ - {Subject: "import-2", Provider: "google"}, - {Subject: "import-2", Provider: "github"}, + Config: identity.AdminIdentityImportCredentialsOIDCConfig{ + Providers: []identity.AdminCreateIdentityImportCredentialsOidcProvider{ + {Subject: "import-2", Provider: "google"}, + {Subject: "import-2", Provider: "github"}, + }, }, }, }, @@ -187,7 +191,7 @@ func TestHandler(t *testing.T) { t.Run("with pkbdf2 password", func(t *testing.T) { res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.AdminCreateIdentityBody{Traits: []byte(`{"email": "import-3@ory.sh"}`), Credentials: &identity.AdminIdentityImportCredentials{Password: &identity.AdminIdentityImportCredentialsPassword{ - HashedPassword: "$pbkdf2-sha256$i=1000,l=128$e8/arsEf4cvQihdNgqj0Nw$5xQQKNTyeTHx2Ld5/JDE7A"}}}) + Config: identity.AdminIdentityImportCredentialsPasswordConfig{HashedPassword: "$pbkdf2-sha256$i=1000,l=128$e8/arsEf4cvQihdNgqj0Nw$5xQQKNTyeTHx2Ld5/JDE7A"}}}}) actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) require.NoError(t, err) @@ -199,7 +203,7 @@ func TestHandler(t *testing.T) { t.Run("with bcrypt2 password", func(t *testing.T) { res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.AdminCreateIdentityBody{Traits: []byte(`{"email": "import-4@ory.sh"}`), Credentials: &identity.AdminIdentityImportCredentials{Password: &identity.AdminIdentityImportCredentialsPassword{ - HashedPassword: "$2a$10$ZsCsoVQ3xfBG/K2z2XpBf.tm90GZmtOqtqWcB5.pYd5Eq8y7RlDyq"}}}) + Config: identity.AdminIdentityImportCredentialsPasswordConfig{HashedPassword: "$2a$10$ZsCsoVQ3xfBG/K2z2XpBf.tm90GZmtOqtqWcB5.pYd5Eq8y7RlDyq"}}}}) actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) require.NoError(t, err) @@ -211,7 +215,7 @@ func TestHandler(t *testing.T) { t.Run("with argon2id password", func(t *testing.T) { res := send(t, adminTS, "POST", "/identities", http.StatusCreated, identity.AdminCreateIdentityBody{Traits: []byte(`{"email": "import-5@ory.sh"}`), Credentials: &identity.AdminIdentityImportCredentials{Password: &identity.AdminIdentityImportCredentialsPassword{ - HashedPassword: "$argon2id$v=19$m=16,t=2,p=1$bVI1aE1SaTV6SGQ3bzdXdw$fnjCcZYmEPOUOjYXsT92Cg"}}}) + Config: identity.AdminIdentityImportCredentialsPasswordConfig{HashedPassword: "$argon2id$v=19$m=16,t=2,p=1$bVI1aE1SaTV6SGQ3bzdXdw$fnjCcZYmEPOUOjYXsT92Cg"}}}}) actual, err := reg.PrivilegedIdentityPool().GetIdentityConfidential(ctx, uuid.FromStringOrNil(res.Get("id").String())) require.NoError(t, err) @@ -491,7 +495,7 @@ func TestHandler(t *testing.T) { assert.JSONEq(t, string(cr.Traits), res.Get("traits").Raw, "%s", res.Raw) assert.EqualValues(t, "employee", res.Get("schema_id").String(), "%s", res.Raw) assert.EqualValues(t, identity.StateActive, res.Get("state").String(), "%s", res.Raw) - assert.EqualValues(t, mockServerURL.String()+"/schemas/employee", res.Get("schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, mockServerURL.String()+"/schemas/ZW1wbG95ZWU", res.Get("schema_url").String(), "%s", res.Raw) }) } }) @@ -508,7 +512,7 @@ func TestHandler(t *testing.T) { assert.JSONEq(t, string(cr.Traits), res.Get("traits").Raw, "%s", res.Raw) assert.EqualValues(t, "employee", res.Get("schema_id").String(), "%s", res.Raw) assert.EqualValues(t, identity.StateActive, res.Get("state").String(), "%s", res.Raw) - assert.EqualValues(t, mockServerURL.String()+"/schemas/employee", res.Get("schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, mockServerURL.String()+"/schemas/ZW1wbG95ZWU", res.Get("schema_url").String(), "%s", res.Raw) }) } }) @@ -525,7 +529,7 @@ func TestHandler(t *testing.T) { assert.JSONEq(t, string(cr.Traits), res.Get("traits").Raw, "%s", res.Raw) assert.EqualValues(t, "employee", res.Get("schema_id").String(), "%s", res.Raw) assert.EqualValues(t, identity.StateInactive, res.Get("state").String(), "%s", res.Raw) - assert.EqualValues(t, mockServerURL.String()+"/schemas/employee", res.Get("schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, mockServerURL.String()+"/schemas/ZW1wbG95ZWU", res.Get("schema_url").String(), "%s", res.Raw) }) } }) @@ -548,7 +552,7 @@ func TestHandler(t *testing.T) { }) assert.EqualValues(t, "employee", res.Get("schema_id").String(), "%s", res.Raw) - assert.EqualValues(t, mockServerURL.String()+"/schemas/employee", res.Get("schema_url").String(), "%s", res.Raw) + assert.EqualValues(t, mockServerURL.String()+"/schemas/ZW1wbG95ZWU", res.Get("schema_url").String(), "%s", res.Raw) assert.EqualValues(t, updatedEmail, res.Get("traits.email").String(), "%s", res.Raw) assert.EqualValues(t, "ory", res.Get("traits.department").String(), "%s", res.Raw) assert.EqualValues(t, updatedEmail, res.Get("recovery_addresses.0.value").String(), "%s", res.Raw)