예제 #1
0
        private async Task <T> GetKeyObjectFromFile <T>(string name, IKeyJsonOps <T> keyOp)
        {
            var secretStorageType = System.Environment.GetEnvironmentVariable(Constants.AzureWebJobsSecretStorageType);

            if (!string.IsNullOrEmpty(secretStorageType) &&
                secretStorageType.Equals("Blob", StringComparison.OrdinalIgnoreCase))
            {
                throw new InvalidOperationException("Runtime keys are stored on blob storage. This API doesn't support this configuration.");
            }

            string keyPath = GetFunctionSecretsFilePath(name);
            string key     = null;

            if (!FileSystemHelpers.FileExists(keyPath) || FileSystemHelpers.FileInfoFromFileName(keyPath).Length == 0)
            {
                FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(keyPath));
                try
                {
                    using (var fileStream = FileSystemHelpers.OpenFile(keyPath, FileMode.Create, FileAccess.Write, FileShare.None))
                    // getting the lock early (instead of acquire the lock at "new StreamWriter(fileStream)")
                    // so no redundant work is being done (generate secrets)
                    {
                        string jsonContent = keyOp.GenerateKeyJson(SecurityUtility.GenerateSecretStringsKeyPair(keyOp.NumberOfKeysInDefaultFormat), FunctionSiteExtensionVersion, out key);
                        using (var sw = new StringWriter())
                            using (var sr = new System.IO.StringReader(jsonContent))
                            {
                                // write json to memory
                                // since JsonConvert has no method to format a json string
                                new JsonTextWriter(sw)
                                {
                                    Formatting = Formatting.Indented
                                }.WriteToken(new JsonTextReader(sr));
                                using (var streamWriter = new StreamWriter(fileStream))
                                {
                                    await streamWriter.WriteAsync(sw.ToString());

                                    await streamWriter.FlushAsync();
                                }
                            }
                    }
                    return(keyOp.GenerateKeyObject(key, name));
                }
                catch (IOException)
                {
                    // failed to open file => function runtime has the handler
                    // fallback to read key files
                }
            }

            string jsonStr = null;
            int    timeOut = 5;

            while (true)
            {
                try
                {
                    jsonStr = await FileSystemHelpers.ReadAllTextFromFileAsync(keyPath);

                    break;
                }
                catch (Exception)
                {
                    if (timeOut == 0)
                    {
                        throw new TimeoutException($"Fail to read {keyPath}, the file is being held by another process");
                    }
                    timeOut--;
                    await Task.Delay(250);
                }
            }

            bool isEncrypted;

            key = keyOp.GetKeyValueFromJson(jsonStr, out isEncrypted);
            if (isEncrypted)
            {
                key = SecurityUtility.DecryptSecretString(key);
            }
            return(keyOp.GenerateKeyObject(key, name));
        }
예제 #2
0
        private async Task <T> GetKeyObjectFromFile <T>(string name, IKeyJsonOps <T> keyOp)
        {
            string keyPath = GetFunctionSecretsFilePath(name);
            string key     = null;

            if (!FileSystemHelpers.FileExists(keyPath))
            {
                FileSystemHelpers.EnsureDirectory(Path.GetDirectoryName(keyPath));
                try
                {
                    using (var fileStream = FileSystemHelpers.OpenFile(keyPath, FileMode.CreateNew, FileAccess.Write, FileShare.None))
                    // will fail if file exists, prevent reading prematurely
                    // getting the lock early so no redundant work is being done
                    {
                        string jsonContent = keyOp.GenerateKeyJson(SecurityUtility.GenerateSecretStringsKeyPair(keyOp.NumberOfKeysInDefaultFormat), FunctionSiteExtensionVersion, out key);
                        using (var sw = new StringWriter())
                            using (var sr = new System.IO.StringReader(jsonContent))
                            {
                                new JsonTextWriter(sw)
                                {
                                    Formatting = Formatting.Indented
                                }.WriteToken(new JsonTextReader(sr));
                                // if lock acquire lock return false, I wait until write finishes and read keyPath
                                using (var streamWriter = new StreamWriter(fileStream))
                                {
                                    await streamWriter.WriteAsync(sw.ToString());

                                    await streamWriter.FlushAsync();
                                }
                            }
                    }
                    return(keyOp.GenerateKeyObject(key, name));
                }
                catch (IOException)
                {
                    // don't throw exception if the file already existed
                    // fallback to read key files
                }
            }

            string jsonStr = null;
            int    timeOut = 5;

            while (true)
            {
                try
                {
                    jsonStr = await FileSystemHelpers.ReadAllTextFromFileAsync(keyPath);

                    break;
                }
                catch (Exception)
                {
                    if (timeOut == 0)
                    {
                        throw new TimeoutException($"Fail to read {keyPath}, the file is being held by another process");
                    }
                    timeOut--;
                    await Task.Delay(250);
                }
            }

            bool isEncrypted;

            key = keyOp.GetKeyValueFromJson(jsonStr, out isEncrypted);
            if (isEncrypted)
            {
                key = SecurityUtility.DecryptSecretString(key);
            }
            return(keyOp.GenerateKeyObject(key, name));
        }