From f3625bb652b26474a3c7fccb5c8b0db9854639b8 Mon Sep 17 00:00:00 2001 From: gloriacai01 Date: Fri, 20 Dec 2024 15:27:49 -0500 Subject: [PATCH 1/4] app-6999 --- cli/app.go | 31 ++++++++++++++ cli/client.go | 58 ++++++++++++++++++++++++++ cli/client_test.go | 39 +++++++++++++++++ testutils/inject/app_service_client.go | 12 ++++++ 4 files changed, 140 insertions(+) diff --git a/cli/app.go b/cli/app.go index 2458b0c1c6d..ef553eaf572 100644 --- a/cli/app.go +++ b/cli/app.go @@ -131,6 +131,8 @@ const ( authApplicationFlagRedirectURIs = "redirect-uris" authApplicationFlagLogoutURI = "logout-uri" + oauthAppFlagClientID = "client-id" + cpFlagRecursive = "recursive" cpFlagPreserve = "preserve" @@ -425,6 +427,35 @@ var app = &cli.App{ Usage: "work with organizations", HideHelpCommand: true, Subcommands: []*cli.Command{ + { + Name: "auth-service", + Usage: "manage auth-service", + Subcommands: []*cli.Command{ + { + Name: "oauth-app", + Usage: "manage the OAuth applications for an organization", + Subcommands: []*cli.Command{ + { + Name: "read", + Usage: "read the OAuth configuration details", + Flags: []cli.Flag{ + &cli.StringFlag{ + Name: generalFlagOrgID, + Required: true, + Usage: "organization ID that is tied to the OAuth application", + }, + &cli.StringFlag{ + Name: oauthAppFlagClientID, + Usage: "id for the OAuth application to be updated", + Required: true, + }, + }, + Action: createCommandWithT[readOAuthAppArgs](ReadOAuthAppAction), + }, + }, + }, + }, + }, { Name: "list", Usage: "list organizations for the current user", diff --git a/cli/client.go b/cli/client.go index 6ffc908bddc..3cf430774d5 100644 --- a/cli/client.go +++ b/cli/client.go @@ -2050,3 +2050,61 @@ func logEntryFieldsToString(fields []*structpb.Struct) (string, error) { } return message + "}", nil } + +type readOAuthAppArgs struct { + OrgID string + ClientID string +} + +const ( + clientAuthenticationPrefix = "CLIENT_AUTHENTICATION_" + pkcePrefix = "PKCE_" + urlValidationPrefix = "URL_VALIDATION_" + enabledGrantPrefix = "ENABLED_GRANT_" +) + +// ReadOAuthAppAction is the corresponding action for 'organizations auth-service oauth-app read'. +func ReadOAuthAppAction(c *cli.Context, args readOAuthAppArgs) error { + client, err := newViamClient(c) + if err != nil { + return err + } + + return client.readOAuthAppAction(c, args.OrgID, args.ClientID) +} + +func (c *viamClient) readOAuthAppAction(cCtx *cli.Context, orgID, clientID string) error { + if err := c.ensureLoggedIn(); err != nil { + return err + } + + req := &apppb.ReadOAuthAppRequest{OrgId: orgID, ClientId: clientID} + resp, err := c.client.ReadOAuthApp(c.c.Context, req) + if err != nil { + return err + } + + config := resp.OauthConfig + printf(cCtx.App.Writer, "OAuth config for client ID %s:", clientID) + printf(cCtx.App.Writer, "") + printf(cCtx.App.Writer, "Client Authentication: %s", protoToString(config.ClientAuthentication.String(), clientAuthenticationPrefix)) + printf(cCtx.App.Writer, "PKCE (Proof Key for Code Exchange): %s", protoToString(config.Pkce.String(), pkcePrefix)) + printf(cCtx.App.Writer, "URL Validation Policy: %s", protoToString(config.UrlValidation.String(), urlValidationPrefix)) + printf(cCtx.App.Writer, "Logout URL: %s", config.LogoutUri) + printf(cCtx.App.Writer, "Redirect URLs: %s", strings.Join(config.RedirectUris, ", ")) + if len(config.OriginUris) > 0 { + printf(cCtx.App.Writer, "Origin URLs: %s", strings.Join(config.OriginUris, ", ")) + } + + var enabledGrants []string + for _, eg := range config.GetEnabledGrants() { + enabledGrants = append(enabledGrants, protoToString(eg.String(), enabledGrantPrefix)) + } + printf(cCtx.App.Writer, "Enabled Grants: %s", strings.Join(enabledGrants, ", ")) + + return nil +} + +func protoToString(protoString, prefixToTrim string) string { + return strings.ToLower(strings.TrimPrefix(protoString, prefixToTrim)) +} diff --git a/cli/client_test.go b/cli/client_test.go index 1402ef6d2cc..1a7fb02f4a8 100644 --- a/cli/client_test.go +++ b/cli/client_test.go @@ -1050,3 +1050,42 @@ func TestShellFileCopy(t *testing.T) { }) }) } + +func TestReadOAuthApp(t *testing.T) { + readOAuthAppFunc := func(ctx context.Context, in *apppb.ReadOAuthAppRequest, opts ...grpc.CallOption) ( + *apppb.ReadOAuthAppResponse, error, + ) { + return &apppb.ReadOAuthAppResponse{ + ClientName: "clientname", + ClientSecret: "fakesecret", + OauthConfig: &apppb.OAuthConfig{ + ClientAuthentication: apppb.ClientAuthentication_CLIENT_AUTHENTICATION_REQUIRED, + Pkce: apppb.PKCE_PKCE_REQUIRED, + UrlValidation: apppb.URLValidation_URL_VALIDATION_ALLOW_WILDCARDS, + LogoutUri: "https://my-logout-uri.com", + OriginUris: []string{"https://my-origin-uri.com", "https://second-origin-uri.com"}, + RedirectUris: []string{"https://my-redirect-uri.com"}, + EnabledGrants: []apppb.EnabledGrant{apppb.EnabledGrant_ENABLED_GRANT_IMPLICIT, apppb.EnabledGrant_ENABLED_GRANT_PASSWORD}, + }, + }, nil + } + + asc := &inject.AppServiceClient{ + ReadOAuthAppFunc: readOAuthAppFunc, + } + + cCtx, ac, out, errOut := setup(asc, nil, nil, nil, nil, "token") + + test.That(t, ac.readOAuthAppAction(cCtx, "test-org-id", "test-client-id"), test.ShouldBeNil) + test.That(t, len(out.messages), test.ShouldEqual, 9) + test.That(t, len(errOut.messages), test.ShouldEqual, 0) + test.That(t, out.messages[0], test.ShouldContainSubstring, "OAuth config for client ID test-client-id") + test.That(t, out.messages[2], test.ShouldContainSubstring, "Client Authentication: required") + test.That(t, out.messages[3], test.ShouldContainSubstring, "PKCE (Proof Key for Code Exchange): required") + test.That(t, out.messages[4], test.ShouldContainSubstring, "URL Validation Policy: allow_wildcards") + test.That(t, out.messages[5], test.ShouldContainSubstring, "Logout URL: https://my-logout-uri.com") + test.That(t, out.messages[6], test.ShouldContainSubstring, "Redirect URLs: https://my-redirect-uri.com") + test.That(t, out.messages[7], test.ShouldContainSubstring, "Origin URLs: https://my-origin-uri.com, https://second-origin-uri.com") + test.That(t, out.messages[8], test.ShouldContainSubstring, "Enabled Grants: implicit, password") + +} diff --git a/testutils/inject/app_service_client.go b/testutils/inject/app_service_client.go index 45f35604723..f16976a035f 100644 --- a/testutils/inject/app_service_client.go +++ b/testutils/inject/app_service_client.go @@ -56,6 +56,8 @@ type AppServiceClient struct { opts ...grpc.CallOption) (*apppb.OrganizationSetLogoResponse, error) OrganizationGetLogoFunc func(ctx context.Context, in *apppb.OrganizationGetLogoRequest, opts ...grpc.CallOption) (*apppb.OrganizationGetLogoResponse, error) + ReadOAuthAppFunc func(ctx context.Context, in *apppb.ReadOAuthAppRequest, + opts ...grpc.CallOption) (*apppb.ReadOAuthAppResponse, error) CreateLocationFunc func(ctx context.Context, in *apppb.CreateLocationRequest, opts ...grpc.CallOption) (*apppb.CreateLocationResponse, error) GetLocationFunc func(ctx context.Context, in *apppb.GetLocationRequest, @@ -403,6 +405,16 @@ func (asc *AppServiceClient) OrganizationGetLogo( return asc.OrganizationGetLogoFunc(ctx, in, opts...) } +// ReadOAuthApp calls the injected ReadOAuthAppFunc or the real version. +func (asc *AppServiceClient) ReadOAuthApp( + ctx context.Context, in *apppb.ReadOAuthAppRequest, opts ...grpc.CallOption, +) (*apppb.ReadOAuthAppResponse, error) { + if asc.ReadOAuthAppFunc == nil { + return asc.AppServiceClient.ReadOAuthApp(ctx, in, opts...) + } + return asc.ReadOAuthAppFunc(ctx, in, opts...) +} + // CreateLocation calls the injected CreateLocationFunc or the real version. func (asc *AppServiceClient) CreateLocation( ctx context.Context, in *apppb.CreateLocationRequest, opts ...grpc.CallOption, From 369373cafa97127f7cd34ac156df5e5174c852f9 Mon Sep 17 00:00:00 2001 From: gloriacai01 Date: Fri, 20 Dec 2024 15:30:48 -0500 Subject: [PATCH 2/4] edit help text --- cli/app.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cli/app.go b/cli/app.go index ef553eaf572..626d3e5f03f 100644 --- a/cli/app.go +++ b/cli/app.go @@ -446,7 +446,7 @@ var app = &cli.App{ }, &cli.StringFlag{ Name: oauthAppFlagClientID, - Usage: "id for the OAuth application to be updated", + Usage: "id for the OAuth application", Required: true, }, }, From 51bbb5e3b4da1d5e5e33e0312488b415a493df21 Mon Sep 17 00:00:00 2001 From: gloriacai01 Date: Wed, 8 Jan 2025 09:27:57 -0500 Subject: [PATCH 3/4] rename to formatStringForOutput --- cli/client.go | 12 ++++-------- cli/utils.go | 4 ++++ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/cli/client.go b/cli/client.go index 3cf430774d5..57d0f791b8b 100644 --- a/cli/client.go +++ b/cli/client.go @@ -2087,9 +2087,9 @@ func (c *viamClient) readOAuthAppAction(cCtx *cli.Context, orgID, clientID strin config := resp.OauthConfig printf(cCtx.App.Writer, "OAuth config for client ID %s:", clientID) printf(cCtx.App.Writer, "") - printf(cCtx.App.Writer, "Client Authentication: %s", protoToString(config.ClientAuthentication.String(), clientAuthenticationPrefix)) - printf(cCtx.App.Writer, "PKCE (Proof Key for Code Exchange): %s", protoToString(config.Pkce.String(), pkcePrefix)) - printf(cCtx.App.Writer, "URL Validation Policy: %s", protoToString(config.UrlValidation.String(), urlValidationPrefix)) + printf(cCtx.App.Writer, "Client Authentication: %s", formatStringForOutput(config.ClientAuthentication.String(), clientAuthenticationPrefix)) + printf(cCtx.App.Writer, "PKCE (Proof Key for Code Exchange): %s", formatStringForOutput(config.Pkce.String(), pkcePrefix)) + printf(cCtx.App.Writer, "URL Validation Policy: %s", formatStringForOutput(config.UrlValidation.String(), urlValidationPrefix)) printf(cCtx.App.Writer, "Logout URL: %s", config.LogoutUri) printf(cCtx.App.Writer, "Redirect URLs: %s", strings.Join(config.RedirectUris, ", ")) if len(config.OriginUris) > 0 { @@ -2098,13 +2098,9 @@ func (c *viamClient) readOAuthAppAction(cCtx *cli.Context, orgID, clientID strin var enabledGrants []string for _, eg := range config.GetEnabledGrants() { - enabledGrants = append(enabledGrants, protoToString(eg.String(), enabledGrantPrefix)) + enabledGrants = append(enabledGrants, formatStringForOutput(eg.String(), enabledGrantPrefix)) } printf(cCtx.App.Writer, "Enabled Grants: %s", strings.Join(enabledGrants, ", ")) return nil } - -func protoToString(protoString, prefixToTrim string) string { - return strings.ToLower(strings.TrimPrefix(protoString, prefixToTrim)) -} diff --git a/cli/utils.go b/cli/utils.go index 94d16624634..67536aff5c6 100644 --- a/cli/utils.go +++ b/cli/utils.go @@ -92,3 +92,7 @@ func parseBillingAddress(address string) (*apppb.BillingAddress, error) { Zipcode: strings.Trim(splitAddress[4], " "), }, nil } + +func formatStringForOutput(protoString, prefixToTrim string) string { + return strings.ToLower(strings.TrimPrefix(protoString, prefixToTrim)) +} From 8d30b1130fa645efe657af0a1a948bbf23cc804e Mon Sep 17 00:00:00 2001 From: gloriacai01 Date: Wed, 8 Jan 2025 12:39:37 -0500 Subject: [PATCH 4/4] linter --- cli/client.go | 3 ++- cli/client_test.go | 1 - 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cli/client.go b/cli/client.go index 688b820df78..82806b2c6f8 100644 --- a/cli/client.go +++ b/cli/client.go @@ -2328,7 +2328,8 @@ func (c *viamClient) readOAuthAppAction(cCtx *cli.Context, orgID, clientID strin config := resp.OauthConfig printf(cCtx.App.Writer, "OAuth config for client ID %s:", clientID) printf(cCtx.App.Writer, "") - printf(cCtx.App.Writer, "Client Authentication: %s", formatStringForOutput(config.ClientAuthentication.String(), clientAuthenticationPrefix)) + printf(cCtx.App.Writer, "Client Authentication: %s", formatStringForOutput(config.ClientAuthentication.String(), + clientAuthenticationPrefix)) printf(cCtx.App.Writer, "PKCE (Proof Key for Code Exchange): %s", formatStringForOutput(config.Pkce.String(), pkcePrefix)) printf(cCtx.App.Writer, "URL Validation Policy: %s", formatStringForOutput(config.UrlValidation.String(), urlValidationPrefix)) printf(cCtx.App.Writer, "Logout URL: %s", config.LogoutUri) diff --git a/cli/client_test.go b/cli/client_test.go index ccfd55177ae..378cad8053e 100644 --- a/cli/client_test.go +++ b/cli/client_test.go @@ -1154,7 +1154,6 @@ func TestReadOAuthApp(t *testing.T) { test.That(t, out.messages[6], test.ShouldContainSubstring, "Redirect URLs: https://my-redirect-uri.com") test.That(t, out.messages[7], test.ShouldContainSubstring, "Origin URLs: https://my-origin-uri.com, https://second-origin-uri.com") test.That(t, out.messages[8], test.ShouldContainSubstring, "Enabled Grants: implicit, password") - } func TestUpdateOAuthAppAction(t *testing.T) {