public async virtual Task <IDictionary <string, string> > GetFunctionSecretsAsync(string functionName, bool merged = false)
        {
            if (string.IsNullOrEmpty(functionName))
            {
                throw new ArgumentNullException(nameof(functionName));
            }

            functionName = functionName.ToLowerInvariant();
            Dictionary <string, string> functionSecrets;

            _secretsMap.TryGetValue(functionName, out functionSecrets);

            if (functionSecrets == null)
            {
                FunctionSecrets secrets = await LoadFunctionSecretsAsync(functionName);

                if (secrets == null)
                {
                    _traceWriter.VerboseFormat(Resources.TraceFunctionSecretGeneration, functionName);
                    secrets = new FunctionSecrets
                    {
                        Keys = new List <Key>
                        {
                            GenerateKey(ScriptConstants.DefaultFunctionKeyName)
                        }
                    };

                    await PersistSecretsAsync(secrets, functionName);
                }

                // Read all secrets, which will run the keys through the appropriate readers
                secrets.Keys = secrets.Keys.Select(k => _keyValueConverterFactory.ReadKey(k)).ToList();

                if (secrets.HasStaleKeys)
                {
                    _traceWriter.VerboseFormat(Resources.TraceStaleFunctionSecretRefresh, functionName);
                    await RefreshSecretsAsync(secrets, functionName);
                }

                Dictionary <string, string> result = secrets.Keys.ToDictionary(s => s.Name, s => s.Value);

                functionSecrets = _secretsMap.AddOrUpdate(functionName, result, (n, r) => result);
            }

            if (merged)
            {
                // If merged is true, we combine function specific keys with host level function keys,
                // prioritizing function specific keys
                HostSecretsInfo hostSecrets = await GetHostSecretsAsync();

                Dictionary <string, string> hostFunctionSecrets = hostSecrets.FunctionKeys;

                functionSecrets = functionSecrets.Union(hostFunctionSecrets.Where(s => !functionSecrets.ContainsKey(s.Key)))
                                  .ToDictionary(kv => kv.Key, kv => kv.Value);
            }

            return(functionSecrets);
        }
Beispiel #2
0
        public virtual IDictionary <string, string> GetFunctionSecrets(string functionName, bool merged = false)
        {
            if (string.IsNullOrEmpty(functionName))
            {
                throw new ArgumentNullException(nameof(functionName));
            }

            functionName = functionName.ToLowerInvariant();

            var functionSecrets = _secretsMap.GetOrAdd(functionName, n =>
            {
                FunctionSecrets secrets;
                string secretsFilePath = GetFunctionSecretsFilePath(functionName);
                if (!TryLoadFunctionSecrets(functionName, out secrets, secretsFilePath))
                {
                    _traceWriter.VerboseFormat(Resources.TraceFunctionSecretGeneration, functionName);
                    secrets = new FunctionSecrets
                    {
                        Keys = new List <Key>
                        {
                            GenerateKey(ScriptConstants.DefaultFunctionKeyName)
                        }
                    };

                    PersistSecrets(secrets, secretsFilePath);
                }

                // Read all secrets, which will run the keys through the appropriate readers
                secrets.Keys = secrets.Keys.Select(k => _keyValueConverterFactory.ReadKey(k)).ToList();

                if (secrets.HasStaleKeys)
                {
                    _traceWriter.VerboseFormat(Resources.TraceStaleFunctionSecretRefresh, functionName);
                    RefreshSecrets(secrets, secretsFilePath);
                }

                return(secrets.Keys.ToDictionary(s => s.Name, s => s.Value));
            });

            if (merged)
            {
                // If merged is true, we combine function specific keys with host level function keys,
                // prioritizing function specific keys
                Dictionary <string, string> hostFunctionSecrets = GetHostSecrets().FunctionKeys;

                functionSecrets = functionSecrets.Union(hostFunctionSecrets.Where(s => !functionSecrets.ContainsKey(s.Key)))
                                  .ToDictionary(kv => kv.Key, kv => kv.Value);
            }

            return(functionSecrets);
        }
        private IHttpActionResult AddOrUpdateFunctionSecret(string keyName, string value, string functionName = null)
        {
            if (functionName != null &&
                !_scriptHostManager.Instance.Functions.Any(f => string.Equals(f.Name, functionName, StringComparison.OrdinalIgnoreCase)))
            {
                return(NotFound());
            }

            KeyOperationResult operationResult;

            if (functionName == null && string.Equals(keyName, MasterKeyName, StringComparison.OrdinalIgnoreCase))
            {
                operationResult = _secretManager.SetMasterKey(value);
            }
            else
            {
                operationResult = _secretManager.AddOrUpdateFunctionSecret(keyName, value, functionName);
            }

            _traceWriter.VerboseFormat(Resources.TraceKeysApiSecretChange, keyName, functionName ?? "host", operationResult.Result);

            switch (operationResult.Result)
            {
            case OperationResult.Created:
            {
                var keyResponse = ApiModelUtility.CreateApiModel(new { name = keyName, value = operationResult.Secret }, Request);
                return(Created(ApiModelUtility.GetBaseUri(Request), keyResponse));
            }

            case OperationResult.Updated:
            {
                var keyResponse = ApiModelUtility.CreateApiModel(new { name = keyName, value = operationResult.Secret }, Request);
                return(Ok(keyResponse));
            }

            case OperationResult.NotFound:
                return(NotFound());

            case OperationResult.Conflict:
                return(Conflict());

            default:
                return(InternalServerError());
            }
        }
        private async Task <IHttpActionResult> AddOrUpdateSecretAsync(string keyName, string value, string keyScope, ScriptSecretsType secretsType)
        {
            if (secretsType == ScriptSecretsType.Function && keyScope != null && !_scriptHostManager.Instance.IsFunction(keyScope))
            {
                return(NotFound());
            }

            KeyOperationResult operationResult;

            if (secretsType == ScriptSecretsType.Host && string.Equals(keyName, MasterKeyName, StringComparison.OrdinalIgnoreCase))
            {
                operationResult = await _secretManager.SetMasterKeyAsync(value);
            }
            else
            {
                operationResult = await _secretManager.AddOrUpdateFunctionSecretAsync(keyName, value, keyScope, secretsType);
            }

            _traceWriter.VerboseFormat(Resources.TraceKeysApiSecretChange, keyName, keyScope ?? "host", operationResult.Result);

            switch (operationResult.Result)
            {
            case OperationResult.Created:
            {
                var keyResponse = ApiModelUtility.CreateApiModel(new { name = keyName, value = operationResult.Secret }, Request);
                return(Created(ApiModelUtility.GetBaseUri(Request), keyResponse));
            }

            case OperationResult.Updated:
            {
                var keyResponse = ApiModelUtility.CreateApiModel(new { name = keyName, value = operationResult.Secret }, Request);
                return(Ok(keyResponse));
            }

            case OperationResult.NotFound:
                return(NotFound());

            case OperationResult.Conflict:
                return(Conflict());

            default:
                return(InternalServerError());
            }
        }
        private async Task <IHttpActionResult> DeleteFunctionSecretAsync(string keyName, string keyScope, ScriptSecretsType secretsType)
        {
            if (keyName == null || keyName.StartsWith("_"))
            {
                // System keys cannot be deleted.
                return(BadRequest("Invalid key name."));
            }

            if ((secretsType == ScriptSecretsType.Function && !_scriptHostManager.Instance.IsFunction(keyScope)) ||
                !await _secretManager.DeleteSecretAsync(keyName, keyScope, secretsType))
            {
                // Either the function or the key were not found
                return(NotFound());
            }

            string message = string.Format(Resources.TraceKeysApiSecretChange, keyName, keyScope ?? "host", "Deleted");

            _traceWriter.VerboseFormat(message);
            _logger?.LogDebug(message);

            return(StatusCode(HttpStatusCode.NoContent));
        }