From 76bbe0e4716b576fed046e1f5c0a488f0e519fbc Mon Sep 17 00:00:00 2001 From: Sebastien Le Digabel Date: Fri, 14 Jan 2022 23:25:24 +0000 Subject: [PATCH] Use Idp Account Name as key for credentials store At the moment the credentials are stored using the idp server url as a primary key for the keychain store. This is very useful if you need to authenticate through different providers or environment (and thus different endpoints), however this prevents the use case where users may want to use different idp accounts to authenticate using different users. A typical example of this is that some users often have a normal user and an admin user with different properties, roles and limitations. This change is refactoring how credentials are stored across the code base to use the idp Name instead of the server URL. --- cmd/saml2aws/commands/configure.go | 9 ++-- cmd/saml2aws/commands/list_roles.go | 4 +- cmd/saml2aws/commands/login.go | 17 +++--- cmd/saml2aws/commands/login_test.go | 64 +++++++++++++++++++---- helper/credentials/credentials.go | 23 +++++--- helper/credentials/saml.go | 19 +++---- helper/linuxkeyring/linuxkeyring_linux.go | 10 ++-- helper/osxkeychain/osxkeychain.go | 31 ++++------- helper/osxkeychain/osxkeychain_test.go | 8 +-- helper/wincred/wincred_windows.go | 10 ++-- pkg/creds/creds.go | 2 + pkg/provider/okta/okta.go | 4 +- pkg/provider/okta/okta_test.go | 1 + 13 files changed, 128 insertions(+), 74 deletions(-) diff --git a/cmd/saml2aws/commands/configure.go b/cmd/saml2aws/commands/configure.go index a8f9fc7c2..29bf3a684 100644 --- a/cmd/saml2aws/commands/configure.go +++ b/cmd/saml2aws/commands/configure.go @@ -6,7 +6,7 @@ import ( "path" "github.com/pkg/errors" - "github.com/versent/saml2aws/v2" + saml2aws "github.com/versent/saml2aws/v2" "github.com/versent/saml2aws/v2/helper/credentials" "github.com/versent/saml2aws/v2/pkg/cfg" "github.com/versent/saml2aws/v2/pkg/flags" @@ -68,14 +68,14 @@ func storeCredentials(configFlags *flags.CommonFlags, account *cfg.IDPAccount) e return nil } if configFlags.Password != "" { - if err := credentials.SaveCredentials(account.URL, account.Username, configFlags.Password); err != nil { + if err := credentials.SaveCredentials(account.Name, account.URL, account.Username, configFlags.Password); err != nil { return errors.Wrap(err, "error storing password in keychain") } } else { password := prompter.Password("Password") if password != "" { if confirmPassword := prompter.Password("Confirm"); confirmPassword == password { - if err := credentials.SaveCredentials(account.URL, account.Username, password); err != nil { + if err := credentials.SaveCredentials(account.Name, account.URL, account.Username, password); err != nil { return errors.Wrap(err, "error storing password in keychain") } } else { @@ -91,7 +91,8 @@ func storeCredentials(configFlags *flags.CommonFlags, account *cfg.IDPAccount) e log.Println("OneLogin provider requires --client-id and --client-secret flags to be set.") os.Exit(1) } - if err := credentials.SaveCredentials(path.Join(account.URL, OneLoginOAuthPath), configFlags.ClientID, configFlags.ClientSecret); err != nil { + // we store the OneLogin token in a different secret (idpName + the one login suffix) + if err := credentials.SaveCredentials(account.Name+credentials.OneLoginTokenSuffix, path.Join(account.URL, OneLoginOAuthPath), configFlags.ClientID, configFlags.ClientSecret); err != nil { return errors.Wrap(err, "error storing client_id and client_secret in keychain") } } diff --git a/cmd/saml2aws/commands/list_roles.go b/cmd/saml2aws/commands/list_roles.go index a8a20b925..5fe5fd0a3 100644 --- a/cmd/saml2aws/commands/list_roles.go +++ b/cmd/saml2aws/commands/list_roles.go @@ -8,7 +8,7 @@ import ( "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/versent/saml2aws/v2" + saml2aws "github.com/versent/saml2aws/v2" "github.com/versent/saml2aws/v2/helper/credentials" "github.com/versent/saml2aws/v2/pkg/flags" "github.com/versent/saml2aws/v2/pkg/samlcache" @@ -83,7 +83,7 @@ func ListRoles(loginFlags *flags.LoginExecFlags) error { } if !loginFlags.CommonFlags.DisableKeychain { - err = credentials.SaveCredentials(loginDetails.URL, loginDetails.Username, loginDetails.Password) + err = credentials.SaveCredentials(loginDetails.IdpName, loginDetails.URL, loginDetails.Username, loginDetails.Password) if err != nil { return errors.Wrap(err, "error storing password in keychain") } diff --git a/cmd/saml2aws/commands/login.go b/cmd/saml2aws/commands/login.go index 0a7766a4e..981063bea 100644 --- a/cmd/saml2aws/commands/login.go +++ b/cmd/saml2aws/commands/login.go @@ -14,7 +14,7 @@ import ( "github.com/aws/aws-sdk-go/service/sts" "github.com/pkg/errors" "github.com/sirupsen/logrus" - "github.com/versent/saml2aws/v2" + saml2aws "github.com/versent/saml2aws/v2" "github.com/versent/saml2aws/v2/helper/credentials" "github.com/versent/saml2aws/v2/pkg/awsconfig" "github.com/versent/saml2aws/v2/pkg/cfg" @@ -122,7 +122,7 @@ func Login(loginFlags *flags.LoginExecFlags) error { } if !loginFlags.CommonFlags.DisableKeychain { - err = credentials.SaveCredentials(loginDetails.URL, loginDetails.Username, loginDetails.Password) + err = credentials.SaveCredentials(loginDetails.IdpName, loginDetails.URL, loginDetails.Username, loginDetails.Password) if err != nil { return errors.Wrap(err, "Error storing password in keychain.") } @@ -174,15 +174,20 @@ func buildIdpAccount(loginFlags *flags.LoginExecFlags) (*cfg.IDPAccount, error) func resolveLoginDetails(account *cfg.IDPAccount, loginFlags *flags.LoginExecFlags) (*creds.LoginDetails, error) { - // log.Printf("loginFlags %+v", loginFlags) - - loginDetails := &creds.LoginDetails{URL: account.URL, Username: account.Username, MFAToken: loginFlags.CommonFlags.MFAToken, DuoMFAOption: loginFlags.DuoMFAOption} + loginDetails := &creds.LoginDetails{ + URL: account.URL, + Username: account.Username, + MFAToken: loginFlags.CommonFlags.MFAToken, + DuoMFAOption: loginFlags.DuoMFAOption, + IdpName: account.Name, + IdpProvider: account.Provider, + } log.Printf("Using IdP Account %s to access %s %s", loginFlags.CommonFlags.IdpAccount, account.Provider, account.URL) var err error if !loginFlags.CommonFlags.DisableKeychain { - err = credentials.LookupCredentials(loginDetails, account.Provider) + err = credentials.LookupCredentials(loginDetails) if err != nil { if !credentials.IsErrCredentialsNotFound(err) { return nil, errors.Wrap(err, "Error loading saved password.") diff --git a/cmd/saml2aws/commands/login_test.go b/cmd/saml2aws/commands/login_test.go index bca0442cf..2a9446318 100644 --- a/cmd/saml2aws/commands/login_test.go +++ b/cmd/saml2aws/commands/login_test.go @@ -6,7 +6,8 @@ import ( "time" "github.com/stretchr/testify/assert" - "github.com/versent/saml2aws/v2" + + saml2aws "github.com/versent/saml2aws/v2" "github.com/versent/saml2aws/v2/pkg/awsconfig" "github.com/versent/saml2aws/v2/pkg/cfg" "github.com/versent/saml2aws/v2/pkg/creds" @@ -14,11 +15,18 @@ import ( ) func TestResolveLoginDetailsWithFlags(t *testing.T) { + commonFlags := &flags.CommonFlags{ + URL: "https://id.example.com", + Username: "wolfeidau", + Password: "testtestlol", + MFAToken: "123456", + SkipPrompt: true, + } - commonFlags := &flags.CommonFlags{URL: "https://id.example.com", Username: "wolfeidau", Password: "testtestlol", MFAIPAddress: "127.0.0.1", MFAToken: "123456", SkipPrompt: true} loginFlags := &flags.LoginExecFlags{CommonFlags: commonFlags} idpa := &cfg.IDPAccount{ + Name: "AccountName", URL: "https://id.example.com", MFA: "none", Provider: "Ping", @@ -27,16 +35,30 @@ func TestResolveLoginDetailsWithFlags(t *testing.T) { loginDetails, err := resolveLoginDetails(idpa, loginFlags) assert.Empty(t, err) - assert.Equal(t, &creds.LoginDetails{Username: "wolfeidau", Password: "testtestlol", URL: "https://id.example.com", MFAToken: "123456", MFAIPAddress: "127.0.0.1"}, loginDetails) + assert.Equal(t, + &creds.LoginDetails{ + IdpName: "AccountName", + IdpProvider: "Ping", + Username: "wolfeidau", + Password: "testtestlol", + URL: "https://id.example.com", + MFAToken: "123456", + }, loginDetails) } func TestOktaResolveLoginDetailsWithFlags(t *testing.T) { - // Default state - user did not supply values for DisableSessions and DisableSessions - commonFlags := &flags.CommonFlags{URL: "https://id.example.com", Username: "testuser", Password: "testtestlol", MFAToken: "123456", SkipPrompt: true} + commonFlags := &flags.CommonFlags{ + URL: "https://id.example.com", + Username: "testuser", + Password: "testtestlol", + MFAToken: "123456", + SkipPrompt: true, + } loginFlags := &flags.LoginExecFlags{CommonFlags: commonFlags} idpa := &cfg.IDPAccount{ + Name: "AnotherAccountName", URL: "https://id.example.com", MFA: "none", Provider: "Okta", @@ -47,11 +69,26 @@ func TestOktaResolveLoginDetailsWithFlags(t *testing.T) { assert.Nil(t, err) assert.False(t, idpa.DisableSessions, fmt.Errorf("default state, DisableSessions should be false")) assert.False(t, idpa.DisableRememberDevice, fmt.Errorf("default state, DisableRememberDevice should be false")) - assert.Equal(t, &creds.LoginDetails{Username: "testuser", Password: "testtestlol", URL: "https://id.example.com", MFAToken: "123456"}, loginDetails) + assert.Equal(t, + &creds.LoginDetails{ + IdpName: "AnotherAccountName", + IdpProvider: "Okta", + Username: "testuser", + Password: "testtestlol", + URL: "https://id.example.com", + MFAToken: "123456", + }, loginDetails) // User disabled keychain, resolveLoginDetails should set the account's DisableSessions and DisableSessions fields to true - commonFlags = &flags.CommonFlags{URL: "https://id.example.com", Username: "testuser", Password: "testtestlol", MFAToken: "123456", SkipPrompt: true, DisableKeychain: true} + commonFlags = &flags.CommonFlags{ + URL: "https://id.example.com", + Username: "testuser", + Password: "testtestlol", + MFAToken: "123456", + SkipPrompt: true, + DisableKeychain: true, + } loginFlags = &flags.LoginExecFlags{CommonFlags: commonFlags} loginDetails, err = resolveLoginDetails(idpa, loginFlags) @@ -59,12 +96,18 @@ func TestOktaResolveLoginDetailsWithFlags(t *testing.T) { assert.Nil(t, err) assert.True(t, idpa.DisableSessions, fmt.Errorf("user disabled keychain, DisableSessions should be true")) assert.True(t, idpa.DisableRememberDevice, fmt.Errorf("user disabled keychain, DisableRememberDevice should be true")) - assert.Equal(t, &creds.LoginDetails{Username: "testuser", Password: "testtestlol", URL: "https://id.example.com", MFAToken: "123456"}, loginDetails) - + assert.Equal(t, + &creds.LoginDetails{ + IdpName: "AnotherAccountName", + IdpProvider: "Okta", + Username: "testuser", + Password: "testtestlol", + URL: "https://id.example.com", + MFAToken: "123456", + }, loginDetails) } func TestResolveRoleSingleEntry(t *testing.T) { - adminRole := &saml2aws.AWSRole{ Name: "admin", RoleARN: "arn:aws:iam::456456456456:saml-provider/example-idp,arn:aws:iam::456456456456:role/admin", @@ -81,7 +124,6 @@ func TestResolveRoleSingleEntry(t *testing.T) { } func TestCredentialsToCredentialProcess(t *testing.T) { - aws_creds := &awsconfig.AWSCredentials{ AWSAccessKey: "someawsaccesskey", AWSSecretKey: "somesecretkey", diff --git a/helper/credentials/credentials.go b/helper/credentials/credentials.go index bebce84f7..d9ad8169b 100644 --- a/helper/credentials/credentials.go +++ b/helper/credentials/credentials.go @@ -2,6 +2,7 @@ package credentials import ( "errors" + "fmt" ) var ( @@ -14,25 +15,35 @@ var ( // Credentials holds the information shared between saml2aws and the credentials store. type Credentials struct { + IdpName string ServerURL string Username string Secret string } -// CredsLabel saml2aws credentials should be labeled as such in credentials stores that allow labelling. -// That label allows to filter out non-Docker credentials too at lookup/search in macOS keychain, -// Windows credentials manager and Linux libsecret. Default value is "saml2aws Credentials" -var CredsLabel = "saml2aws Credentials" +const ( + // CredsLabel saml2aws credentials should be labeled as such in credentials stores that allow labelling. + // That label allows to filter out non-Docker credentials too at lookup/search in macOS keychain, + // Windows credentials manager and Linux libsecret. Default value is "saml2aws Credentials" + CredsLabel = "saml2aws Credentials" + CredsKeyPrefix = "saml2aws_credentials" + OktaSessionCookieSuffix = "_okta_session" + OneLoginTokenSuffix = "_onelogin_token" +) + +func GetKeyFromAccount(accountName string) string { + return fmt.Sprintf("%s_%s", CredsKeyPrefix, accountName) +} // Helper is the interface a credentials store helper must implement. type Helper interface { // Add appends credentials to the store. Add(*Credentials) error // Delete removes credentials from the store. - Delete(serverURL string) error + Delete(idpName string) error // Get retrieves credentials from the store. // It returns username and secret as strings. - Get(serverURL string) (string, string, error) + Get(idpName string) (string, string, error) // SupportsCredentialStorage returns true or false if there is credential storage. SupportsCredentialStorage() bool } diff --git a/helper/credentials/saml.go b/helper/credentials/saml.go index 0f3ba65a8..8015c7c7a 100644 --- a/helper/credentials/saml.go +++ b/helper/credentials/saml.go @@ -1,15 +1,13 @@ package credentials import ( - "path" - "github.com/versent/saml2aws/v2/pkg/creds" ) // LookupCredentials lookup an existing set of credentials and validate it. -func LookupCredentials(loginDetails *creds.LoginDetails, provider string) error { +func LookupCredentials(loginDetails *creds.LoginDetails) error { - username, password, err := CurrentHelper.Get(loginDetails.URL) + username, password, err := CurrentHelper.Get(loginDetails.IdpName) if err != nil { return err } @@ -18,15 +16,17 @@ func LookupCredentials(loginDetails *creds.LoginDetails, provider string) error loginDetails.Password = password // If the provider is Okta, check for existing Okta Session Cookie (sid) - if provider == "Okta" { - _, oktaSessionCookie, err := CurrentHelper.Get(loginDetails.URL + "/sessionCookie") + if loginDetails.IdpProvider == "Okta" { + // load up the Okta token from a different secret (idp name + Okta suffix) + _, oktaSessionCookie, err := CurrentHelper.Get(loginDetails.IdpName + OktaSessionCookieSuffix) if err == nil { loginDetails.OktaSessionCookie = oktaSessionCookie } } - if provider == "OneLogin" { - id, secret, err := CurrentHelper.Get(path.Join(loginDetails.URL, "/auth/oauth2/v2/token")) + if loginDetails.IdpProvider == "OneLogin" { + // load up the one login token from a different secret (idp name + one login suffix) + id, secret, err := CurrentHelper.Get(loginDetails.IdpName + OneLoginTokenSuffix) if err != nil { return err } @@ -37,9 +37,10 @@ func LookupCredentials(loginDetails *creds.LoginDetails, provider string) error } // SaveCredentials save the user credentials. -func SaveCredentials(url, username, password string) error { +func SaveCredentials(idpName, url, username, password string) error { creds := &Credentials{ + IdpName: idpName, ServerURL: url, Username: username, Secret: password, diff --git a/helper/linuxkeyring/linuxkeyring_linux.go b/helper/linuxkeyring/linuxkeyring_linux.go index 123e7c787..3e08fd4b1 100644 --- a/helper/linuxkeyring/linuxkeyring_linux.go +++ b/helper/linuxkeyring/linuxkeyring_linux.go @@ -52,19 +52,19 @@ func (kr *KeyringHelper) Add(creds *credentials.Credentials) error { } return kr.keyring.Set(keyring.Item{ - Key: creds.ServerURL, + Key: credentials.GetKeyFromAccount(creds.IdpName), Label: credentials.CredsLabel, Data: encoded, KeychainNotTrustApplication: false, }) } -func (kr *KeyringHelper) Delete(serverURL string) error { - return kr.keyring.Remove(serverURL) +func (kr *KeyringHelper) Delete(idpName string) error { + return kr.keyring.Remove(credentials.GetKeyFromAccount(idpName)) } -func (kr *KeyringHelper) Get(serverURL string) (string, string, error) { - item, err := kr.keyring.Get(serverURL) +func (kr *KeyringHelper) Get(idpName string) (string, string, error) { + item, err := kr.keyring.Get(credentials.GetKeyFromAccount(idpName)) if err != nil { logger.WithField("err", err).Error("keychain Get returned error") return "", "", credentials.ErrCredentialsNotFound diff --git a/helper/osxkeychain/osxkeychain.go b/helper/osxkeychain/osxkeychain.go index 93e2bcdf3..e878d9932 100644 --- a/helper/osxkeychain/osxkeychain.go +++ b/helper/osxkeychain/osxkeychain.go @@ -19,14 +19,15 @@ type Osxkeychain struct{} // Add adds new credentials to the keychain. func (h Osxkeychain) Add(creds *credentials.Credentials) error { - err := h.Delete(creds.ServerURL) + err := h.Delete(creds.IdpName) if err != nil { logger.WithError(err).Debug("delete of existing keychain entry failed") } item := keychain.NewItem() item.SetSecClass(keychain.SecClassInternetPassword) - item.SetLabel(credentials.CredsLabel) + item.SetLabel(credentials.GetKeyFromAccount(creds.IdpName)) + item.SetString("Purpose", credentials.CredsLabel) item.SetAccount(creds.Username) item.SetData([]byte(creds.Secret)) err = splitServer3(creds.ServerURL, item) @@ -44,36 +45,24 @@ func (h Osxkeychain) Add(creds *credentials.Credentials) error { } // Delete removes credentials from the keychain. -func (h Osxkeychain) Delete(serverURL string) error { +func (h Osxkeychain) Delete(idpName string) error { item := keychain.NewItem() item.SetSecClass(keychain.SecClassInternetPassword) - err := splitServer3(serverURL, item) - if err != nil { - return err - } - - err = keychain.DeleteItem(item) - if err != nil { - return err - } - - return nil + item.SetLabel(credentials.GetKeyFromAccount(idpName)) + return keychain.DeleteItem(item) } // Get returns the username and secret to use for a given registry server URL. -func (h Osxkeychain) Get(serverURL string) (string, string, error) { +func (h Osxkeychain) Get(idpName string) (string, string, error) { - logger.WithField("serverURL", serverURL).Debug("Get credentials") + logger.WithField("Credential Key", idpName).Debug("Get credentials") query := keychain.NewItem() query.SetSecClass(keychain.SecClassInternetPassword) - err := splitServer3(serverURL, query) - if err != nil { - return "", "", err - } - + // only search on the idp name + query.SetLabel(credentials.GetKeyFromAccount(idpName)) query.SetMatchLimit(keychain.MatchLimitOne) query.SetReturnAttributes(true) query.SetReturnData(true) diff --git a/helper/osxkeychain/osxkeychain_test.go b/helper/osxkeychain/osxkeychain_test.go index 78b85337c..7ff9f4f16 100644 --- a/helper/osxkeychain/osxkeychain_test.go +++ b/helper/osxkeychain/osxkeychain_test.go @@ -34,11 +34,13 @@ import ( func TestOSXKeychainHelper(t *testing.T) { creds := &credentials.Credentials{ + IdpName: "creds_idpName", ServerURL: "https://foobar.docker.io:2376/v1", Username: "foobar", Secret: "foobarbaz", } creds1 := &credentials.Credentials{ + IdpName: "creds1_idpName", ServerURL: "https://foobar.docker.io:2376/v2", Username: "foobarbaz", Secret: "foobar", @@ -48,7 +50,7 @@ func TestOSXKeychainHelper(t *testing.T) { t.Fatal(err) } - username, secret, err := helper.Get(creds.ServerURL) + username, secret, err := helper.Get(creds.IdpName) if err != nil { t.Fatal(err) } @@ -65,10 +67,10 @@ func TestOSXKeychainHelper(t *testing.T) { require.Nil(t, err) defer func() { - _ = helper.Delete(creds1.ServerURL) + _ = helper.Delete(creds1.IdpName) }() - if err := helper.Delete(creds.ServerURL); err != nil { + if err := helper.Delete(creds.IdpName); err != nil { t.Fatal(err) } } diff --git a/helper/wincred/wincred_windows.go b/helper/wincred/wincred_windows.go index 38d707521..9f45714ad 100644 --- a/helper/wincred/wincred_windows.go +++ b/helper/wincred/wincred_windows.go @@ -35,7 +35,7 @@ type Wincred struct{} // Add adds new credentials to the windows credentials manager. func (h Wincred) Add(creds *credentials.Credentials) error { - g := winc.NewGenericCredential(creds.ServerURL) + g := winc.NewGenericCredential(credentials.GetKeyFromAccount(creds.IdpName)) g.UserName = creds.Username g.CredentialBlob = []byte(creds.Secret) g.Persist = winc.PersistLocalMachine @@ -45,8 +45,8 @@ func (h Wincred) Add(creds *credentials.Credentials) error { } // Delete removes credentials from the windows credentials manager. -func (h Wincred) Delete(serverURL string) error { - g, err := winc.GetGenericCredential(serverURL) +func (h Wincred) Delete(idpName string) error { + g, err := winc.GetGenericCredential(credentials.GetKeyFromAccount(idpName)) if g == nil { return nil } @@ -57,8 +57,8 @@ func (h Wincred) Delete(serverURL string) error { } // Get retrieves credentials from the windows credentials manager. -func (h Wincred) Get(serverURL string) (string, string, error) { - g, _ := winc.GetGenericCredential(serverURL) +func (h Wincred) Get(idpName string) (string, string, error) { + g, _ := winc.GetGenericCredential(credentials.GetKeyFromAccount(idpName)) if g == nil { return "", "", credentials.ErrCredentialsNotFound } diff --git a/pkg/creds/creds.go b/pkg/creds/creds.go index 5aa697103..c86724128 100644 --- a/pkg/creds/creds.go +++ b/pkg/creds/creds.go @@ -2,6 +2,8 @@ package creds // LoginDetails used to authenticate type LoginDetails struct { + IdpName string // the IDP name for those login Details, required for the credential + IdpProvider string // the IDP provider, required to populate Okta and OneLogin ClientID string // used by OneLogin ClientSecret string // used by OneLogin DownloadBrowser bool // used by Browser diff --git a/pkg/provider/okta/okta.go b/pkg/provider/okta/okta.go index 95c13524d..b0dcdb27e 100644 --- a/pkg/provider/okta/okta.go +++ b/pkg/provider/okta/okta.go @@ -199,7 +199,7 @@ func (oc *Client) createSession(loginDetails *creds.LoginDetails, sessionToken s oktaSessionCookie := gjson.Get(resp, "id").String() - err = credentials.SaveCredentials(loginDetails.URL+"/sessionCookie", loginDetails.Username, oktaSessionCookie) + err = credentials.SaveCredentials(loginDetails.IdpName+credentials.OktaSessionCookieSuffix, loginDetails.URL+"/sessionCookie", loginDetails.Username, oktaSessionCookie) if err != nil { return "", "", fmt.Errorf("error storing okta session token | err: %v", err) } @@ -568,7 +568,7 @@ func (oc *Client) follow(ctx context.Context, req *http.Request, loginDetails *c if handler == nil { html, _ := doc.Selection.Html() logger.WithField("doc", html).Debug("Unknown document type") - return "", fmt.Errorf("Unknown document type") + return "", fmt.Errorf("unknown document type") } ctx, req, err = handler(ctx, doc) diff --git a/pkg/provider/okta/okta_test.go b/pkg/provider/okta/okta_test.go index 181f03b2c..953ae1c65 100644 --- a/pkg/provider/okta/okta_test.go +++ b/pkg/provider/okta/okta_test.go @@ -202,6 +202,7 @@ func setupTestClient(t *testing.T, ts *httptest.Server, mfa string) (*Client, *c func TestSetDeviceTokenCookie(t *testing.T) { idpAccount := cfg.NewIDPAccount() + idpAccount.Name = "myOktaProvider" idpAccount.URL = "https://idp.example.com/abcd" idpAccount.Username = "user@example.com"