Azure / Azure/azure-functions-host

Function Key Management API is not case-sensitive , causing 404 as well as previous key overridden

Open
#2,687 10 comments 0 reactions 1 assignee Claimed by @fabiocav View on GitHub
2.x bug
Dominant language
C#
Stars
2k
Forks
482
Avg merge
2d 10h
Merged PRs (30d)
36

Description

When using the Functions App Management API to get and set Function Keys ( https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/[KeyName] ) the In- and Output is caseSensitive, but the keys are overwritten if a key with the same name (not caseSensitive) already exists.

For example, if we want to look at two Function Keys: TestKey & testKey

See if key exists:

> GET https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/TestKey
--> Response: 404

Create key with captial 'T':

> POST https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/TestKey
--> Response: {..... TestKey}

See if Key exists now:

> GET https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/TestKey
--> Response: {..... TestKey}

See if Key with small 't' exists:

> GET https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/testKey
--> Response: 404

Create Key with small 't':

> POST https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/testKey
--> Response: {..... testKey}

See if both keys exist:

> GET https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/TestKey
--> Response: 404

> GET https://[FunctionAppName].azurewebsites.net/admin/functions/[FunctionName]/keys/testKey
--> Response: {... testKey}

_**Point to Note : if we create keys from Azure portal , then angular UI already takes care of that and doesn't allow to create duplicate keys irrespective of case/Ordinal.**_

#### Investigative information
-- POST mykey1
{"name":"mykey1","value":"jZMEduaHRZDDxC7P90MaYNGNmKjdMuq8ANaTd/UH7UVVB/5ZHAKMkQ==","links":[{"rel":"self","href":"https://fnzipdeploye.azurewebsites.net/admin/functions/HttpTriggerCSharp1/keys/mykey1"}]}

-- GET mykey1
{"name":"mykey1","value":"jZMEduaHRZDDxC7P90MaYNGNmKjdMuq8ANaTd/UH7UVVB/5ZHAKMkQ==","links":[{"rel":"self","href":"https://fnzipdeploye.azurewebsites.net/admin/functions/HttpTriggerCSharp1/keys/mykey1"}]}

-- GET KEYS
{"keys":[{"name":"abc","value":"/CMCsDahlK0dHTEjX12O4jqXbdx7llK0H0MgXhK55sy6a6X3H85vuw=="},
{"name":"my2","value":"rUPEOrpfH8LKhLRKVAAtb58aT0VP4egaGkST09j6TFbsMCjfDc1/VQ=="},
{"name":"my1","value":"G3xrlTWQy3NRMRYi7nVze5CALCuqdfcq1wesHxrPJPaM90ysRPTfZw=="},
{"name":"mykey1","value":"jZMEduaHRZDDxC7P90MaYNGNmKjdMuq8ANaTd/UH7UVVB/5ZHAKMkQ=="}],
"links":[{"rel":"self","href":"https://fnzipdeploye.azurewebsites.net/admin/functions/HttpTriggerCSharp1/keys/"}]}

-- POST Mykey1
{"name":"Mykey1","value":"Ii0ReLaxsdp4mNw7ooV4ENSb71e0NCZP85EhNe2vDhyzVtTUJoVs1A==","links":[{"rel":"self","href":"https://fnzipdeploye.azurewebsites.net/admin/functions/HttpTriggerCSharp1/keys/Mykey1"}]}

-- GET Mykey1
{"name":"Mykey1","value":"Ii0ReLaxsdp4mNw7ooV4ENSb71e0NCZP85EhNe2vDhyzVtTUJoVs1A==","links":[{"rel":"self","href":"https://fnzipdeploye.azurewebsites.net/admin/functions/HttpTriggerCSharp1/keys/Mykey1"}]}

-- GET KEYS
{"keys":[{"name":"abc","value":"/CMCsDahlK0dHTEjX12O4jqXbdx7llK0H0MgXhK55sy6a6X3H85vuw=="},
{"name":"my2","value":"rUPEOrpfH8LKhLRKVAAtb58aT0VP4egaGkST09j6TFbsMCjfDc1/VQ=="},
{"name":"my1","value":"G3xrlTWQy3NRMRYi7nVze5CALCuqdfcq1wesHxrPJPaM90ysRPTfZw=="},
{"name":"Mykey1","value":"Ii0ReLaxsdp4mNw7ooV4ENSb71e0NCZP85EhNe2vDhyzVtTUJoVs1A=="}],"links":[{"rel":"self","href":"https://fnzipdeploye.azurewebsites.net/admin/functions/HttpTriggerCSharp1/keys"}]}

-- GET mykey1
returns 404.

#### Expected behavior

1) Either should say that Key already exist and doesn't let create key using POST.
2)OR , if we want to maintain both keys , then it should not remove previous key from collection.

#### Related information in source Code

`[HttpPost]
[Route("admin/functions/{name}/keys/{keyName}")]
public Task Post(string name, string keyName) => AddOrUpdateSecretAsync(keyName, null, name, ScriptSecretsType.Function);`

**this internally calls , which is actually creating this new Key with case changed , but at the same time seems to be deleting old key.**

```
private async Task AddOrUpdateSecretAsync(ScriptSecretsType secretsType, string keyScope, string secretName, string secret, Func secretsFactory)
{
OperationResult result = OperationResult.NotFound;
secret = secret ?? GenerateSecret();
await ModifyFunctionSecretsAsync(secretsType, keyScope, secrets =>
{
Key key = secrets.GetFunctionKey(secretName, keyScope);

var createAndUpdateKey = new Action((o) =>
{
var newKey = CreateKey(secretName, secret);
secrets.AddKey(newKey, keyScope);
result = o;
});

if (key == null)
{
createAndUpdateKey(OperationResult.Created);
}
else if (secrets.RemoveKey(key, keyScope))
{
createAndUpdateKey(OperationResult.Updated);
}

return secrets;
}, secretsFactory);

return new KeyOperationResult(secret, result);
}
````

**Expectation :**
1) If we want to keep this thing case sensitive, then both key should exist.
2) we don’t want it to be case sensitive, then do not delete previous key from keys collection & then irrespective of key cases, the key should be retrieved and should not throw 404.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.