partial void PrepareRequest(Transaction body, HttpClient client, HttpRequestMessage request, string url)
        {
            var uriBuilder = new UriBuilder(request.RequestUri);
            var query      = HttpUtility.ParseQueryString(uriBuilder.Query);

            if (conn is LocalConnection)
            {
                query["dbname"] = conn.DbName;
                if (!_isEmpty(body.Source_dbname))
                {
                    query["source_dbname"] = body.Source_dbname;
                }
            }
            query["open_mode"] = body.Mode.ToString();
            if (conn is ManagementConnection || conn is CloudConnection)
            {
                query["region"] = EnumString.GetDescription(conn.Region);
            }
            if (conn is CloudConnection)
            {
                query["compute_name"] = conn.ComputeName;
            }
            uriBuilder.Query   = query.ToString();
            request.RequestUri = uriBuilder.Uri;

            // populate headers
            request.Headers.Host = request.RequestUri.Host;
            request.Content.Headers.ContentType = MediaTypeHeaderValue.Parse("application/json; charset=utf-8");

            // sign request here
            var raiRequest = new RAIRequest(request, conn);

            raiRequest.Sign(debugLevel: DebugLevel);
            DelveClient.AddExtraHeaders(request);

            // use HTTP 2.0 (to handle keep-alive)
            request.Version = System.Net.HttpVersion.Version20;

            // have a separate keep-alive task (per thread)
            if (!isStatusRequest(body))
            {
                var tokenSource = new CancellationTokenSource();
                AsyncLocalKeepAliveCancellationTokenSource.Value = tokenSource;
                CancellationToken ct = tokenSource.Token;

                /**
                 * TODO: currently we swallo exceptions in KeepClientAlive.
                 * If we want to throw, then we need to change this to asynchronously handle the throw
                 * e.g.
                 * try {
                 *   await this.KeepClientAlive(client, url, ct).ConfigureAwait(false);
                 * } catch (Exception e) {
                 *   // Handle here
                 * }
                 **/
                var keep_alive_task = this.KeepClientAlive(client, url, ct).ConfigureAwait(false);
            }
        }
Example #2
0
        public ComputeInfoProtocol CreateCompute(string name, RAIComputeSize size = RAIComputeSize.XS, string region = null, bool dryRun = false)
        {
            if (region == null)
            {
                region = EnumString.GetDescription(this.conn.Region);
            }

            CreateComputeRequestProtocol request = new CreateComputeRequestProtocol();

            request.Region = region;
            request.Name   = name;
            request.Size   = EnumString.GetDescription(size);
            request.Dryrun = dryRun;
            return(this.ComputePutAsync(request).Result.Compute);
        }
        public void Sign(DateTime t, string[] includeHeaders = null, int debugLevel = 1)
        {
            if (includeHeaders == null)
            {
                includeHeaders = new string[] { "host", "content-type", "x-rai-date" };
            }
            if (this.Creds == null)
            {
                return;
            }

            // ISO8601 date/time strings for time of request
            string signatureDate = String.Format("{0:yyyyMMddTHHmmssZ}", t);
            string scopeDate     = String.Format("{0:yyyyMMdd}", t);

            // Authentication scope
            string scope = string.Join("/", new string[] {
                scopeDate, EnumString.GetDescription(this.Region), this.Service, "rai01_request"
            });

            // SHA256 hash of content
            Sha256 shaw256HashAlgo = new Sha256();

            byte[] reqContent  = InnerReq.Content.ReadAsByteArrayAsync().Result;
            byte[] sha256Hash  = shaw256HashAlgo.Hash(reqContent);
            string contentHash = sha256Hash.ToHex();

            // HTTP headers
            InnerReq.Headers.Authorization = null;
            // Include "x-rai-date" in signed headers
            if (!InnerReq.Headers.Contains("x-rai-date"))
            {
                InnerReq.Headers.TryAddWithoutValidation("x-rai-date", signatureDate);
            }

            var allHeaders = InnerReq.Headers.Union(InnerReq.Content.Headers);

            // Sort and lowercase() Headers to produce canonical form
            string canonicalHeaders = string.Join(
                "\n",
                from header in allHeaders
                orderby header.Key.ToLower()
                where includeHeaders.Contains(header.Key.ToLower())
                select string.Format(
                    "{0}:{1}",
                    header.Key.ToLower(),
                    string.Join(",", header.Value).Trim()
                    )
                );
            string signedHeaders = string.Join(
                ";",
                from header in allHeaders
                orderby header.Key.ToLower()
                where includeHeaders.Contains(header.Key.ToLower())
                select header.Key.ToLower()
                );

            // Sort Query String
            var parsedQuery     = HttpUtility.ParseQueryString(InnerReq.RequestUri.Query);
            var parsedQueryDict = parsedQuery.AllKeys.SelectMany(
                parsedQuery.GetValues, (k, v) => new { key = k, value = v }
                );
            string query = string.Join(
                "&",
                from qparam in parsedQueryDict
                orderby qparam.key, qparam.value
                select string.Format(
                    "{0}={1}",
                    HttpUtility.UrlEncode(qparam.key),
                    HttpUtility.UrlEncode(qparam.value))
                );

            // Create hash of canonical request
            string canonicalForm = string.Format(
                "{0}\n{1}\n{2}\n{3}\n\n{4}\n{5}",
                InnerReq.Method,
                HttpUtility.UrlPathEncode(InnerReq.RequestUri.AbsolutePath),
                query,
                canonicalHeaders,
                signedHeaders,
                contentHash
                );

            if (debugLevel > 2)
            {
                Console.WriteLine("reqContent:");
                Console.WriteLine(System.Text.Encoding.Default.GetString(reqContent));
                Console.WriteLine("canonical_form:");
                Console.WriteLine(canonicalForm);
                Console.WriteLine();
            }

            sha256Hash = shaw256HashAlgo.Hash(Encoding.UTF8.GetBytes(canonicalForm));
            string canonicalHash = sha256Hash.ToHex();

            // Create and sign "String to Sign"
            string stringToSign = string.Format(
                "RAI01-ED25519-SHA256\n{0}\n{1}\n{2}", signatureDate, scope, canonicalHash
                );

            byte[] seed = Convert.FromBase64String(Creds.PrivateKey);

            // select the Ed25519 signature algorithm
            var algorithm = SignatureAlgorithm.Ed25519;

            // create a new key pair
            using var key = Key.Import(algorithm, seed, KeyBlobFormat.RawPrivateKey);

            // sign the data using the private key
            byte[] signature = algorithm.Sign(key, Encoding.UTF8.GetBytes(stringToSign));

            string sig = signature.ToHex();

            if (debugLevel > 2)
            {
                Console.WriteLine("string_to_sign:");
                Console.WriteLine(stringToSign);
                Console.WriteLine();
                Console.WriteLine("signature:");
                Console.WriteLine(sig);
                Console.WriteLine();
            }

            var authHeader = string.Format(
                "RAI01-ED25519-SHA256 Credential={0}/{1}, SignedHeaders={2}, Signature={3}",
                Creds.AccessKey,
                scope,
                signedHeaders,
                sig
                );

            InnerReq.Headers.TryAddWithoutValidation("Authorization", authHeader);
        }