Skip to content

Commit

Permalink
APP-4496: Add cli command to create end user auth applications (viamr…
Browse files Browse the repository at this point in the history
  • Loading branch information
jr22 authored May 10, 2024
1 parent 6564794 commit ef90d24
Show file tree
Hide file tree
Showing 10 changed files with 334 additions and 36 deletions.
91 changes: 91 additions & 0 deletions cli/app.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,12 @@ const (
packageFlagType = "type"
packageFlagDestination = "destination"

authApplicationFlagName = "application-name"
authApplicationFlagApplicationID = "application-id"
authApplicationFlagOriginURIs = "origin-uris"
authApplicationFlagRedirectURIs = "redirect-uris"
authApplicationFlagLogoutURI = "logout-uri"

cpFlagRecursive = "recursive"
cpFlagPreserve = "preserve"
)
Expand Down Expand Up @@ -1639,6 +1645,91 @@ Example:
},
},
},
{
Name: "auth-app",
Usage: "manage third party auth applications",
Subcommands: []*cli.Command{
{
Name: "register",
Usage: "register a third party auth application",
UsageText: createUsageText("auth-app register", []string{
generalFlagOrgID,
authApplicationFlagName, authApplicationFlagOriginURIs, authApplicationFlagRedirectURIs,
authApplicationFlagLogoutURI,
}, false),
Flags: []cli.Flag{
&cli.StringFlag{
Name: generalFlagOrgID,
Usage: "organization ID that will be tied to auth application",
Required: true,
},
&cli.StringFlag{
Name: authApplicationFlagName,
Usage: "name for the auth application",
Required: true,
},
&cli.StringSliceFlag{
Name: authApplicationFlagOriginURIs,
Usage: "origin uris for the auth application",
Required: true,
},
&cli.StringSliceFlag{
Name: authApplicationFlagRedirectURIs,
Usage: "redirect uris for the auth application",
Required: true,
},
&cli.StringFlag{
Name: authApplicationFlagLogoutURI,
Usage: "logout uri for the auth application",
Required: true,
},
},
Action: RegisterAuthApplicationAction,
},
{
Name: "update",
Usage: "update a third party auth application",
UsageText: createUsageText("auth-app update", []string{
generalFlagOrgID,
authApplicationFlagApplicationID, authApplicationFlagName, authApplicationFlagOriginURIs,
authApplicationFlagRedirectURIs, authApplicationFlagLogoutURI,
}, false),
Flags: []cli.Flag{
&cli.StringFlag{
Name: generalFlagOrgID,
Required: true,
Usage: "organization ID that will be tied to auth application",
},
&cli.StringFlag{
Name: authApplicationFlagApplicationID,
Usage: "id for the auth application",
Required: true,
},
&cli.StringFlag{
Name: authApplicationFlagName,
Usage: "updated name for the auth application",
Required: true,
},
&cli.StringSliceFlag{
Name: authApplicationFlagOriginURIs,
Usage: "updated origin uris for the auth application",
Required: false,
},
&cli.StringSliceFlag{
Name: authApplicationFlagRedirectURIs,
Usage: "updated redirect uris for the auth application",
Required: false,
},
&cli.StringFlag{
Name: authApplicationFlagLogoutURI,
Usage: "updated logout uri for the auth application",
Required: false,
},
},
Action: UpdateAuthApplicationAction,
},
},
},
{
Name: "version",
Usage: "print version info for this program",
Expand Down
1 change: 1 addition & 0 deletions cli/auth.go
Original file line number Diff line number Diff line change
Expand Up @@ -501,6 +501,7 @@ func (c *viamClient) ensureLoggedIn() error {
c.dataClient = datapb.NewDataServiceClient(conn)
c.packageClient = packagepb.NewPackageServiceClient(conn)
c.datasetClient = datasetpb.NewDatasetServiceClient(conn)
c.endUserClient = apppb.NewEndUserServiceClient(conn)
c.mlTrainingClient = mltrainingpb.NewMLTrainingServiceClient(conn)
c.buildClient = buildpb.NewBuildServiceClient(conn)

Expand Down
96 changes: 96 additions & 0 deletions cli/auth_application.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
package cli

import (
"encoding/json"

"github.com/urfave/cli/v2"
apppb "go.viam.com/api/app/v1"
)

// RegisterAuthApplicationAction is the corresponding action for 'third-party-auth-app register'.
func RegisterAuthApplicationAction(c *cli.Context) error {
client, err := newViamClient(c)
if err != nil {
return err
}

return client.registerAuthApplicationAction(c)
}

func (c *viamClient) registerAuthApplicationAction(cCtx *cli.Context) error {
if err := c.ensureLoggedIn(); err != nil {
return err
}

orgID := cCtx.String(generalFlagOrgID)
applicationName := cCtx.String(authApplicationFlagName)
originURIs := cCtx.StringSlice(authApplicationFlagOriginURIs)
redirectURIs := cCtx.StringSlice(authApplicationFlagRedirectURIs)
logoutURI := cCtx.String(authApplicationFlagLogoutURI)

req := &apppb.RegisterAuthApplicationRequest{
OrgId: orgID,
ApplicationName: applicationName,
OriginUris: originURIs,
RedirectUris: redirectURIs,
LogoutUri: logoutURI,
}
resp, err := c.endUserClient.RegisterAuthApplication(c.c.Context, req)
if err != nil {
return err
}

infof(cCtx.App.Writer, "Successfully registered auth application")
formatOutput, err := json.MarshalIndent(resp, "", "\t")
if err != nil {
return err
}
printf(cCtx.App.Writer, "%s", formatOutput)
warningf(cCtx.App.Writer, "Keep this information somewhere safe; "+
"it contains the secret to your auth application")
return nil
}

// UpdateAuthApplicationAction is the corresponding action for 'third-party-auth-app update'.
func UpdateAuthApplicationAction(c *cli.Context) error {
client, err := newViamClient(c)
if err != nil {
return err
}

return client.updateAuthApplicationAction(c)
}

func (c *viamClient) updateAuthApplicationAction(cCtx *cli.Context) error {
if err := c.ensureLoggedIn(); err != nil {
return err
}

orgID := cCtx.String(generalFlagOrgID)
applicationID := cCtx.String(authApplicationFlagApplicationID)
applicationName := cCtx.String(authApplicationFlagName)
originURIs := cCtx.StringSlice(authApplicationFlagOriginURIs)
redirectURIs := cCtx.StringSlice(authApplicationFlagRedirectURIs)
logoutURI := cCtx.String(authApplicationFlagLogoutURI)

req := &apppb.UpdateAuthApplicationRequest{
OrgId: orgID,
ApplicationId: applicationID,
ApplicationName: applicationName,
OriginUris: originURIs,
RedirectUris: redirectURIs,
LogoutUri: logoutURI,
}
resp, err := c.endUserClient.UpdateAuthApplication(c.c.Context, req)
if err != nil {
return err
}

infof(cCtx.App.Writer, "Successfully updated auth application")
formatOutput, err := json.MarshalIndent(resp, "", "\t")
if err != nil {
return err
}
printf(cCtx.App.Writer, "%s", formatOutput)
return nil
}
68 changes: 68 additions & 0 deletions cli/auth_application_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package cli

import (
"context"
"testing"

apppb "go.viam.com/api/app/v1"
"go.viam.com/test"
"google.golang.org/grpc"

"go.viam.com/rdk/testutils/inject"
)

func TestRegisterAuthApplicationAction(t *testing.T) {
registerAuthApplicationFunc := func(ctx context.Context, in *apppb.RegisterAuthApplicationRequest,
opts ...grpc.CallOption,
) (*apppb.RegisterAuthApplicationResponse, error) {
return &apppb.RegisterAuthApplicationResponse{
ApplicationId: "c6215428-1b73-41c3-b44a-56db0631c8f1",
ApplicationName: in.ApplicationName,
Secret: "reallysecretsecret",
}, nil
}

eusc := &inject.EndUserServiceClient{
RegisterAuthApplicationFunc: registerAuthApplicationFunc,
}
flags := make(map[string]any)
flags[generalFlagOrgID] = "a757fe30-5648-4c5b-ab74-4ecd6bf06e4c"
flags[authApplicationFlagName] = "pupper_app"
flags[authApplicationFlagOriginURIs] = []string{"https://woof.com/login", "https://arf.com/"}
flags[authApplicationFlagRedirectURIs] = []string{"https://woof.com/home", "https://arf.com/home"}
flags[authApplicationFlagLogoutURI] = "https://woof.com/logout"

cCtx, ac, out, errOut := setup(&inject.AppServiceClient{}, nil, nil, eusc, flags, "token")
err := ac.registerAuthApplicationAction(cCtx)
test.That(t, err, test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
test.That(t, len(out.messages), test.ShouldEqual, 5)
}

func TestUpdateAuthApplicationAction(t *testing.T) {
updateAuthApplication := func(ctx context.Context, in *apppb.UpdateAuthApplicationRequest,
opts ...grpc.CallOption,
) (*apppb.UpdateAuthApplicationResponse, error) {
return &apppb.UpdateAuthApplicationResponse{
ApplicationId: "c6215428-1b73-41c3-b44a-56db0631c8f1",
ApplicationName: in.ApplicationName,
}, nil
}

eusc := &inject.EndUserServiceClient{
UpdateAuthApplicationFunc: updateAuthApplication,
}
flags := make(map[string]any)
flags[generalFlagOrgID] = "a757fe30-5648-4c5b-ab74-4ecd6bf06e4c"
flags[authApplicationFlagApplicationID] = "a673022c-9916-4238-b8eb-4f7a89885909"
flags[authApplicationFlagName] = "pupper_app"
flags[authApplicationFlagOriginURIs] = []string{"https://woof.com/login", "https://arf.com/"}
flags[authApplicationFlagRedirectURIs] = []string{"https://woof.com/home", "https://arf.com/home"}
flags[authApplicationFlagLogoutURI] = "https://woof.com/logout"

cCtx, ac, out, errOut := setup(&inject.AppServiceClient{}, nil, nil, eusc, flags, "token")
err := ac.updateAuthApplicationAction(cCtx)
test.That(t, err, test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
test.That(t, len(out.messages), test.ShouldEqual, 3)
}
20 changes: 10 additions & 10 deletions cli/auth_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import (
)

func TestLoginAction(t *testing.T) {
cCtx, ac, out, errOut := setup(nil, nil, nil, nil, "token")
cCtx, ac, out, errOut := setup(nil, nil, nil, nil, nil, "token")

test.That(t, ac.loginAction(cCtx), test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand All @@ -26,7 +26,7 @@ func TestLoginAction(t *testing.T) {
}

func TestAPIKeyAuth(t *testing.T) {
_, ac, _, errOut := setup(nil, nil, nil, nil, "apiKey")
_, ac, _, errOut := setup(nil, nil, nil, nil, nil, "apiKey")
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
APIKey, isAPIKey := ac.conf.Auth.(*apiKey)
test.That(t, isAPIKey, test.ShouldBeTrue)
Expand All @@ -36,7 +36,7 @@ func TestAPIKeyAuth(t *testing.T) {

func TestPrintAccessTokenAction(t *testing.T) {
// AppServiceClient needed for any Action that calls ensureLoggedIn.
cCtx, ac, out, errOut := setup(&inject.AppServiceClient{}, nil, nil, nil, "token")
cCtx, ac, out, errOut := setup(&inject.AppServiceClient{}, nil, nil, nil, nil, "token")

test.That(t, ac.printAccessTokenAction(cCtx), test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand All @@ -53,7 +53,7 @@ func TestAPIKeyCreateAction(t *testing.T) {
asc := &inject.AppServiceClient{
CreateKeyFunc: createKeyFunc,
}
cCtx, ac, out, errOut := setup(asc, nil, nil, nil, "token")
cCtx, ac, out, errOut := setup(asc, nil, nil, nil, nil, "token")

test.That(t, ac.organizationsAPIKeyCreateAction(cCtx), test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand All @@ -80,7 +80,7 @@ func TestRobotAPIKeyCreateAction(t *testing.T) {
flags[generalFlagOrgID] = fakeOrgID
flags[generalFlagMachineID] = fakeRobotID
flags[apiKeyCreateFlagName] = "my-name"
cCtx, ac, out, errOut := setup(asc, nil, nil, flags, "token")
cCtx, ac, out, errOut := setup(asc, nil, nil, nil, flags, "token")

test.That(t, ac.robotAPIKeyCreateAction(cCtx), test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand Down Expand Up @@ -135,7 +135,7 @@ func TestRobotAPIKeyCreateAction(t *testing.T) {
flags[generalFlagMachineID] = fakeRobotID
flags[generalFlagOrgID] = ""
flags[apiKeyCreateFlagName] = "test-me"
cCtx, ac, out, _ = setup(asc, nil, nil, flags, "token")
cCtx, ac, out, _ = setup(asc, nil, nil, nil, flags, "token")
err = ac.robotAPIKeyCreateAction(cCtx)
test.That(t, err, test.ShouldNotBeNil)

Expand All @@ -162,7 +162,7 @@ func TestLocationAPIKeyCreateAction(t *testing.T) {
flags[generalFlagOrgID] = ""
flags[apiKeyCreateFlagName] = "" // testing no locationID

cCtx, ac, out, errOut := setup(asc, nil, nil, flags, "token")
cCtx, ac, out, errOut := setup(asc, nil, nil, nil, flags, "token")
err := ac.locationAPIKeyCreateAction(cCtx)
test.That(t, err, test.ShouldNotBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand Down Expand Up @@ -203,7 +203,7 @@ func TestLocationAPIKeyCreateAction(t *testing.T) {
flags[generalFlagOrgID] = ""
flags[apiKeyCreateFlagName] = "test-name"

cCtx, ac, _, _ = setup(asc, nil, nil, flags, "token")
cCtx, ac, _, _ = setup(asc, nil, nil, nil, flags, "token")

err = ac.locationAPIKeyCreateAction(cCtx)
test.That(t, err, test.ShouldNotBeNil)
Expand All @@ -212,7 +212,7 @@ func TestLocationAPIKeyCreateAction(t *testing.T) {
}

func TestLogoutAction(t *testing.T) {
cCtx, ac, out, errOut := setup(nil, nil, nil, nil, "token")
cCtx, ac, out, errOut := setup(nil, nil, nil, nil, nil, "token")

test.That(t, ac.logoutAction(cCtx), test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand All @@ -222,7 +222,7 @@ func TestLogoutAction(t *testing.T) {
}

func TestWhoAmIAction(t *testing.T) {
cCtx, ac, out, errOut := setup(nil, nil, nil, nil, "token")
cCtx, ac, out, errOut := setup(nil, nil, nil, nil, nil, "token")

test.That(t, ac.whoAmIAction(cCtx), test.ShouldBeNil)
test.That(t, len(errOut.messages), test.ShouldEqual, 0)
Expand Down
1 change: 1 addition & 0 deletions cli/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@ type viamClient struct {
dataClient datapb.DataServiceClient
packageClient packagepb.PackageServiceClient
datasetClient datasetpb.DatasetServiceClient
endUserClient apppb.EndUserServiceClient
mlTrainingClient mltrainingpb.MLTrainingServiceClient
buildClient buildpb.BuildServiceClient
baseURL *url.URL
Expand Down
Loading

0 comments on commit ef90d24

Please sign in to comment.