Skip to content

Commit 92e3dd8

Browse files
authored
Fixing key defaulting regression (#9309)
1 parent e104f5f commit 92e3dd8

File tree

3 files changed

+51
-8
lines changed

3 files changed

+51
-8
lines changed

src/WebJobs.Script.WebHost/Filters/JwtAuthenticationAttribute.cs

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -44,15 +44,12 @@ public Task AuthenticateAsync(HttpAuthenticationContext context, CancellationTok
4444

4545
if (!string.IsNullOrEmpty(token))
4646
{
47-
if (SecretsUtility.TryGetEncryptionKey(out string key))
47+
var signingKeys = SecretsUtility.GetTokenIssuerSigningKeys();
48+
if (signingKeys.Length > 0)
4849
{
4950
var validationParameters = new TokenValidationParameters()
5051
{
51-
IssuerSigningKeys = new SecurityKey[]
52-
{
53-
new SymmetricSecurityKey(key.ToKeyBytes()),
54-
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
55-
},
52+
IssuerSigningKeys = signingKeys,
5653
ValidateAudience = true,
5754
ValidateIssuer = true,
5855
ValidAudiences = new string[]

src/WebJobs.Script.WebHost/Security/SecretsUtility.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,11 @@
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

44
using System;
5+
using System.Collections.Generic;
56
using System.Linq;
7+
using System.Text;
68
using Microsoft.Azure.Web.DataProtection;
9+
using Microsoft.IdentityModel.Tokens;
710

811
namespace Microsoft.Azure.WebJobs.Script.WebHost
912
{
@@ -54,6 +57,30 @@ public static byte[] GetEncryptionKey()
5457
return key.ToKeyBytes();
5558
}
5659

60+
public static SymmetricSecurityKey[] GetTokenIssuerSigningKeys()
61+
{
62+
List<SymmetricSecurityKey> signingKeys = new List<SymmetricSecurityKey>();
63+
64+
// first we want to use the DataProtection APIs to get the default key,
65+
// which will return any user specified AzureWebEncryptionKey with precedence
66+
// over the platform default key
67+
string defaultKey = Util.GetDefaultKeyValue();
68+
if (defaultKey != null)
69+
{
70+
signingKeys.Add(new SymmetricSecurityKey(defaultKey.ToKeyBytes()));
71+
signingKeys.Add(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(defaultKey)));
72+
}
73+
74+
// next we want to ensure a key is also added for the platform default key
75+
// if it wasn't already added above
76+
if (SecretsUtility.TryGetEncryptionKey(out string key) && !string.Equals(key, defaultKey))
77+
{
78+
signingKeys.Add(new SymmetricSecurityKey(key.ToKeyBytes()));
79+
}
80+
81+
return signingKeys.ToArray();
82+
}
83+
5784
public static bool TryGetEncryptionKey(string keyName, out string encryptionKey)
5885
{
5986
encryptionKey = Environment.GetEnvironmentVariable(keyName);

test/WebJobs.Script.Tests/Filters/JwtAuthenticationAttributeTests.cs

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
using System.Net;
88
using System.Net.Http;
99
using System.Net.Http.Headers;
10+
using System.Text;
1011
using System.Threading;
1112
using System.Threading.Tasks;
1213
using System.Web.Http.Controllers;
@@ -15,6 +16,7 @@
1516
using Microsoft.Azure.WebJobs.Extensions.Http;
1617
using Microsoft.Azure.WebJobs.Script.WebHost;
1718
using Microsoft.Azure.WebJobs.Script.WebHost.Filters;
19+
using Microsoft.Azure.WebJobs.Script.WebHost.Security;
1820
using Microsoft.IdentityModel.Tokens;
1921
using Xunit;
2022
using static Microsoft.Azure.WebJobs.Script.Config.ScriptSettingsManager;
@@ -26,6 +28,7 @@ namespace Microsoft.Azure.WebJobs.Script.Tests.Filters
2628
public class JwtAuthenticationAttributeTests : IDisposable
2729
{
2830
private const string TestKeyValue = "0F75CA46E7EBDD39E4CA6B074D1F9A5972B849A55F91A248";
31+
private const string PlatformDefaultKeyValue = "B77F872A341F8970D50F093E1FA924777A5A61CCABC63C2A";
2932
private const string TestAppName = "testsite";
3033
private TestScopedEnvironmentVariable _testEnv;
3134

@@ -34,6 +37,7 @@ public JwtAuthenticationAttributeTests()
3437
var values = new Dictionary<string, string>
3538
{
3639
{ "AzureWebEncryptionKey", TestKeyValue },
40+
{ EnvironmentSettingNames.WebsiteAuthEncryptionKey, PlatformDefaultKeyValue },
3741
{ AzureWebsiteName, TestAppName }
3842
};
3943
_testEnv = new TestScopedEnvironmentVariable(values);
@@ -56,12 +60,27 @@ public async Task AuthenticateAsync_WithValidToken_SetsAdminAuthorizationLevel(s
5660
{
5761
issuer = issuer ?? string.Format(ScmSiteUriFormat, Instance.GetSetting(AzureWebsiteName));
5862
audience = audience ?? string.Format(SiteAzureFunctionsUriFormat, Instance.GetSetting(AzureWebsiteName));
59-
60-
string token = JwtGenerator.GenerateToken(issuer, audience, expires: DateTime.UtcNow.AddMinutes(10));
63+
string token = JwtTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(10), audience, issuer);
6164

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

68+
[Theory]
69+
[InlineData("AzureWebEncryptionKey", true)]
70+
[InlineData("AzureWebEncryptionKey", false)]
71+
[InlineData(EnvironmentSettingNames.WebsiteAuthEncryptionKey, true)]
72+
public async Task AuthenticateAsync_WithValidToken_WithSupportedKeyConfigurations_SetsAdminAuthorizationLevel(string keyName, bool hexEncoding)
73+
{
74+
string issuer = "https://testsite.azurewebsites.net";
75+
string audience = "https://testsite.azurewebsites.net";
76+
77+
string keyValue = Environment.GetEnvironmentVariable(keyName);
78+
byte[] key = hexEncoding ? keyValue.ToKeyBytes() : Encoding.UTF8.GetBytes(keyValue);
79+
string token = JwtTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(10), audience, issuer, key);
80+
81+
await AuthenticateAsync(token, ScriptConstants.SiteTokenHeaderName, AuthorizationLevel.Admin);
82+
}
83+
6584
[Theory]
6685
[InlineData(-10, null, null)] // Our default clock skew setting is 5 minutes
6786
[InlineData(10, "invalid", null)]

0 commit comments

Comments
 (0)