Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: password, social sign, verified email import #2256

Merged
merged 15 commits into from
Feb 26, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,6 @@ test/e2e/.bin
pkged.go
coverage.*
schema.sql

heap_profiler/
goroutine_dump/
inflight_trace_dump/
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ node_modules: package.json Makefile


.bin/golangci-lint: Makefile
bash <(curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh) -d -b .bin v1.28.3
bash <(curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh) -d -b .bin v1.44.2

.bin/hydra: Makefile
bash <(curl https://raw.githubusercontent.com/ory/meta/master/install.sh) -d -b .bin hydra v1.11.0
Expand Down
6 changes: 2 additions & 4 deletions cmd/identities/get_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ import (
"testing"

"github.com/ory/kratos/cmd/identities"
"github.com/ory/kratos/selfservice/strategy/oidc"

"github.com/ory/x/assertx"

"github.com/ory/kratos/x"
Expand Down Expand Up @@ -55,7 +53,7 @@ func TestGetCmd(t *testing.T) {

t.Run("case=gets a single identity with oidc credentials", func(t *testing.T) {
applyCredentials := func(identifier, accessToken, refreshToken, idToken string, encrypt bool) identity.Credentials {
toJson := func(c oidc.CredentialsConfig) []byte {
toJson := func(c identity.CredentialsOIDC) []byte {
out, err := json.Marshal(&c)
require.NoError(t, err)
return out
Expand All @@ -69,7 +67,7 @@ func TestGetCmd(t *testing.T) {
return identity.Credentials{
Type: identity.CredentialsTypeOIDC,
Identifiers: []string{"bar:" + identifier},
Config: toJson(oidc.CredentialsConfig{Providers: []oidc.ProviderCredentialsConfig{
Config: toJson(identity.CredentialsOIDC{Providers: []identity.CredentialsOIDCProvider{
{
Subject: "foo",
Provider: "bar",
Expand Down
6 changes: 3 additions & 3 deletions contrib/quickstart/kratos/cloud/kratos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,10 +66,10 @@ hashers:
cost: 8

identity:
default_schema_id: default
default_schema_id: preset://email
schemas:
- id: default
schema: file:///etc/config/kratos/identity.schema.json
- id: preset://email
url: file:///etc/config/kratos/identity.schema.json

courier:
smtp:
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ require (
github.com/ory/kratos-client-go v0.6.3-alpha.1
github.com/ory/mail/v3 v3.0.0
github.com/ory/nosurf v1.2.7
github.com/ory/x v0.0.348
github.com/ory/x v0.0.351
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2
github.com/pkg/errors v0.9.1
github.com/pquerna/otp v1.3.0
Expand Down
5 changes: 3 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -555,6 +555,7 @@ github.com/envoyproxy/protoc-gen-validate v0.6.1/go.mod h1:txg5va2Qkip90uYoSKH+n
github.com/envoyproxy/protoc-gen-validate v0.6.2 h1:JiO+kJTpmYGjEodY7O1Zk8oZcNz1+f30UtwtXoFUPzE=
github.com/envoyproxy/protoc-gen-validate v0.6.2/go.mod h1:2t7qjJNvHPx8IjnBOzl9E9/baC+qXE/TeeyBRzgJDws=
github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
github.com/evanphx/json-patch v4.9.0+incompatible h1:kLcOMZeuLAJvL2BPWLMIj5oaZQobrkAqrL+WFZwQses=
github.com/evanphx/json-patch v4.9.0+incompatible/go.mod h1:50XU6AFN0ol/bzJsmQLiYLvXMP4fmwYFNcr97nuDLSk=
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU=
Expand Down Expand Up @@ -1804,8 +1805,8 @@ github.com/ory/x v0.0.205/go.mod h1:A1s4iwmFIppRXZLF3J9GGWeY/HpREVm0Dk5z/787iek=
github.com/ory/x v0.0.250/go.mod h1:jUJaVptu+geeqlb9SyQCogTKj5ztSDIF6APkhbKtwLc=
github.com/ory/x v0.0.272/go.mod h1:1TTPgJGQutrhI2OnwdrTIHE9ITSf4MpzXFzA/ncTGRc=
github.com/ory/x v0.0.288/go.mod h1:APpShLyJcVzKw1kTgrHI+j/L9YM+8BRjHlcYObc7C1U=
github.com/ory/x v0.0.348 h1:Z2wbEvSpTindtjKTTrd3grIlWbBtvW2udYG5ZjTZHTo=
github.com/ory/x v0.0.348/go.mod h1:Ddbu3ecSaNDgxdntdD1gDu3ALG5fWR5AwUB1ILeBUNE=
github.com/ory/x v0.0.351 h1:RkiK5MH7rCm461SmHvGJopHWGToTkGLaC8VOrTis6cM=
github.com/ory/x v0.0.351/go.mod h1:zuNjBKtyxFpKnDG6q/1QP0pqQv840P/Dw5JbdY7lNTU=
github.com/otiai10/copy v1.2.0/go.mod h1:rrF5dJ5F0t/EWSYODDu4j9/vEeYHMkc8jt0zJChqQWw=
github.com/otiai10/curr v0.0.0-20150429015615-9b4961190c95/go.mod h1:9qAhocn7zKJG+0mI8eUu6xqkFDYS2kb2saOteoSB3cE=
github.com/otiai10/curr v1.0.0/go.mod h1:LskTG5wDwr8Rs+nNQ+1LlxRjAtTZZjtJW4rMXl6j4vs=
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"credentials": {
"password": {
"type": "password",
"identifiers": [
"[email protected]"
],
"config": {
}
}
},
"schema_id": "default",
"state": "active",
"traits": {
"email": "[email protected]"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"credentials": {
"password": {
"type": "password",
"identifiers": [
"[email protected]"
],
"config": {
}
}
},
"schema_id": "default",
"state": "active",
"traits": {
"email": "[email protected]"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"credentials": {
"oidc": {
"type": "oidc",
"identifiers": [
"google:import-2",
"github:import-2"
],
"config": {
"providers": [
{
"subject": "import-2",
"provider": "google",
"initial_id_token": "",
"initial_access_token": "",
"initial_refresh_token": ""
},
{
"subject": "import-2",
"provider": "github",
"initial_id_token": "",
"initial_access_token": "",
"initial_refresh_token": ""
}
]
}
},
"password": {
"type": "password",
"identifiers": [
"[email protected]"
],
"config": {
}
}
},
"schema_id": "default",
"state": "active",
"traits": {
"email": "[email protected]"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"credentials": {
"password": {
"type": "password",
"identifiers": [
"[email protected]"
],
"config": {
}
}
},
"schema_id": "default",
"state": "active",
"traits": {
"email": "[email protected]"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"credentials": {
"password": {
"type": "password",
"identifiers": [
"[email protected]"
],
"config": {}
}
},
"schema_id": "default",
"state": "active",
"traits": {
"email": "[email protected]"
}
}
57 changes: 57 additions & 0 deletions identity/credentials_oidc.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
package identity

import (
"bytes"
"encoding/json"
"fmt"

"github.com/pkg/errors"

"github.com/ory/kratos/x"
)

// CredentialsOIDC is contains the configuration for credentials of the type oidc.
//
// swagger:model identityCredentialsOidc
type CredentialsOIDC struct {
Providers []CredentialsOIDCProvider `json:"providers"`
}

// CredentialsOIDCProvider is contains a specific OpenID COnnect credential for a particular connection (e.g. Google).
//
// swagger:model identityCredentialsOidcProvider
type CredentialsOIDCProvider struct {
Subject string `json:"subject"`
Provider string `json:"provider"`
InitialIDToken string `json:"initial_id_token"`
InitialAccessToken string `json:"initial_access_token"`
InitialRefreshToken string `json:"initial_refresh_token"`
}

// NewCredentialsOIDC creates a new OIDC credential.
func NewCredentialsOIDC(idToken, accessToken, refreshToken, provider, subject string) (*Credentials, error) {
var b bytes.Buffer
if err := json.NewEncoder(&b).Encode(CredentialsOIDC{
Providers: []CredentialsOIDCProvider{
{
Subject: subject,
Provider: provider,
InitialIDToken: idToken,
InitialAccessToken: accessToken,
InitialRefreshToken: refreshToken,
}},
}); err != nil {
return nil, errors.WithStack(x.PseudoPanic.
WithDebugf("Unable to encode password options to JSON: %s", err))
}

return &Credentials{
Type: CredentialsTypeOIDC,
Identifiers: []string{OIDCUniqueID(provider, subject)},
Config: b.Bytes(),
}, nil
}

func OIDCUniqueID(provider, subject string) string {
return fmt.Sprintf("%s:%s", provider, subject)
}
9 changes: 9 additions & 0 deletions identity/credentials_password.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package identity

// CredentialsPassword is contains the configuration for credentials of the type password.
//
// swagger:model identityCredentialsPassword
type CredentialsPassword struct {
// HashedPassword is a hash-representation of the password.
HashedPassword string `json:"hashed_password"`
}
91 changes: 90 additions & 1 deletion identity/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"net/http"
"time"

"github.com/ory/kratos/hash"

"github.com/ory/kratos/x"

"github.com/ory/kratos/cipher"
Expand Down Expand Up @@ -34,6 +36,7 @@ type (
config.Provider
x.CSRFProvider
cipher.Provider
hash.HashProvider
}
HandlerProvider interface {
IdentityHandler() *Handler
Expand Down Expand Up @@ -202,12 +205,82 @@ type AdminCreateIdentityBody struct {
// required: true
Traits json.RawMessage `json:"traits"`

// Credentials represents all credentials that can be used for authenticating this identity.
//
// Use this structure to import credentials for a user.
Credentials *AdminIdentityImportCredentials `json:"credentials"`

// VerifiableAddresses contains all the addresses that can be verified by the user.
//
// Use this structure to import verified addresses for an identity. Please keep in mind
// that the address needs to be represented in the Identity Schema or this field will be overwritten
// on the next identity update.
VerifiableAddresses []VerifiableAddress `json:"verifiable_addresses"`

// RecoveryAddresses contains all the addresses that can be used to recover an identity.
//
// Use this structure to import recovery addresses for an identity. Please keep in mind
// that the address needs to be represented in the Identity Schema or this field will be overwritten
// on the next identity update.
RecoveryAddresses []RecoveryAddress `json:"recovery_addresses"`

// State is the identity's state.
//
// required: false
State State `json:"state"`
}

// swagger:model adminIdentityImportCredentials
type AdminIdentityImportCredentials struct {
// Password if set will import a password credential.
Password *AdminIdentityImportCredentialsPassword `json:"password"`

// OIDC if set will import an OIDC credential.
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"`

// The password in plain text if no hash is available.
Password string `json:"password"`
}

// 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"`
}

// swagger:model adminCreateIdentityImportCredentialsOidcProvider
type AdminCreateIdentityImportCredentialsOidcProvider struct {
// The subject (`sub`) of the OpenID Connect connection. Usually the `sub` field of the ID Token.
//
// required: true
Subject string `json:"subject"`

// The OpenID Connect provider to link the subject to. Usually something like `google` or `github`.
//
// required: true
Provider string `json:"provider"`
}

// swagger:route POST /identities v0alpha2 adminCreateIdentity
//
// Create an Identity
Expand Down Expand Up @@ -249,7 +322,21 @@ func (h *Handler) create(w http.ResponseWriter, r *http.Request, _ httprouter.Pa
}
state = cr.State
}
i := &Identity{SchemaID: cr.SchemaID, Traits: []byte(cr.Traits), State: state, StateChangedAt: &stateChangedAt}

i := &Identity{
SchemaID: cr.SchemaID,
Traits: []byte(cr.Traits),
State: state,
StateChangedAt: &stateChangedAt,
VerifiableAddresses: cr.VerifiableAddresses,
RecoveryAddresses: cr.RecoveryAddresses,
}

if err := h.importCredentials(r.Context(), i, cr.Credentials); err != nil {
h.r.Writer().WriteError(w, r, err)
return
}

if err := h.r.IdentityManager().Create(r.Context(), i); err != nil {
h.r.Writer().WriteError(w, r, err)
return
Expand Down Expand Up @@ -281,6 +368,8 @@ type adminUpdateIdentity struct {
type AdminUpdateIdentityBody struct {
// SchemaID is the ID of the JSON Schema to be used for validating the identity's traits. If set
// will update the Identity's SchemaID.
//
// required: true
SchemaID string `json:"schema_id"`

// Traits represent an identity's traits. The identity is able to create, modify, and delete traits
Expand Down
Loading