Skip to content

Commit

Permalink
Fixing key defaulting regression (#9309)
Browse files Browse the repository at this point in the history
  • Loading branch information
mathewc authored Jun 9, 2023
1 parent e104f5f commit 92e3dd8
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -44,15 +44,12 @@ public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationTok

if (!string.IsNullOrEmpty(token))
{
if (SecretsUtility.TryGetEncryptionKey(out string key))
var signingKeys = SecretsUtility.GetTokenIssuerSigningKeys();
if (signingKeys.Length > 0)
{
var validationParameters = new TokenValidationParameters()
{
IssuerSigningKeys = new SecurityKey[]
{
new SymmetricSecurityKey(key.ToKeyBytes()),
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
},
IssuerSigningKeys = signingKeys,
ValidateAudience = true,
ValidateIssuer = true,
ValidAudiences = new string[]
Expand Down
27 changes: 27 additions & 0 deletions src/WebJobs.Script.WebHost/Security/SecretsUtility.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@
// Licensed under the MIT License. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Azure.Web.DataProtection;
using Microsoft.IdentityModel.Tokens;

namespace Microsoft.Azure.WebJobs.Script.WebHost
{
Expand Down Expand Up @@ -54,6 +57,30 @@ public static byte[] GetEncryptionKey()
return key.ToKeyBytes();
}

public static SymmetricSecurityKey[] GetTokenIssuerSigningKeys()
{
List<SymmetricSecurityKey> signingKeys = new List<SymmetricSecurityKey>();

// first we want to use the DataProtection APIs to get the default key,
// which will return any user specified AzureWebEncryptionKey with precedence
// over the platform default key
string defaultKey = Util.GetDefaultKeyValue();
if (defaultKey != null)
{
signingKeys.Add(new SymmetricSecurityKey(defaultKey.ToKeyBytes()));
signingKeys.Add(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(defaultKey)));
}

// next we want to ensure a key is also added for the platform default key
// if it wasn't already added above
if (SecretsUtility.TryGetEncryptionKey(out string key) && !string.Equals(key, defaultKey))
{
signingKeys.Add(new SymmetricSecurityKey(key.ToKeyBytes()));
}

return signingKeys.ToArray();
}

public static bool TryGetEncryptionKey(string keyName, out string encryptionKey)
{
encryptionKey = Environment.GetEnvironmentVariable(keyName);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
using System.Net;
using System.Net.Http;
using System.Net.Http.Headers;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Web.Http.Controllers;
Expand All @@ -15,6 +16,7 @@
using Microsoft.Azure.WebJobs.Extensions.Http;
using Microsoft.Azure.WebJobs.Script.WebHost;
using Microsoft.Azure.WebJobs.Script.WebHost.Filters;
using Microsoft.Azure.WebJobs.Script.WebHost.Security;
using Microsoft.IdentityModel.Tokens;
using Xunit;
using static Microsoft.Azure.WebJobs.Script.Config.ScriptSettingsManager;
Expand All @@ -26,6 +28,7 @@ namespace Microsoft.Azure.WebJobs.Script.Tests.Filters
public class JwtAuthenticationAttributeTests : IDisposable
{
private const string TestKeyValue = "0F75CA46E7EBDD39E4CA6B074D1F9A5972B849A55F91A248";
private const string PlatformDefaultKeyValue = "B77F872A341F8970D50F093E1FA924777A5A61CCABC63C2A";
private const string TestAppName = "testsite";
private TestScopedEnvironmentVariable _testEnv;

Expand All @@ -34,6 +37,7 @@ public JwtAuthenticationAttributeTests()
var values = new Dictionary<string, string>
{
{ "AzureWebEncryptionKey", TestKeyValue },
{ EnvironmentSettingNames.WebsiteAuthEncryptionKey, PlatformDefaultKeyValue },
{ AzureWebsiteName, TestAppName }
};
_testEnv = new TestScopedEnvironmentVariable(values);
Expand All @@ -56,12 +60,27 @@ public async Task AuthenticateAsync_WithValidToken_SetsAdminAuthorizationLevel(s
{
issuer = issuer ?? string.Format(ScmSiteUriFormat, Instance.GetSetting(AzureWebsiteName));
audience = audience ?? string.Format(SiteAzureFunctionsUriFormat, Instance.GetSetting(AzureWebsiteName));

string token = JwtGenerator.GenerateToken(issuer, audience, expires: DateTime.UtcNow.AddMinutes(10));
string token = JwtTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(10), audience, issuer);

await AuthenticateAsync(token, headerName, AuthorizationLevel.Admin);
}

[Theory]
[InlineData("AzureWebEncryptionKey", true)]
[InlineData("AzureWebEncryptionKey", false)]
[InlineData(EnvironmentSettingNames.WebsiteAuthEncryptionKey, true)]
public async Task AuthenticateAsync_WithValidToken_WithSupportedKeyConfigurations_SetsAdminAuthorizationLevel(string keyName, bool hexEncoding)
{
string issuer = "https://testsite.azurewebsites.net";
string audience = "https://testsite.azurewebsites.net";

string keyValue = Environment.GetEnvironmentVariable(keyName);
byte[] key = hexEncoding ? keyValue.ToKeyBytes() : Encoding.UTF8.GetBytes(keyValue);
string token = JwtTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(10), audience, issuer, key);

await AuthenticateAsync(token, ScriptConstants.SiteTokenHeaderName, AuthorizationLevel.Admin);
}

[Theory]
[InlineData(-10, null, null)] // Our default clock skew setting is 5 minutes
[InlineData(10, "invalid", null)]
Expand Down

0 comments on commit 92e3dd8

Please sign in to comment.