Пример #1
0
        internal void renewSession()
        {
            RenewSessionRequest postBody = new RenewSessionRequest()
            {
                oldSessionToken = this.sessionToken,
                requestType     = "RENEW"
            };

            SFRestRequest renewSessionRequest = new SFRestRequest
            {
                jsonBody = postBody,
                uri      = BuildUri(SF_TOKEN_REQUEST_PATH,
                                    new Dictionary <string, string> {
                    { SF_QUERY_REQUEST_ID, Guid.NewGuid().ToString() }
                }),
                authorizationToken   = string.Format(SF_AUTHORIZATION_SNOWFLAKE_FMT, masterToken),
                sfRestRequestTimeout = Timeout.InfiniteTimeSpan
            };

            var response = restRequest.Post <RenewSessionResponse>(renewSessionRequest);

            if (!response.success)
            {
                SnowflakeDbException e = new SnowflakeDbException("",
                                                                  response.code, response.message, "");
                logger.Error("Renew session failed", e);
                throw e;
            }
            else
            {
                sessionToken = response.data.sessionToken;
            }
        }
 public override void Open()
 {
     logger.Debug("Open Connection.");
     SetSession();
     try
     {
         SfSession.Open();
     }
     catch (Exception e)
     {
         // Otherwise when Dispose() is called, the close request would timeout.
         _connectionState = ConnectionState.Closed;
         logger.Error("Unable to connect", e);
         if (!(e.GetType() == typeof(SnowflakeDbException)))
         {
             throw new SnowflakeDbException(e.InnerException,
                                            SFError.INTERNAL_ERROR,
                                            "Unable to connect");
         }
         else
         {
             throw;
         }
     }
     OnSessionEstablished();
 }
        /// <summary>
        /// Generate the authenticator given the session
        /// </summary>
        /// <param name="session">session that requires the authentication</param>
        /// <returns>authenticator</returns>
        /// <exception cref="SnowflakeDbException">when authenticator is unknown</exception>
        internal static IAuthenticator GetAuthenticator(SFSession session)
        {
            string type = session.properties[SFSessionProperty.AUTHENTICATOR];

            if (type.Equals(BasicAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                return(new BasicAuthenticator(session));
            }
            else if (type.Equals(ExternalBrowserAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                return(new ExternalBrowserAuthenticator(session));
            }
            else if (type.Equals(KeyPairAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                // Get private key path or private key from connection settings
                if (!session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY_FILE, out var pkPath) &&
                    !session.properties.TryGetValue(SFSessionProperty.PRIVATE_KEY, out var pkContent))
                {
                    // There is no PRIVATE_KEY_FILE defined, can't authenticate with key-pair
                    string invalidStringDetail =
                        "Missing required PRIVATE_KEY_FILE or PRIVATE_KEY for key pair authentication";
                    var error = new SnowflakeDbException(
                        SFError.INVALID_CONNECTION_STRING,
                        new object[] { invalidStringDetail });
                    logger.Error(error.Message, error);
                    throw error;
                }

                return(new KeyPairAuthenticator(session));
            }
            else if (type.Equals(OAuthAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                // Get private key path or private key from connection settings
                if (!session.properties.TryGetValue(SFSessionProperty.TOKEN, out var pkPath))
                {
                    // There is no TOKEN defined, can't authenticate with oauth
                    string invalidStringDetail =
                        "Missing required TOKEN for Oauth authentication";
                    var error = new SnowflakeDbException(
                        SFError.INVALID_CONNECTION_STRING,
                        new object[] { invalidStringDetail });
                    logger.Error(error.Message, error);
                    throw error;
                }

                return(new OAuthAuthenticator(session));
            }
            // Okta would provide a url of form: https://xxxxxx.okta.com or https://xxxxxx.oktapreview.com
            else if ((type.EndsWith("okta.com") || type.EndsWith("oktapreview.com")) &&
                     type.StartsWith("https://"))
            {
                return(new OktaAuthenticator(session, type));
            }

            var e = new SnowflakeDbException(SFError.UNKNOWN_AUTHENTICATOR, type);

            logger.Error("Unknown authenticator", e);

            throw e;
        }
Пример #4
0
 private void VerifyUrls(Uri tokenOrSsoUrl, Uri sessionUrl)
 {
     if (tokenOrSsoUrl.Scheme != sessionUrl.Scheme || tokenOrSsoUrl.Host != sessionUrl.Host)
     {
         var e = new SnowflakeDbException(
             SFError.IDP_SSO_TOKEN_URL_MISMATCH, tokenOrSsoUrl.ToString(), oktaUrl.ToString());
         logger.Error("Different urls", e);
         throw e;
     }
 }
        internal async Task <SFBaseResultSet> ExecuteAsync(int timeout, string sql, Dictionary <string, BindingDTO> bindings, bool describeOnly,
                                                           CancellationToken cancellationToken)
        {
            registerQueryCancellationCallback(timeout, cancellationToken);
            var queryRequest = BuildQueryRequest(sql, bindings, describeOnly);

            try
            {
                QueryExecResponse response      = null;
                bool receivedFirstQueryResponse = false;
                while (!receivedFirstQueryResponse)
                {
                    response = await _restRequester.PostAsync <QueryExecResponse>(queryRequest, cancellationToken).ConfigureAwait(false);

                    if (SessionExpired(response))
                    {
                        SfSession.renewSession();
                        queryRequest.authorizationToken = string.Format(SF_AUTHORIZATION_SNOWFLAKE_FMT, SfSession.sessionToken);
                    }
                    else
                    {
                        receivedFirstQueryResponse = true;
                    }
                }

                var lastResultUrl = response.data?.getResultUrl;

                while (RequestInProgress(response) || SessionExpired(response))
                {
                    var req = BuildResultRequest(lastResultUrl);
                    response = await _restRequester.GetAsync <QueryExecResponse>(req, cancellationToken).ConfigureAwait(false);

                    if (SessionExpired(response))
                    {
                        logger.Info("Ping pong request failed with session expired, trying to renew the session.");
                        SfSession.renewSession();
                    }
                    else
                    {
                        lastResultUrl = response.data?.getResultUrl;
                    }
                }

                return(BuildResultSet(response, cancellationToken));
            }
            catch
            {
                logger.Error("Query execution failed.");
                throw;
            }
            finally
            {
                ClearQueryRequestId();
            }
        }
Пример #6
0
        internal static SFSessionProperties parseConnectionString(String connectionString, SecureString password)
        {
            logger.Info("Start parsing connection string.");
            SFSessionProperties properties = new SFSessionProperties();

            string[] propertyEntry = connectionString.Split(';');

            foreach (string keyVal in propertyEntry)
            {
                if (keyVal.Length > 0)
                {
                    string[] token = keyVal.Split(new string[] { "=" }, StringSplitOptions.None);
                    if (token.Length == 2)
                    {
                        try
                        {
                            SFSessionProperty p = (SFSessionProperty)Enum.Parse(
                                typeof(SFSessionProperty), token[0].ToUpper());
                            properties.Add(p, token[1]);
                            logger.Info($"Connection property: {p}, value: {(p == SFSessionProperty.PASSWORD ? "XXXXXXXX" : token[1])}");
                        }
                        catch (ArgumentException e)
                        {
                            logger.Warn($"Property {token[0]} not found ignored.");
                        }
                    }
                    else
                    {
                        string invalidStringDetail = String.Format("Invalid kay value pair {0}", keyVal);
                        SnowflakeDbException e     = new SnowflakeDbException(SFError.INVALID_CONNECTION_STRING,
                                                                              new object[] { invalidStringDetail });
                        logger.Error("Invalid string.", e);
                        throw e;
                    }
                }
            }

            if (password != null)
            {
                properties[SFSessionProperty.PASSWORD] = new NetworkCredential(string.Empty, password).Password;
            }
            checkSessionProperties(properties);

            // compose host value if not specified
            if (!properties.ContainsKey(SFSessionProperty.HOST))
            {
                string hostName = String.Format("%s.snowflakecomputing.com", properties[SFSessionProperty.ACCOUNT]);
                properties.Add(SFSessionProperty.HOST, hostName);
                logger.Info($"Compose host name: {hostName}");
            }

            return(properties);
        }
Пример #7
0
        /// <summary>
        /// Generate the authenticator given the session
        /// </summary>
        /// <param name="session">session that requires the authentication</param>
        /// <returns>authenticator</returns>
        /// <exception cref="SnowflakeDbException">when authenticator is unknown</exception>
        internal static IAuthenticator GetAuthenticator(SFSession session)
        {
            string type = session.properties[SFSessionProperty.AUTHENTICATOR];

            if (type.Equals(BasicAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                return(new BasicAuthenticator(session));
            }
            else if (type.Equals(ExternalBrowserAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                return(new ExternalBrowserAuthenticator(session));
            }
            // Okta would provide a url of form: https://xxxxxx.okta.com
            else if (type.EndsWith("okta.com") && type.StartsWith("https://"))
            {
                return(new OktaAuthenticator(session, type));
            }
            else if (type.Equals(OAuthAuthenticator.AUTH_NAME, StringComparison.InvariantCultureIgnoreCase))
            {
                return(new OAuthAuthenticator(session));
            }

            var e = new SnowflakeDbException(SFError.UNKNOWN_AUTHENTICATOR, type);

            logger.Error("Unknown authenticator", e);

            throw e;
        }
        internal async Task <SFBaseResultSet> ExecuteAsync(int timeout, string sql, Dictionary <string, BindingDTO> bindings, bool describeOnly,
                                                           CancellationToken cancellationToken)
        {
            registerQueryCancellationCallback(timeout, cancellationToken);
            var queryRequest = BuildQueryRequest(sql, bindings, describeOnly);

            try
            {
                var response = await _restRequest.PostAsync <QueryExecResponse>(queryRequest, cancellationToken);

                if (SessionExpired(response))
                {
                    SfSession.renewSession();
                    ClearQueryRequestId();
                    return(await ExecuteAsync(timeout, sql, bindings, describeOnly, cancellationToken));
                }

                var lastResultUrl = response.data?.getResultUrl;

                while (RequestInProgress(response) || SessionExpired(response))
                {
                    var req = BuildResultRequest(lastResultUrl);
                    response = await _restRequest.GetAsync <QueryExecResponse>(req, cancellationToken);

                    if (SessionExpired(response))
                    {
                        logger.Info("Ping pong request failed with session expired, trying to renew the session.");
                        SfSession.renewSession();
                    }
                    else
                    {
                        lastResultUrl = response.data?.getResultUrl;
                    }
                }

                return(BuildResultSet(response, cancellationToken));
            }
            catch (Exception ex)
            {
                logger.Error("Query execution failed.", ex);
                throw;
            }
            finally
            {
                ClearQueryRequestId();
            }
        }
 public override void Open()
 {
     logger.Debug("Open Connection.");
     SetMockSession();
     try
     {
         SfSession.Open();
     }
     catch (Exception e)
     {
         // Otherwise when Dispose() is called, the close request would timeout.
         _connectionState = System.Data.ConnectionState.Closed;
         logger.Error("Unable to connect", e);
         throw;
     }
     OnSessionEstablished();
 }
        internal void ProcessLoginResponse(LoginResponse authnResponse)
        {
            if (authnResponse.success)
            {
                sessionToken  = authnResponse.data.token;
                masterToken   = authnResponse.data.masterToken;
                database      = authnResponse.data.authResponseSessionInfo.databaseName;
                schema        = authnResponse.data.authResponseSessionInfo.schemaName;
                serverVersion = authnResponse.data.serverVersion;

                UpdateSessionParameterMap(authnResponse.data.nameValueParameter);
            }
            else
            {
                SnowflakeDbException e = new SnowflakeDbException("", authnResponse.code, authnResponse.message, "");
                logger.Error("Authentication failed", e);
                throw e;
            }
        }
Пример #11
0
 /// <summary>
 ///     Register cancel callback. Two factors: either external cancellation token passed down from upper
 ///     layer or timeout reached. Whichever comes first would trigger query cancellation.
 /// </summary>
 /// <param name="timeout">query timeout. 0 means no timeout</param>
 /// <param name="externalCancellationToken">cancellation token from upper layer</param>
 private void registerQueryCancellationCallback(int timeout, CancellationToken externalCancellationToken)
 {
     SetTimeout(timeout);
     _linkedCancellationTokenSouce = CancellationTokenSource.CreateLinkedTokenSource(_timeoutTokenSource.Token,
                                                                                     externalCancellationToken);
     if (!_linkedCancellationTokenSouce.IsCancellationRequested)
     {
         _linkedCancellationTokenSouce.Token.Register(() =>
         {
             try
             {
                 Cancel();
             }
             catch (Exception ex)
             {
                 // Prevent an unhandled exception from being thrown
                 logger.Error("Unable to cancel query.", ex);
             }
         });
     }
 }
Пример #12
0
        /// <summary>
        /// Generate the authenticator given the session
        /// </summary>
        /// <param name="session">session that requires the authentication</param>
        /// <returns>authenticator</returns>
        /// <exception cref="SnowflakeDbException">when authenticator is unknown</exception>
        internal static IAuthenticator GetAuthenticator(SFSession session)
        {
            string type = session.properties[SFSessionProperty.AUTHENTICATOR];

            if (type == "snowflake")
            {
                return(new BasicAuthenticator(session));
            }
            // Okta would provide a url of form: https://xxxxxx.okta.com
            else if (type.EndsWith("okta.com") && type.StartsWith("https://"))
            {
                return(new OktaAuthenticator(session, type));
            }

            var e = new SnowflakeDbException(SFError.UNKNOWN_AUTHENTICATOR, type);

            logger.Error("Unknown authenticator", e);

            throw e;
        }
        internal static SFSessionProperties parseConnectionString(String connectionString, SecureString password)
        {
            logger.Info("Start parsing connection string.");
            SFSessionProperties properties = new SFSessionProperties();

            string[] propertyEntry = connectionString.Split(';');

            foreach (string keyVal in propertyEntry)
            {
                if (keyVal.Length > 0)
                {
                    string[] tokens = keyVal.Split(new string[] { "=" }, StringSplitOptions.None);
                    if (tokens.Length != 2)
                    {
                        // https://docs.microsoft.com/en-us/dotnet/api/system.data.oledb.oledbconnection.connectionstring
                        // To include an equal sign (=) in a keyword or value, it must be preceded
                        // by another equal sign. For example, in the hypothetical connection
                        // string "key==word=value" :
                        // the keyword is "key=word" and the value is "value".
                        int currentIndex     = 0;
                        int singleEqualIndex = -1;
                        while (currentIndex <= keyVal.Length)
                        {
                            currentIndex = keyVal.IndexOf("=", currentIndex);
                            if (-1 == currentIndex)
                            {
                                // No '=' found
                                break;
                            }
                            if ((currentIndex < (keyVal.Length - 1)) &&
                                ('=' != keyVal[currentIndex + 1]))
                            {
                                if (0 > singleEqualIndex)
                                {
                                    // First single '=' encountered
                                    singleEqualIndex = currentIndex;
                                    currentIndex++;
                                }
                                else
                                {
                                    // Found another single '=' which is not allowed
                                    singleEqualIndex = -1;
                                    break;
                                }
                            }
                            else
                            {
                                // skip the doubled one
                                currentIndex += 2;
                            }
                        }

                        if ((singleEqualIndex > 0) && (singleEqualIndex < keyVal.Length - 1))
                        {
                            // Split the key/value at the right index and deduplicate '=='
                            tokens    = new string[2];
                            tokens[0] = keyVal.Substring(0, singleEqualIndex).Replace("==", "=");
                            tokens[1] = keyVal.Substring(
                                singleEqualIndex + 1,
                                keyVal.Length - (singleEqualIndex + 1)).Replace("==", "=");;
                        }
                        else
                        {
                            // An equal sign was not doubled or something else happened
                            // making the connection invalid
                            string invalidStringDetail =
                                String.Format("Invalid key value pair {0}", keyVal);
                            SnowflakeDbException e =
                                new SnowflakeDbException(SFError.INVALID_CONNECTION_STRING,
                                                         new object[] { invalidStringDetail });
                            logger.Error("Invalid string.", e);
                            throw e;
                        }
                    }

                    try
                    {
                        SFSessionProperty p = (SFSessionProperty)Enum.Parse(
                            typeof(SFSessionProperty), tokens[0].ToUpper());
                        properties.Add(p, tokens[1]);
                        logger.Info($"Connection property: {p}, value: {(secretProps.Contains(p) ? "XXXXXXXX" : tokens[1])}");
                    }
                    catch (ArgumentException e)
                    {
                        logger.Warn($"Property {tokens[0]} not found ignored.", e);
                    }
                }
            }

            if (password != null)
            {
                properties[SFSessionProperty.PASSWORD] = new NetworkCredential(string.Empty, password).Password;
            }
            checkSessionProperties(properties);

            // compose host value if not specified
            if (!properties.ContainsKey(SFSessionProperty.HOST) ||
                (0 == properties[SFSessionProperty.HOST].Length))
            {
                string hostName = String.Format("{0}.snowflakecomputing.com", properties[SFSessionProperty.ACCOUNT]);
                // Remove in case it's here but empty
                properties.Remove(SFSessionProperty.HOST);
                properties.Add(SFSessionProperty.HOST, hostName);
                logger.Info($"Compose host name: {hostName}");
            }

            return(properties);
        }