github.com/snowflakedb/gosnowflake@v1.9.0/auth.go (about)

     1  // Copyright (c) 2017-2022 Snowflake Computing Inc. All rights reserved.
     2  
     3  package gosnowflake
     4  
     5  import (
     6  	"context"
     7  	"crypto/sha256"
     8  	"crypto/x509"
     9  	"encoding/base64"
    10  	"encoding/json"
    11  	"fmt"
    12  	"io"
    13  	"net/http"
    14  	"net/url"
    15  	"runtime"
    16  	"strconv"
    17  	"strings"
    18  	"time"
    19  
    20  	"github.com/form3tech-oss/jwt-go"
    21  )
    22  
    23  const (
    24  	clientType = "Go"
    25  )
    26  
    27  const (
    28  	idToken                        = "ID_TOKEN"
    29  	mfaToken                       = "MFATOKEN"
    30  	clientStoreTemporaryCredential = "CLIENT_STORE_TEMPORARY_CREDENTIAL"
    31  	clientRequestMfaToken          = "CLIENT_REQUEST_MFA_TOKEN"
    32  	idTokenAuthenticator           = "ID_TOKEN"
    33  )
    34  
    35  // AuthType indicates the type of authentication in Snowflake
    36  type AuthType int
    37  
    38  const (
    39  	// AuthTypeSnowflake is the general username password authentication
    40  	AuthTypeSnowflake AuthType = iota
    41  	// AuthTypeOAuth is the OAuth authentication
    42  	AuthTypeOAuth
    43  	// AuthTypeExternalBrowser is to use a browser to access an Fed and perform SSO authentication
    44  	AuthTypeExternalBrowser
    45  	// AuthTypeOkta is to use a native okta URL to perform SSO authentication on Okta
    46  	AuthTypeOkta
    47  	// AuthTypeJwt is to use Jwt to perform authentication
    48  	AuthTypeJwt
    49  	// AuthTypeTokenAccessor is to use the provided token accessor and bypass authentication
    50  	AuthTypeTokenAccessor
    51  	// AuthTypeUsernamePasswordMFA is to use username and password with mfa
    52  	AuthTypeUsernamePasswordMFA
    53  )
    54  
    55  func determineAuthenticatorType(cfg *Config, value string) error {
    56  	upperCaseValue := strings.ToUpper(value)
    57  	lowerCaseValue := strings.ToLower(value)
    58  	if strings.Trim(value, " ") == "" || upperCaseValue == AuthTypeSnowflake.String() {
    59  		cfg.Authenticator = AuthTypeSnowflake
    60  		return nil
    61  	} else if upperCaseValue == AuthTypeOAuth.String() {
    62  		cfg.Authenticator = AuthTypeOAuth
    63  		return nil
    64  	} else if upperCaseValue == AuthTypeJwt.String() {
    65  		cfg.Authenticator = AuthTypeJwt
    66  		return nil
    67  	} else if upperCaseValue == AuthTypeExternalBrowser.String() {
    68  		cfg.Authenticator = AuthTypeExternalBrowser
    69  		return nil
    70  	} else if upperCaseValue == AuthTypeUsernamePasswordMFA.String() {
    71  		cfg.Authenticator = AuthTypeUsernamePasswordMFA
    72  		return nil
    73  	} else if upperCaseValue == AuthTypeTokenAccessor.String() {
    74  		cfg.Authenticator = AuthTypeTokenAccessor
    75  		return nil
    76  	} else {
    77  		// possibly Okta case
    78  		oktaURLString, err := url.QueryUnescape(lowerCaseValue)
    79  		if err != nil {
    80  			return &SnowflakeError{
    81  				Number:      ErrCodeFailedToParseAuthenticator,
    82  				Message:     errMsgFailedToParseAuthenticator,
    83  				MessageArgs: []interface{}{lowerCaseValue},
    84  			}
    85  		}
    86  
    87  		oktaURL, err := url.Parse(oktaURLString)
    88  		if err != nil {
    89  			return &SnowflakeError{
    90  				Number:      ErrCodeFailedToParseAuthenticator,
    91  				Message:     errMsgFailedToParseAuthenticator,
    92  				MessageArgs: []interface{}{oktaURLString},
    93  			}
    94  		}
    95  
    96  		if oktaURL.Scheme != "https" || !strings.HasSuffix(oktaURL.Host, "okta.com") {
    97  			return &SnowflakeError{
    98  				Number:      ErrCodeFailedToParseAuthenticator,
    99  				Message:     errMsgFailedToParseAuthenticator,
   100  				MessageArgs: []interface{}{oktaURLString},
   101  			}
   102  		}
   103  		cfg.OktaURL = oktaURL
   104  		cfg.Authenticator = AuthTypeOkta
   105  	}
   106  	return nil
   107  }
   108  
   109  func (authType AuthType) String() string {
   110  	switch authType {
   111  	case AuthTypeSnowflake:
   112  		return "SNOWFLAKE"
   113  	case AuthTypeOAuth:
   114  		return "OAUTH"
   115  	case AuthTypeExternalBrowser:
   116  		return "EXTERNALBROWSER"
   117  	case AuthTypeOkta:
   118  		return "OKTA"
   119  	case AuthTypeJwt:
   120  		return "SNOWFLAKE_JWT"
   121  	case AuthTypeTokenAccessor:
   122  		return "TOKENACCESSOR"
   123  	case AuthTypeUsernamePasswordMFA:
   124  		return "USERNAME_PASSWORD_MFA"
   125  	default:
   126  		return "UNKNOWN"
   127  	}
   128  }
   129  
   130  // platform consists of compiler and architecture type in string
   131  var platform = fmt.Sprintf("%v-%v", runtime.Compiler, runtime.GOARCH)
   132  
   133  // operatingSystem is the runtime operating system.
   134  var operatingSystem = runtime.GOOS
   135  
   136  // userAgent shows up in User-Agent HTTP header
   137  var userAgent = fmt.Sprintf("%v/%v (%v-%v) %v/%v",
   138  	clientType,
   139  	SnowflakeGoDriverVersion,
   140  	operatingSystem,
   141  	runtime.GOARCH,
   142  	runtime.Compiler,
   143  	runtime.Version())
   144  
   145  type authRequestClientEnvironment struct {
   146  	Application string `json:"APPLICATION"`
   147  	Os          string `json:"OS"`
   148  	OsVersion   string `json:"OS_VERSION"`
   149  	OCSPMode    string `json:"OCSP_MODE"`
   150  }
   151  type authRequestData struct {
   152  	ClientAppID             string                       `json:"CLIENT_APP_ID"`
   153  	ClientAppVersion        string                       `json:"CLIENT_APP_VERSION"`
   154  	SvnRevision             string                       `json:"SVN_REVISION"`
   155  	AccountName             string                       `json:"ACCOUNT_NAME"`
   156  	LoginName               string                       `json:"LOGIN_NAME,omitempty"`
   157  	Password                string                       `json:"PASSWORD,omitempty"`
   158  	RawSAMLResponse         string                       `json:"RAW_SAML_RESPONSE,omitempty"`
   159  	ExtAuthnDuoMethod       string                       `json:"EXT_AUTHN_DUO_METHOD,omitempty"`
   160  	Passcode                string                       `json:"PASSCODE,omitempty"`
   161  	Authenticator           string                       `json:"AUTHENTICATOR,omitempty"`
   162  	SessionParameters       map[string]interface{}       `json:"SESSION_PARAMETERS,omitempty"`
   163  	ClientEnvironment       authRequestClientEnvironment `json:"CLIENT_ENVIRONMENT"`
   164  	BrowserModeRedirectPort string                       `json:"BROWSER_MODE_REDIRECT_PORT,omitempty"`
   165  	ProofKey                string                       `json:"PROOF_KEY,omitempty"`
   166  	Token                   string                       `json:"TOKEN,omitempty"`
   167  }
   168  type authRequest struct {
   169  	Data authRequestData `json:"data"`
   170  }
   171  
   172  type nameValueParameter struct {
   173  	Name  string      `json:"name"`
   174  	Value interface{} `json:"value"`
   175  }
   176  
   177  type authResponseSessionInfo struct {
   178  	DatabaseName  string `json:"databaseName"`
   179  	SchemaName    string `json:"schemaName"`
   180  	WarehouseName string `json:"warehouseName"`
   181  	RoleName      string `json:"roleName"`
   182  }
   183  
   184  type authResponseMain struct {
   185  	Token               string                  `json:"token,omitempty"`
   186  	Validity            time.Duration           `json:"validityInSeconds,omitempty"`
   187  	MasterToken         string                  `json:"masterToken,omitempty"`
   188  	MasterValidity      time.Duration           `json:"masterValidityInSeconds"`
   189  	MfaToken            string                  `json:"mfaToken,omitempty"`
   190  	MfaTokenValidity    time.Duration           `json:"mfaTokenValidityInSeconds"`
   191  	IDToken             string                  `json:"idToken,omitempty"`
   192  	IDTokenValidity     time.Duration           `json:"idTokenValidityInSeconds"`
   193  	DisplayUserName     string                  `json:"displayUserName"`
   194  	ServerVersion       string                  `json:"serverVersion"`
   195  	FirstLogin          bool                    `json:"firstLogin"`
   196  	RemMeToken          string                  `json:"remMeToken"`
   197  	RemMeValidity       time.Duration           `json:"remMeValidityInSeconds"`
   198  	HealthCheckInterval time.Duration           `json:"healthCheckInterval"`
   199  	NewClientForUpgrade string                  `json:"newClientForUpgrade"`
   200  	SessionID           int64                   `json:"sessionId"`
   201  	Parameters          []nameValueParameter    `json:"parameters"`
   202  	SessionInfo         authResponseSessionInfo `json:"sessionInfo"`
   203  	TokenURL            string                  `json:"tokenUrl,omitempty"`
   204  	SSOURL              string                  `json:"ssoUrl,omitempty"`
   205  	ProofKey            string                  `json:"proofKey,omitempty"`
   206  }
   207  
   208  type authResponse struct {
   209  	Data    authResponseMain `json:"data"`
   210  	Message string           `json:"message"`
   211  	Code    string           `json:"code"`
   212  	Success bool             `json:"success"`
   213  }
   214  
   215  func postAuth(
   216  	ctx context.Context,
   217  	sr *snowflakeRestful,
   218  	client *http.Client,
   219  	params *url.Values,
   220  	headers map[string]string,
   221  	bodyCreator bodyCreatorType,
   222  	timeout time.Duration) (
   223  	data *authResponse, err error) {
   224  	params.Add(requestIDKey, getOrGenerateRequestIDFromContext(ctx).String())
   225  	params.Add(requestGUIDKey, NewUUID().String())
   226  
   227  	fullURL := sr.getFullURL(loginRequestPath, params)
   228  	logger.Infof("full URL: %v", fullURL)
   229  	resp, err := sr.FuncAuthPost(ctx, client, fullURL, headers, bodyCreator, timeout, sr.MaxRetryCount)
   230  	if err != nil {
   231  		return nil, err
   232  	}
   233  	defer resp.Body.Close()
   234  	if resp.StatusCode == http.StatusOK {
   235  		var respd authResponse
   236  		err = json.NewDecoder(resp.Body).Decode(&respd)
   237  		if err != nil {
   238  			logger.Errorf("failed to decode JSON. err: %v", err)
   239  			return nil, err
   240  		}
   241  		return &respd, nil
   242  	}
   243  	switch resp.StatusCode {
   244  	case http.StatusBadGateway, http.StatusServiceUnavailable, http.StatusGatewayTimeout:
   245  		// service availability or connectivity issue. Most likely server side issue.
   246  		return nil, &SnowflakeError{
   247  			Number:      ErrCodeServiceUnavailable,
   248  			SQLState:    SQLStateConnectionWasNotEstablished,
   249  			Message:     errMsgServiceUnavailable,
   250  			MessageArgs: []interface{}{resp.StatusCode, fullURL},
   251  		}
   252  	case http.StatusUnauthorized, http.StatusForbidden:
   253  		// failed to connect to db. account name may be wrong
   254  		return nil, &SnowflakeError{
   255  			Number:      ErrCodeFailedToConnect,
   256  			SQLState:    SQLStateConnectionRejected,
   257  			Message:     errMsgFailedToConnect,
   258  			MessageArgs: []interface{}{resp.StatusCode, fullURL},
   259  		}
   260  	}
   261  	b, err := io.ReadAll(resp.Body)
   262  	if err != nil {
   263  		logger.Errorf("failed to extract HTTP response body. err: %v", err)
   264  		return nil, err
   265  	}
   266  	logger.Infof("HTTP: %v, URL: %v, Body: %v", resp.StatusCode, fullURL, b)
   267  	logger.Infof("Header: %v", resp.Header)
   268  	return nil, &SnowflakeError{
   269  		Number:      ErrFailedToAuth,
   270  		SQLState:    SQLStateConnectionRejected,
   271  		Message:     errMsgFailedToAuth,
   272  		MessageArgs: []interface{}{resp.StatusCode, fullURL},
   273  	}
   274  }
   275  
   276  // Generates a map of headers needed to authenticate
   277  // with Snowflake.
   278  func getHeaders() map[string]string {
   279  	headers := make(map[string]string)
   280  	headers[httpHeaderContentType] = headerContentTypeApplicationJSON
   281  	headers[httpHeaderAccept] = headerAcceptTypeApplicationSnowflake
   282  	headers[httpClientAppID] = clientType
   283  	headers[httpClientAppVersion] = SnowflakeGoDriverVersion
   284  	headers[httpHeaderUserAgent] = userAgent
   285  	return headers
   286  }
   287  
   288  // Used to authenticate the user with Snowflake.
   289  func authenticate(
   290  	ctx context.Context,
   291  	sc *snowflakeConn,
   292  	samlResponse []byte,
   293  	proofKey []byte,
   294  ) (resp *authResponseMain, err error) {
   295  	if sc.cfg.Authenticator == AuthTypeTokenAccessor {
   296  		logger.Info("Bypass authentication using existing token from token accessor")
   297  		sessionInfo := authResponseSessionInfo{
   298  			DatabaseName:  sc.cfg.Database,
   299  			SchemaName:    sc.cfg.Schema,
   300  			WarehouseName: sc.cfg.Warehouse,
   301  			RoleName:      sc.cfg.Role,
   302  		}
   303  		token, masterToken, sessionID := sc.cfg.TokenAccessor.GetTokens()
   304  		return &authResponseMain{
   305  			Token:       token,
   306  			MasterToken: masterToken,
   307  			SessionID:   sessionID,
   308  			SessionInfo: sessionInfo,
   309  		}, nil
   310  	}
   311  
   312  	headers := getHeaders()
   313  	clientEnvironment := authRequestClientEnvironment{
   314  		Application: sc.cfg.Application,
   315  		Os:          operatingSystem,
   316  		OsVersion:   platform,
   317  		OCSPMode:    sc.cfg.ocspMode(),
   318  	}
   319  
   320  	sessionParameters := make(map[string]interface{})
   321  	paramsMutex.Lock()
   322  	for k, v := range sc.cfg.Params {
   323  		// upper casing to normalize keys
   324  		sessionParameters[strings.ToUpper(k)] = *v
   325  	}
   326  	paramsMutex.Unlock()
   327  
   328  	sessionParameters[sessionClientValidateDefaultParameters] = sc.cfg.ValidateDefaultParameters != ConfigBoolFalse
   329  	if sc.cfg.ClientRequestMfaToken == ConfigBoolTrue {
   330  		sessionParameters[clientRequestMfaToken] = true
   331  	}
   332  	if sc.cfg.ClientStoreTemporaryCredential == ConfigBoolTrue {
   333  		sessionParameters[clientStoreTemporaryCredential] = true
   334  	}
   335  	bodyCreator := func() ([]byte, error) {
   336  		return createRequestBody(sc, sessionParameters, clientEnvironment, proofKey, samlResponse)
   337  	}
   338  
   339  	params := &url.Values{}
   340  	if sc.cfg.Database != "" {
   341  		params.Add("databaseName", sc.cfg.Database)
   342  	}
   343  	if sc.cfg.Schema != "" {
   344  		params.Add("schemaName", sc.cfg.Schema)
   345  	}
   346  	if sc.cfg.Warehouse != "" {
   347  		params.Add("warehouse", sc.cfg.Warehouse)
   348  	}
   349  	if sc.cfg.Role != "" {
   350  		params.Add("roleName", sc.cfg.Role)
   351  	}
   352  
   353  	logger.WithContext(sc.ctx).Infof("PARAMS for Auth: %v, %v, %v, %v, %v, %v",
   354  		params, sc.rest.Protocol, sc.rest.Host, sc.rest.Port, sc.rest.LoginTimeout, sc.cfg.Authenticator.String())
   355  
   356  	respd, err := sc.rest.FuncPostAuth(ctx, sc.rest, sc.rest.getClientFor(sc.cfg.Authenticator), params, headers, bodyCreator, sc.rest.LoginTimeout)
   357  	if err != nil {
   358  		return nil, err
   359  	}
   360  	if !respd.Success {
   361  		logger.Errorln("Authentication FAILED")
   362  		sc.rest.TokenAccessor.SetTokens("", "", -1)
   363  		if sessionParameters[clientRequestMfaToken] == true {
   364  			deleteCredential(sc, mfaToken)
   365  		}
   366  		if sessionParameters[clientStoreTemporaryCredential] == true {
   367  			deleteCredential(sc, idToken)
   368  		}
   369  		code, err := strconv.Atoi(respd.Code)
   370  		if err != nil {
   371  			code = -1
   372  			return nil, err
   373  		}
   374  		return nil, (&SnowflakeError{
   375  			Number:   code,
   376  			SQLState: SQLStateConnectionRejected,
   377  			Message:  respd.Message,
   378  		}).exceptionTelemetry(sc)
   379  	}
   380  	logger.Info("Authentication SUCCESS")
   381  	sc.rest.TokenAccessor.SetTokens(respd.Data.Token, respd.Data.MasterToken, respd.Data.SessionID)
   382  	if sessionParameters[clientRequestMfaToken] == true {
   383  		token := respd.Data.MfaToken
   384  		setCredential(sc, mfaToken, token)
   385  	}
   386  	if sessionParameters[clientStoreTemporaryCredential] == true {
   387  		token := respd.Data.IDToken
   388  		setCredential(sc, idToken, token)
   389  	}
   390  	return &respd.Data, nil
   391  }
   392  
   393  func createRequestBody(sc *snowflakeConn, sessionParameters map[string]interface{},
   394  	clientEnvironment authRequestClientEnvironment, proofKey []byte, samlResponse []byte,
   395  ) ([]byte, error) {
   396  	requestMain := authRequestData{
   397  		ClientAppID:       clientType,
   398  		ClientAppVersion:  SnowflakeGoDriverVersion,
   399  		AccountName:       sc.cfg.Account,
   400  		SessionParameters: sessionParameters,
   401  		ClientEnvironment: clientEnvironment,
   402  	}
   403  
   404  	switch sc.cfg.Authenticator {
   405  	case AuthTypeExternalBrowser:
   406  		if sc.cfg.IDToken != "" {
   407  			requestMain.Authenticator = idTokenAuthenticator
   408  			requestMain.Token = sc.cfg.IDToken
   409  			requestMain.LoginName = sc.cfg.User
   410  		} else {
   411  			requestMain.ProofKey = string(proofKey)
   412  			requestMain.Token = string(samlResponse)
   413  			requestMain.LoginName = sc.cfg.User
   414  			requestMain.Authenticator = AuthTypeExternalBrowser.String()
   415  		}
   416  	case AuthTypeOAuth:
   417  		requestMain.LoginName = sc.cfg.User
   418  		requestMain.Authenticator = AuthTypeOAuth.String()
   419  		requestMain.Token = sc.cfg.Token
   420  	case AuthTypeOkta:
   421  		samlResponse, err := authenticateBySAML(
   422  			sc.ctx,
   423  			sc.rest,
   424  			sc.cfg.OktaURL,
   425  			sc.cfg.Application,
   426  			sc.cfg.Account,
   427  			sc.cfg.User,
   428  			sc.cfg.Password)
   429  		if err != nil {
   430  			return nil, err
   431  		}
   432  		requestMain.RawSAMLResponse = string(samlResponse)
   433  	case AuthTypeJwt:
   434  		requestMain.Authenticator = AuthTypeJwt.String()
   435  
   436  		jwtTokenString, err := prepareJWTToken(sc.cfg)
   437  		if err != nil {
   438  			return nil, err
   439  		}
   440  		requestMain.Token = jwtTokenString
   441  	case AuthTypeSnowflake:
   442  		logger.Info("Username and password")
   443  		requestMain.LoginName = sc.cfg.User
   444  		requestMain.Password = sc.cfg.Password
   445  		switch {
   446  		case sc.cfg.PasscodeInPassword:
   447  			requestMain.ExtAuthnDuoMethod = "passcode"
   448  		case sc.cfg.Passcode != "":
   449  			requestMain.Passcode = sc.cfg.Passcode
   450  			requestMain.ExtAuthnDuoMethod = "passcode"
   451  		}
   452  	case AuthTypeUsernamePasswordMFA:
   453  		logger.Info("Username and password MFA")
   454  		requestMain.LoginName = sc.cfg.User
   455  		requestMain.Password = sc.cfg.Password
   456  		if sc.cfg.MfaToken != "" {
   457  			requestMain.Token = sc.cfg.MfaToken
   458  		}
   459  	}
   460  
   461  	authRequest := authRequest{
   462  		Data: requestMain,
   463  	}
   464  	jsonBody, err := json.Marshal(authRequest)
   465  	if err != nil {
   466  		return nil, err
   467  	}
   468  	return jsonBody, nil
   469  }
   470  
   471  // Generate a JWT token in string given the configuration
   472  func prepareJWTToken(config *Config) (string, error) {
   473  	pubBytes, err := x509.MarshalPKIXPublicKey(config.PrivateKey.Public())
   474  	if err != nil {
   475  		return "", err
   476  	}
   477  	hash := sha256.Sum256(pubBytes)
   478  
   479  	accountName := strings.ToUpper(config.Account)
   480  	userName := strings.ToUpper(config.User)
   481  
   482  	issueAtTime := time.Now().UTC()
   483  	token := jwt.NewWithClaims(jwt.SigningMethodRS256, jwt.MapClaims{
   484  		"iss": fmt.Sprintf("%s.%s.%s", accountName, userName, "SHA256:"+base64.StdEncoding.EncodeToString(hash[:])),
   485  		"sub": fmt.Sprintf("%s.%s", accountName, userName),
   486  		"iat": issueAtTime.Unix(),
   487  		"nbf": time.Date(2015, 10, 10, 12, 0, 0, 0, time.UTC).Unix(),
   488  		"exp": issueAtTime.Add(config.JWTExpireTimeout).Unix(),
   489  	})
   490  
   491  	tokenString, err := token.SignedString(config.PrivateKey)
   492  
   493  	if err != nil {
   494  		return "", err
   495  	}
   496  
   497  	return tokenString, err
   498  }
   499  
   500  // Authenticate with sc.cfg
   501  func authenticateWithConfig(sc *snowflakeConn) error {
   502  	var authData *authResponseMain
   503  	var samlResponse []byte
   504  	var proofKey []byte
   505  	var err error
   506  	//var consentCacheIdToken = true
   507  
   508  	if sc.cfg.Authenticator == AuthTypeExternalBrowser {
   509  		if (runtime.GOOS == "windows" || runtime.GOOS == "darwin") && sc.cfg.ClientStoreTemporaryCredential == configBoolNotSet {
   510  			sc.cfg.ClientStoreTemporaryCredential = ConfigBoolTrue
   511  		}
   512  		if sc.cfg.ClientStoreTemporaryCredential == ConfigBoolTrue {
   513  			fillCachedIDToken(sc)
   514  		}
   515  		// Disable console login by default
   516  		if sc.cfg.DisableConsoleLogin == configBoolNotSet {
   517  			sc.cfg.DisableConsoleLogin = ConfigBoolTrue
   518  		}
   519  	}
   520  
   521  	if sc.cfg.Authenticator == AuthTypeUsernamePasswordMFA {
   522  		if (runtime.GOOS == "windows" || runtime.GOOS == "darwin") && sc.cfg.ClientRequestMfaToken == configBoolNotSet {
   523  			sc.cfg.ClientRequestMfaToken = ConfigBoolTrue
   524  		}
   525  		if sc.cfg.ClientRequestMfaToken == ConfigBoolTrue {
   526  			fillCachedMfaToken(sc)
   527  		}
   528  	}
   529  
   530  	logger.Infof("Authenticating via %v", sc.cfg.Authenticator.String())
   531  	switch sc.cfg.Authenticator {
   532  	case AuthTypeExternalBrowser:
   533  		if sc.cfg.IDToken == "" {
   534  			samlResponse, proofKey, err = authenticateByExternalBrowser(
   535  				sc.ctx,
   536  				sc.rest,
   537  				sc.cfg.Authenticator.String(),
   538  				sc.cfg.Application,
   539  				sc.cfg.Account,
   540  				sc.cfg.User,
   541  				sc.cfg.Password,
   542  				sc.cfg.ExternalBrowserTimeout,
   543  				sc.cfg.DisableConsoleLogin)
   544  			if err != nil {
   545  				sc.cleanup()
   546  				return err
   547  			}
   548  		}
   549  	}
   550  	authData, err = authenticate(
   551  		sc.ctx,
   552  		sc,
   553  		samlResponse,
   554  		proofKey)
   555  	if err != nil {
   556  		sc.cleanup()
   557  		return err
   558  	}
   559  	sc.populateSessionParameters(authData.Parameters)
   560  	sc.ctx = context.WithValue(sc.ctx, SFSessionIDKey, authData.SessionID)
   561  	return nil
   562  }
   563  
   564  func fillCachedIDToken(sc *snowflakeConn) {
   565  	getCredential(sc, idToken)
   566  }
   567  
   568  func fillCachedMfaToken(sc *snowflakeConn) {
   569  	getCredential(sc, mfaToken)
   570  }