From 1acdcfe3ea4ae64beedd1766bde6961daaf5fafe Mon Sep 17 00:00:00 2001 From: Protocole Date: Sat, 4 Dec 2021 20:01:59 +0100 Subject: [PATCH 1/3] feat(cmd): add oidc credential include --- cmd/identities/get.go | 32 ++++++++++++++++++++--- cmd/identities/get_test.go | 53 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 3 deletions(-) diff --git a/cmd/identities/get.go b/cmd/identities/get.go index 148bbdcb49ac..ba19fec4b2e5 100644 --- a/cmd/identities/get.go +++ b/cmd/identities/get.go @@ -2,10 +2,10 @@ package identities import ( "fmt" - kratos "github.com/ory/kratos-client-go" "github.com/ory/kratos/x" "github.com/ory/x/cmdx" + "github.com/ory/x/stringsx" "github.com/ory/kratos/internal/clihelpers" @@ -14,8 +14,16 @@ import ( "github.com/ory/kratos/cmd/cliclient" ) +const ( + FlagIncludeCreds = "include-credentials" +) + func NewGetCmd() *cobra.Command { - return &cobra.Command{ + var ( + includeCreds []string + ) + + cmd := &cobra.Command{ Use: "get ", Short: "Get one or more identities by ID", Long: fmt.Sprintf(`This command gets all the details about an identity. To get an identity by some selector, e.g. the recovery email address, use the list command in combination with jq. @@ -29,10 +37,23 @@ func NewGetCmd() *cobra.Command { RunE: func(cmd *cobra.Command, args []string) error { c := cliclient.NewClient(cmd) + // we check includeCreds argument is valid + for _, opt := range includeCreds { + e := stringsx.SwitchExact(opt) + if !e.AddCase("oidc") { + cmd.PrintErrln(`You have to put a valid value of credentials type to be included, try --help for details.`) + return nil + } + } + identities := make([]kratos.Identity, 0, len(args)) failed := make(map[string]error) for _, id := range args { - identity, _, err := c.V0alpha2Api.AdminGetIdentity(cmd.Context(), id).Execute() + identity, _, err := c.V0alpha2Api. + AdminGetIdentity(cmd.Context(), id). + IncludeCredential(includeCreds). + Execute() + if x.SDKError(err) != nil { failed[id] = err continue @@ -54,4 +75,9 @@ func NewGetCmd() *cobra.Command { return nil }, } + + flags := cmd.Flags() + // include credential flag to add third party tokens in returned data + flags.StringArrayVarP(&includeCreds, FlagIncludeCreds, "i", []string{}, `Include third party tokens (only "oidc" supported) `) + return cmd } diff --git a/cmd/identities/get_test.go b/cmd/identities/get_test.go index 6369517153d8..911da181e28f 100644 --- a/cmd/identities/get_test.go +++ b/cmd/identities/get_test.go @@ -2,10 +2,12 @@ package identities_test import ( "context" + "encoding/hex" "encoding/json" "testing" "github.com/ory/kratos/cmd/identities" + "github.com/ory/kratos/selfservice/strategy/oidc" "github.com/ory/x/assertx" @@ -50,4 +52,55 @@ func TestGetCmd(t *testing.T) { assert.Contains(t, stdErr, "404 Not Found", stdErr) }) + + 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 { + out, err := json.Marshal(&c) + require.NoError(t, err) + return out + } + transform := func(token string) string { + if !encrypt { + return token + } + return hex.EncodeToString([]byte(token)) + } + return identity.Credentials{ + Type: identity.CredentialsTypeOIDC, + Identifiers: []string{"bar:" + identifier}, + Config: toJson(oidc.CredentialsConfig{Providers: []oidc.ProviderCredentialsConfig{ + { + Subject: "foo", + Provider: "bar", + InitialAccessToken: transform(accessToken + "0"), + InitialRefreshToken: transform(refreshToken + "0"), + InitialIDToken: transform(idToken + "0"), + }, + { + Subject: "baz", + Provider: "zab", + InitialAccessToken: transform(accessToken + "1"), + InitialRefreshToken: transform(refreshToken + "1"), + InitialIDToken: transform(idToken + "1"), + }, + }}), + } + } + i := identity.NewIdentity(config.DefaultIdentityTraitsSchemaID) + i.SetCredentials(identity.CredentialsTypeOIDC, applyCredentials("uniqueIdentifier", "accessBar", "refreshBar", "idBar", true)) + // duplicate identity with decrypted tokens + di := i.CopyWithoutCredentials() + di.SetCredentials(identity.CredentialsTypeOIDC, applyCredentials("uniqueIdentifier", "accessBar", "refreshBar", "idBar", false)) + + require.NoError(t, c.Flags().Set(identities.FlagIncludeCreds, "oidc")) + require.NoError(t, reg.Persister().CreateIdentity(context.Background(), i)) + + stdOut := execNoErr(t, c, i.ID.String()) + ij, err := json.Marshal(identity.WithCredentialsInJSON(*di)) + require.NoError(t, err) + + ii := []string{"schema_url", "state_changed_at", "created_at", "updated_at", "credentials.oidc.created_at", "credentials.oidc.updated_at"} + assertx.EqualAsJSONExcept(t, json.RawMessage(ij), json.RawMessage(stdOut), ii) + }) } From dc7737393aebda066b8034ff1dad44e2fc9a1559 Mon Sep 17 00:00:00 2001 From: Patrik Date: Mon, 6 Dec 2021 10:57:29 +0100 Subject: [PATCH 2/3] fix: return error instead of nil --- cmd/identities/get.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/identities/get.go b/cmd/identities/get.go index ba19fec4b2e5..bf107b8961fa 100644 --- a/cmd/identities/get.go +++ b/cmd/identities/get.go @@ -42,7 +42,7 @@ func NewGetCmd() *cobra.Command { e := stringsx.SwitchExact(opt) if !e.AddCase("oidc") { cmd.PrintErrln(`You have to put a valid value of credentials type to be included, try --help for details.`) - return nil + return cmdx.FailSilently(cmd) } } From e4ab754859d8b3e5ffd742396e9fa3cafba2978d Mon Sep 17 00:00:00 2001 From: zepatrik Date: Mon, 6 Dec 2021 12:01:42 +0100 Subject: [PATCH 3/3] chore: format --- cmd/identities/get.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/identities/get.go b/cmd/identities/get.go index bf107b8961fa..d4f8c8faf406 100644 --- a/cmd/identities/get.go +++ b/cmd/identities/get.go @@ -2,6 +2,7 @@ package identities import ( "fmt" + kratos "github.com/ory/kratos-client-go" "github.com/ory/kratos/x" "github.com/ory/x/cmdx"