Skip to content

Commit

Permalink
Re authenticate with common fate during registry sync if token is exp…
Browse files Browse the repository at this point in the history
…ired (#798)

* Re authenticate with common fate during registry sync if token is expired

* Only auto login in interactive mode

* Add a flag to skip profile registry sync

* Apply suggestions from code review

Co-authored-by: Calvin <[email protected]>

---------

Co-authored-by: Calvin <[email protected]>
  • Loading branch information
JoshuaWilkes and ckluy31 authored Nov 11, 2024
1 parent fd86607 commit 062ec34
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 11 deletions.
10 changes: 8 additions & 2 deletions pkg/assume/entrypoint.go
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ func GlobalFlags() []cli.Flag {
&cli.BoolFlag{Name: "wait", Usage: "When using Granted with Common Fate the assume will halt while waiting for the access request to be approved."},
&cli.BoolFlag{Name: "no-cache", Usage: "Disables caching of session credentials and forces a refresh", EnvVars: []string{"GRANTED_NO_CACHE"}},
&cli.StringSliceFlag{Name: "browser-launch-template-arg", Usage: "Additional arguments to provide to the browser launch template command in key=value format, e.g. '--browser-launch-template-arg foo=bar"},
&cli.BoolFlag{Name: "skip-profile-registry-sync", Usage: "You can use this to skip the automated profile registry sync process."},
}
}

Expand Down Expand Up @@ -140,8 +141,13 @@ func GetCliApp() *cli.App {
// terminates the command with os.exit(0)
browser.GrantedIntroduction()
}
// Sync granted profile registries if enabled
autosync.Run(c.Context, true)

if !c.Bool("skip-profile-registry-sync") {
// Sync granted profile registries if enabled
autosync.Run(c.Context, true)
} else {
clio.Debug("skipping profile registry sync because --skip-profile-registry-sync flag was true")
}

// Setup the shell alias
if os.Getenv("FORCE_NO_ALIAS") != "true" {
Expand Down
4 changes: 2 additions & 2 deletions pkg/granted/registry/add.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ var AddCommand = cli.Command{
if err != nil {
return err
}
src, err := registry.AWSProfiles(ctx)
src, err := registry.AWSProfiles(ctx, true)
if err != nil {
return err
}
Expand Down Expand Up @@ -174,7 +174,7 @@ var AddCommand = cli.Command{
if err != nil {
return err
}
src, err := registry.AWSProfiles(ctx)
src, err := registry.AWSProfiles(ctx, true)
if err != nil {
return err
}
Expand Down
49 changes: 45 additions & 4 deletions pkg/granted/registry/cfregistry/cfregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@ package cfregistry

import (
"context"
"fmt"
"strings"
"sync"

"connectrpc.com/connect"
"github.com/common-fate/clio"
"github.com/common-fate/granted/pkg/cfcfg"
awsv1alpha1 "github.com/common-fate/sdk/gen/granted/registry/aws/v1alpha1"
"github.com/common-fate/sdk/gen/granted/registry/aws/v1alpha1/awsv1alpha1connect"
"github.com/common-fate/sdk/loginflow"
grantedv1alpha1 "github.com/common-fate/sdk/service/granted/registry"
"gopkg.in/ini.v1"
)
Expand All @@ -32,7 +36,7 @@ type Opts struct {
// Becuase the Registry is constructed every time the Granted CLI executes,
// calling `config.LoadDefault()` when creating the registry makes Granted very slow.
// Instead, we only obtain an OIDC token if we actually need to load profiles for the registry.
func (r *Registry) getClient() (awsv1alpha1connect.ProfileRegistryServiceClient, error) {
func (r *Registry) getClient(interactive bool) (awsv1alpha1connect.ProfileRegistryServiceClient, error) {
// if the cached
if r.client != nil {
return r.client, nil
Expand All @@ -41,7 +45,24 @@ func (r *Registry) getClient() (awsv1alpha1connect.ProfileRegistryServiceClient,
// Load the config from the deployment URL
cfg, err := cfcfg.LoadURL(context.Background(), r.opts.URL)
if err != nil {
return nil, err
// NOTE(josh): ideally we'll bubble up a more strongly typed error in future here, to avoid the string comparison on the error message.
// the OAuth2.0 token is expired so we should prompt the user to log in
if needsToRefreshLogin(err) {
if interactive {
clio.Infof("You need to log into Common Fate to sync your profile registry")
lf := loginflow.NewFromConfig(cfg)
err = lf.Login(context.Background())
if err != nil {
return nil, err
}
} else {
// in non interactive mode, just return a wrapped error
return nil, fmt.Errorf("you need to log into Common Fate to sync your profile registry using `granted auth login`: %w", err)
}

} else {
return nil, err
}
}

accountClient := grantedv1alpha1.NewFromConfig(cfg)
Expand All @@ -52,6 +73,26 @@ func (r *Registry) getClient() (awsv1alpha1connect.ProfileRegistryServiceClient,

return r.client, nil
}
func needsToRefreshLogin(err error) bool {
if err == nil {
return false
}
if strings.Contains(err.Error(), "oauth2: token expired") {
return true
}
if strings.Contains(err.Error(), "oauth2: invalid grant") {
return true
}
// Sanity check that error message is matching correctly
if strings.Contains(err.Error(), `oauth2: "token_expired"`) {
return true
}
if strings.Contains(err.Error(), `oauth2: "invalid_grant"`) {
return true
}

return false
}

func New(opts Opts) *Registry {
r := Registry{
Expand All @@ -61,8 +102,8 @@ func New(opts Opts) *Registry {
return &r
}

func (r *Registry) AWSProfiles(ctx context.Context) (*ini.File, error) {
client, err := r.getClient()
func (r *Registry) AWSProfiles(ctx context.Context, interactive bool) (*ini.File, error) {
client, err := r.getClient(interactive)
if err != nil {
return nil, err
}
Expand Down
2 changes: 1 addition & 1 deletion pkg/granted/registry/gitregistry/gitregistry.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func New(opts Opts) (*Registry, error) {
return &p, nil
}

func (r Registry) AWSProfiles(ctx context.Context) (*ini.File, error) {
func (r Registry) AWSProfiles(ctx context.Context, interactive bool) (*ini.File, error) {
err := r.pull()
if err != nil {
return nil, err
Expand Down
2 changes: 1 addition & 1 deletion pkg/granted/registry/registry.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
)

type Registry interface {
AWSProfiles(ctx context.Context) (*ini.File, error)
AWSProfiles(ctx context.Context, interactive bool) (*ini.File, error)
}

type loadedRegistry struct {
Expand Down
2 changes: 1 addition & 1 deletion pkg/granted/registry/sync.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ func SyncProfileRegistries(ctx context.Context, interactive bool) error {
m := awsmerge.Merger{}

for _, r := range registries {
src, err := r.Registry.AWSProfiles(ctx)
src, err := r.Registry.AWSProfiles(ctx, interactive)
if err != nil {
return fmt.Errorf("error retrieving AWS profiles for registry %s: %w", r.Config.Name, err)
}
Expand Down

0 comments on commit 062ec34

Please sign in to comment.