Skip to content

Commit 71193d6

Browse files
authored
Fixing key defaulting regression (#9307)
1 parent 3f6da05 commit 71193d6

File tree

3 files changed

+60
-17
lines changed

3 files changed

+60
-17
lines changed

src/WebJobs.Script.WebHost/Security/Authentication/Jwt/ScriptJwtBearerExtensions.cs

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33

44
using System.Linq;
55
using System.Security.Claims;
6-
using System.Text;
76
using System.Threading;
87
using System.Threading.Tasks;
98
using Microsoft.AspNetCore.Authentication;
@@ -73,15 +72,11 @@ public static AuthenticationBuilder AddScriptJwtBearer(this AuthenticationBuilde
7372

7473
private static TokenValidationParameters CreateTokenValidationParameters()
7574
{
75+
var signingKeys = SecretsUtility.GetTokenIssuerSigningKeys();
7676
var result = new TokenValidationParameters();
77-
if (SecretsUtility.TryGetEncryptionKey(out string key))
77+
if (signingKeys.Length > 0)
7878
{
79-
// TODO: Once ScriptSettingsManager is gone, Audience and Issuer should be pulled from configuration.
80-
result.IssuerSigningKeys = new SecurityKey[]
81-
{
82-
new SymmetricSecurityKey(key.ToKeyBytes()),
83-
new SymmetricSecurityKey(Encoding.UTF8.GetBytes(key))
84-
};
79+
result.IssuerSigningKeys = signingKeys;
8580
result.ValidateAudience = true;
8681
result.ValidateIssuer = true;
8782
result.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
{
@@ -68,6 +71,30 @@ public static byte[] GetEncryptionKey(IEnvironment environment = null)
6871
return key.ToKeyBytes();
6972
}
7073

74+
public static SymmetricSecurityKey[] GetTokenIssuerSigningKeys()
75+
{
76+
List<SymmetricSecurityKey> signingKeys = new List<SymmetricSecurityKey>();
77+
78+
// first we want to use the DataProtection APIs to get the default key,
79+
// which will return any user specified AzureWebEncryptionKey with precedence
80+
// over the platform default key
81+
string defaultKey = Util.GetDefaultKeyValue();
82+
if (defaultKey != null)
83+
{
84+
signingKeys.Add(new SymmetricSecurityKey(defaultKey.ToKeyBytes()));
85+
signingKeys.Add(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(defaultKey)));
86+
}
87+
88+
// next we want to ensure a key is also added for the platform default key
89+
// if it wasn't already added above
90+
if (SecretsUtility.TryGetEncryptionKey(out string key) && !string.Equals(key, defaultKey))
91+
{
92+
signingKeys.Add(new SymmetricSecurityKey(key.ToKeyBytes()));
93+
}
94+
95+
return signingKeys.ToArray();
96+
}
97+
7198
public static byte[] ToKeyBytes(this string hexOrBase64)
7299
{
73100
// only support 32 bytes (256 bits) key length

test/WebJobs.Script.Tests.Integration/WebHostEndToEnd/SWAEndToEndTests.cs

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1-
using Microsoft.Azure.WebJobs.Script.WebHost;
2-
using Microsoft.Azure.WebJobs.Script.WebHost.Management;
3-
using Microsoft.Azure.WebJobs.Script.WebHost.Security;
4-
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
5-
using Microsoft.Extensions.DependencyInjection;
6-
using Microsoft.Extensions.DependencyInjection.Extensions;
7-
using Newtonsoft.Json;
1+
// Copyright (c) .NET Foundation. All rights reserved.
2+
// Licensed under the MIT License. See License.txt in the project root for license information.
3+
84
using System;
95
using System.Collections.Generic;
106
using System.Linq;
117
using System.Net;
128
using System.Net.Http;
139
using System.Net.Http.Headers;
1410
using System.Threading.Tasks;
11+
using Microsoft.Azure.WebJobs.Script.WebHost;
12+
using Microsoft.Azure.WebJobs.Script.WebHost.Management;
13+
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
14+
using Microsoft.Extensions.DependencyInjection;
15+
using Microsoft.Extensions.DependencyInjection.Extensions;
16+
using Newtonsoft.Json;
1517
using Xunit;
1618

1719
namespace Microsoft.Azure.WebJobs.Script.Tests.Integration.WebHostEndToEnd
@@ -68,7 +70,7 @@ public async Task InvokeFunction_FunctionLevel_ValidToken_Succeeds(string header
6870
{
6971
// if an admin token is passed, the function invocation succeeds
7072
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, "api/HttpTrigger-FunctionAuth?code=test");
71-
string token = _fixture.Host.GenerateAdminJwtToken();
73+
string token = GetSWAAdminJwtToken();
7274

7375
if (string.Compare(nameof(HttpRequestHeader.Authorization), headerName) == 0)
7476
{
@@ -83,6 +85,16 @@ public async Task InvokeFunction_FunctionLevel_ValidToken_Succeeds(string header
8385
response.EnsureSuccessStatusCode();
8486
}
8587

88+
private string GetSWAAdminJwtToken()
89+
{
90+
// Ensure we use AzureWebEncryptionKey to generate tokens, as that's what SWA does
91+
string keyValue = _fixture.SWAEncryptionKey;
92+
byte[] keyBytes = keyValue.ToKeyBytes();
93+
string token = _fixture.Host.GenerateAdminJwtToken(key: keyBytes);
94+
95+
return token;
96+
}
97+
8698
[Fact]
8799
public async Task SyncTriggers_Succeeds()
88100
{
@@ -109,19 +121,28 @@ public class TestFixture : EndToEndTestFixture
109121

110122
public TestFixture() : base(@"TestScripts\CSharp", "csharp", RpcWorkerConstants.DotNetLanguageWorkerName, addTestSettings: false)
111123
{
124+
// SWA generates their own key and sets via AzureWebEncryptionKey
125+
// This should take precedence over the default key
112126
var testKeyBytes = TestHelpers.GenerateKeyBytes();
113127
var testKey = TestHelpers.GenerateKeyHexString(testKeyBytes);
128+
SWAEncryptionKey = testKey;
129+
130+
// Default key provisioned by Antares and available via WEBSITE_AUTH_ENCRYPTION_KEY
131+
var defaultTestKeyBytes = TestHelpers.GenerateKeyBytes();
132+
var defaultTestKey = TestHelpers.GenerateKeyHexString(defaultTestKeyBytes);
114133

115134
var settings = new Dictionary<string, string>()
116135
{
117136
{ "AzureWebEncryptionKey", testKey },
118-
{ EnvironmentSettingNames.WebSiteAuthEncryptionKey, testKey },
137+
{ EnvironmentSettingNames.WebSiteAuthEncryptionKey, defaultTestKey },
119138
{ "AzureWebJobsStorage", null },
120139
{ EnvironmentSettingNames.AzureWebsiteName, "testsite" }
121140
};
122141
_scopedEnvironment = new TestScopedEnvironmentVariable(settings);
123142
}
124143

144+
public string SWAEncryptionKey { get; }
145+
125146
public override void ConfigureScriptHost(IWebJobsBuilder webJobsBuilder)
126147
{
127148
base.ConfigureScriptHost(webJobsBuilder);

0 commit comments

Comments
 (0)