Skip to content

Commit 2e42e3b

Browse files
VpOfEngineeringazfuncghmathewc
authored
4.21.3 hotfix (#9305)
* Bumping minor version * Fixing key defaulting regression (#9304) --------- Co-authored-by: azfuncgh <[email protected]> Co-authored-by: Mathew Charles <[email protected]>
1 parent 694d143 commit 2e42e3b

File tree

4 files changed

+62
-17
lines changed

4 files changed

+62
-17
lines changed

build/common.props

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<LangVersion>latest</LangVersion>
66
<MajorVersion>4</MajorVersion>
77
<MinorVersion>21</MinorVersion>
8-
<PatchVersion>2</PatchVersion>
8+
<PatchVersion>3</PatchVersion>
99
<BuildNumber Condition="'$(BuildNumber)' == '' ">0</BuildNumber>
1010
<PreviewVersion></PreviewVersion>
1111

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

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
// Copyright (c) .NET Foundation. All rights reserved.
22
// Licensed under the MIT License. See License.txt in the project root for license information.
33

4+
using System.Collections.Generic;
45
using System.Linq;
56
using System.Security.Claims;
6-
using System.Text;
77
using System.Threading;
88
using System.Threading.Tasks;
99
using Microsoft.AspNetCore.Authentication;
@@ -73,15 +73,11 @@ public static AuthenticationBuilder AddScriptJwtBearer(this AuthenticationBuilde
7373

7474
private static TokenValidationParameters CreateTokenValidationParameters()
7575
{
76+
var signingKeys = SecretsUtility.GetTokenIssuerSigningKeys();
7677
var result = new TokenValidationParameters();
77-
if (SecretsUtility.TryGetEncryptionKey(out string key))
78+
if (signingKeys.Length > 0)
7879
{
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-
};
80+
result.IssuerSigningKeys = signingKeys;
8581
result.ValidateAudience = true;
8682
result.ValidateIssuer = true;
8783
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
{
@@ -82,6 +85,30 @@ public static byte[] ToKeyBytes(this string hexOrBase64)
8285
return Convert.FromBase64String(hexOrBase64);
8386
}
8487

88+
public static SymmetricSecurityKey[] GetTokenIssuerSigningKeys()
89+
{
90+
List<SymmetricSecurityKey> signingKeys = new List<SymmetricSecurityKey>();
91+
92+
// first we want to use the DataProtection APIs to get the default key,
93+
// which will return any user specified AzureWebEncryptionKey with precedence
94+
// over the platform default key
95+
string defaultKey = Util.GetDefaultKeyValue();
96+
if (defaultKey != null)
97+
{
98+
signingKeys.Add(new SymmetricSecurityKey(defaultKey.ToKeyBytes()));
99+
signingKeys.Add(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(defaultKey)));
100+
}
101+
102+
// next we want to ensure a key is also added for the platform default key
103+
// if it wasn't already added above
104+
if (SecretsUtility.TryGetEncryptionKey(out string key) && !string.Equals(key, defaultKey))
105+
{
106+
signingKeys.Add(new SymmetricSecurityKey(key.ToKeyBytes()));
107+
}
108+
109+
return signingKeys.ToArray();
110+
}
111+
85112
private static bool TryGetEncryptionKey(IEnvironment environment, string keyName, out string encryptionKey)
86113
{
87114
encryptionKey = environment.GetEnvironmentVariable(keyName);

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

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
using Microsoft.Azure.WebJobs.Script.WebHost;
2-
using Microsoft.Azure.WebJobs.Script.WebHost.Management;
3-
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
4-
using Microsoft.Extensions.DependencyInjection;
5-
using Microsoft.Extensions.DependencyInjection.Extensions;
6-
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+
74
using System;
85
using System.Collections.Generic;
96
using System.Linq;
107
using System.Net;
118
using System.Net.Http;
129
using System.Net.Http.Headers;
1310
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;
1417
using Xunit;
1518

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

7275
if (string.Compare(nameof(HttpRequestHeader.Authorization), headerName) == 0)
7376
{
@@ -82,6 +85,16 @@ public async Task InvokeFunction_FunctionLevel_ValidToken_Succeeds(string header
8285
response.EnsureSuccessStatusCode();
8386
}
8487

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+
8598
[Fact]
8699
public async Task SyncTriggers_Succeeds()
87100
{
@@ -108,19 +121,28 @@ public class TestFixture : EndToEndTestFixture
108121

109122
public TestFixture() : base(@"TestScripts\CSharp", "csharp", RpcWorkerConstants.DotNetLanguageWorkerName, addTestSettings: false)
110123
{
124+
// SWA generates their own key and sets via AzureWebEncryptionKey
125+
// This should take precedence over the default key
111126
var testKeyBytes = TestHelpers.GenerateKeyBytes();
112127
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);
113133

114134
var settings = new Dictionary<string, string>()
115135
{
116136
{ "AzureWebEncryptionKey", testKey },
117-
{ EnvironmentSettingNames.WebSiteAuthEncryptionKey, testKey },
137+
{ EnvironmentSettingNames.WebSiteAuthEncryptionKey, defaultTestKey },
118138
{ "AzureWebJobsStorage", null },
119139
{ EnvironmentSettingNames.AzureWebsiteName, "testsite" }
120140
};
121141
_scopedEnvironment = new TestScopedEnvironmentVariable(settings);
122142
}
123143

144+
public string SWAEncryptionKey { get; }
145+
124146
public override void ConfigureScriptHost(IWebJobsBuilder webJobsBuilder)
125147
{
126148
base.ConfigureScriptHost(webJobsBuilder);

0 commit comments

Comments
 (0)