Skip to content

Commit

Permalink
Replace device code login with interactive login (#90)
Browse files Browse the repository at this point in the history
* replace device code login with interactive login

* add flag --use-device-code for login command

* add SilenceUsage and fix usage for flag

* extend help for use-device-code

* update help
  • Loading branch information
nilsgstrabo authored Apr 12, 2024
1 parent 01969bf commit f26d0a8
Show file tree
Hide file tree
Showing 5 changed files with 36 additions and 18 deletions.
6 changes: 4 additions & 2 deletions cmd/login.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package cmd

import (
"github.com/equinor/radix-cli/pkg/client"
"github.com/equinor/radix-cli/pkg/flagnames"
"github.com/spf13/cobra"
)

Expand All @@ -25,10 +26,10 @@ var loginCmd = &cobra.Command{
Short: "Login to Radix",
Long: `Login to Radix.`,
RunE: func(cmd *cobra.Command, args []string) error {

cmd.SilenceUsage = true

err := client.LoginCommand(cmd)
useDeviceCode, _ := cmd.Flags().GetBool(flagnames.UseDeviceCode)
err := client.LoginCommand(cmd, useDeviceCode)
if err != nil {
return err
}
Expand All @@ -39,5 +40,6 @@ var loginCmd = &cobra.Command{

func init() {
rootCmd.AddCommand(loginCmd)
loginCmd.Flags().Bool(flagnames.UseDeviceCode, false, "Use CLI's old authentication flow based on device code. The device code flow does not work for compliant device policy enabled accounts.")
setVerbosePersistentFlag(loginCmd)
}
5 changes: 1 addition & 4 deletions pkg/client/auth/client.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,14 @@
package auth

import (
"fmt"

"github.com/AzureAD/microsoft-authentication-library-for-go/apps/public"
radixconfig "github.com/equinor/radix-cli/pkg/config"
)

// newPublicClient creates a new authentication client
func newPublicClient(radixConfig *radixconfig.RadixConfig, clientID, tenantID string) (*public.Client, error) {
func newPublicClient(radixConfig *radixconfig.RadixConfig, clientID, authority string) (*public.Client, error) {
cacheAccessor := NewTokenCache(radixConfig)
cache := public.WithCache(cacheAccessor)
authority := fmt.Sprintf("https://login.microsoftonline.com/%s", tenantID)
client, err := public.New(clientID, cache, public.WithAuthority(authority))
if err != nil {
return nil, err
Expand Down
34 changes: 26 additions & 8 deletions pkg/client/auth/msal_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,24 +13,27 @@ import (

// MSALAuthProvider is an AuthProvider that uses MSAL
type MSALAuthProvider interface {
Login(ctx context.Context) error
Login(ctx context.Context, useDeviceCode bool) error
Logout(ctx context.Context) error
runtime.ClientAuthInfoWriter
}

// NewMSALAuthProvider creates a new MSALAuthProvider
func NewMSALAuthProvider(radixConfig *radixconfig.RadixConfig, clientID, tenantID string) (MSALAuthProvider, error) {
client, err := newPublicClient(radixConfig, clientID, tenantID)
authority := fmt.Sprintf("https://login.microsoftonline.com/%s", tenantID)
client, err := newPublicClient(radixConfig, clientID, authority)
if err != nil {
return nil, err
}
return &msalAuthProvider{
client: client,
client: client,
authority: authority,
}, nil
}

type msalAuthProvider struct {
client *public.Client
authority string
client *public.Client
}

func (provider *msalAuthProvider) AuthenticateRequest(r runtime.ClientRequest, _ strfmt.Registry) error {
Expand All @@ -43,8 +46,12 @@ func (provider *msalAuthProvider) AuthenticateRequest(r runtime.ClientRequest, _

// Login allows the plugin to initialize its configuration. It must not
// require direct user interaction.
func (provider *msalAuthProvider) Login(ctx context.Context) error {
_, err := provider.loginWithDeviceCode(ctx)
func (provider *msalAuthProvider) Login(ctx context.Context, useDeviceCode bool) error {
var loginCmd func(context.Context) (string, error) = provider.loginInteractive
if useDeviceCode {
loginCmd = provider.loginDeviceCode
}
_, err := loginCmd(ctx)
return err
}

Expand Down Expand Up @@ -80,10 +87,21 @@ func (provider *msalAuthProvider) GetToken(ctx context.Context) (string, error)

// either there was no cached account/token or the call to AcquireTokenSilent() failed
// make a new request to AAD
return provider.loginWithDeviceCode(ctx)
return provider.loginInteractive(ctx)
}

func (provider *msalAuthProvider) loginInteractive(ctx context.Context) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 100*time.Second)
defer cancel()
fmt.Printf("A web browser has been opened at %s/oauth2/v2.0/authorize. Please continue the login in the web browser.\n", provider.authority)
result, err := provider.client.AcquireTokenInteractive(ctx, getScopes())
if err != nil {
return "", err
}
return result.AccessToken, nil
}

func (provider *msalAuthProvider) loginWithDeviceCode(ctx context.Context) (string, error) {
func (provider *msalAuthProvider) loginDeviceCode(ctx context.Context) (string, error) {
ctx, cancel := context.WithTimeout(ctx, 100*time.Second)
defer cancel()
devCode, err := provider.client.AcquireTokenByDeviceCode(ctx, getScopes())
Expand Down
8 changes: 4 additions & 4 deletions pkg/client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,8 +84,8 @@ func getAuthWriter(cmd *cobra.Command, config *radixconfig.RadixConfig) (runtime
}

// LoginCommand Login client for command
func LoginCommand(cmd *cobra.Command) error {
return LoginContext()
func LoginCommand(cmd *cobra.Command, useDeviceCode bool) error {
return LoginContext(useDeviceCode)
}

// LogoutCommand Logout command
Expand All @@ -112,7 +112,7 @@ func getContextAndCluster(cmd *cobra.Command) (string, string, error) {
}

// LoginContext Performs login
func LoginContext() error {
func LoginContext(useDeviceCode bool) error {
radixConfig, err := radixconfig.GetRadixConfig()
if err != nil {
return err
Expand All @@ -124,7 +124,7 @@ func LoginContext() error {
if err != nil {
return err
}
return provider.Login(context.Background())
return provider.Login(context.Background(), useDeviceCode)
}

func getAuthProvider(radixConfig *radixconfig.RadixConfig) (auth.MSALAuthProvider, error) {
Expand Down
1 change: 1 addition & 0 deletions pkg/flagnames/names.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ const (
TokenEnvironment = "token-environment"
TokenStdin = "token-stdin"
UseActiveDeployment = "use-active-deployment"
UseDeviceCode = "use-device-code"
User = "user"
Variable = "variable"
Verbose = "verbose"
Expand Down

0 comments on commit f26d0a8

Please sign in to comment.