Skip to content

Commit 55ac56a

Browse files
authored
Including admin JWT on outbound platform calls (#9198)
1 parent a084951 commit 55ac56a

File tree

8 files changed

+54
-26
lines changed

8 files changed

+54
-26
lines changed

src/WebJobs.Script.WebHost/Management/FunctionsSyncManager.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -688,7 +688,8 @@ internal HttpRequestMessage BuildSetTriggersRequest()
688688
// of triggers. It'll verify app ownership using a SWT token valid for 5 minutes. It should be plenty.
689689
private async Task<(bool, string)> SetTriggersAsync(string content)
690690
{
691-
var token = SimpleWebTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(5));
691+
string swtToken = SimpleWebTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(5));
692+
string jwtToken = JwtTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(5));
692693

693694
string sanitizedContentString = content;
694695
if (ArmCacheEnabled)
@@ -707,7 +708,8 @@ internal HttpRequestMessage BuildSetTriggersRequest()
707708
var requestId = Guid.NewGuid().ToString();
708709
request.Headers.Add(ScriptConstants.AntaresLogIdHeaderName, requestId);
709710
request.Headers.Add("User-Agent", ScriptConstants.FunctionsUserAgent);
710-
request.Headers.Add(ScriptConstants.SiteRestrictedTokenHeaderName, token);
711+
request.Headers.Add(ScriptConstants.SiteRestrictedTokenHeaderName, swtToken);
712+
request.Headers.Add(ScriptConstants.SiteTokenHeaderName, jwtToken);
711713
request.Content = new StringContent(content, Encoding.UTF8, "application/json");
712714

713715
if (_environment.IsKubernetesManagedHosting())

src/WebJobs.Script.WebHost/Metrics/LinuxContainerMetricsPublisher.cs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -284,12 +284,14 @@ private HttpRequestMessage BuildRequest<TContent>(HttpMethod method, string path
284284
Content = new ObjectContent<TContent>(content, new JsonMediaTypeFormatter())
285285
};
286286

287-
var token = SimpleWebTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(5));
287+
string swtToken = SimpleWebTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(5));
288+
string jwtToken = JwtTokenHelper.CreateToken(DateTime.UtcNow.AddMinutes(5));
288289

289290
// add the required authentication headers
290291
request.Headers.Add(ContainerNameHeader, _containerName);
291292
request.Headers.Add(HostNameHeader, _hostNameProvider.Value);
292-
request.Headers.Add(ScriptConstants.SiteRestrictedTokenHeaderName, token);
293+
request.Headers.Add(ScriptConstants.SiteRestrictedTokenHeaderName, swtToken);
294+
request.Headers.Add(ScriptConstants.SiteTokenHeaderName, jwtToken);
293295
request.Headers.Add(StampNameHeader, _stampName);
294296

295297
return request;

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

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -86,14 +86,14 @@ private static TokenValidationParameters CreateTokenValidationParameters()
8686
result.ValidateIssuer = true;
8787
result.ValidAudiences = new string[]
8888
{
89-
string.Format(AdminJwtSiteFunctionsValidAudienceFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName)),
90-
string.Format(AdminJwtSiteValidAudienceFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName))
89+
string.Format(SiteAzureFunctionsUriFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName)),
90+
string.Format(SiteUriFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName))
9191
};
9292
result.ValidIssuers = new string[]
9393
{
94-
AdminJwtAppServiceIssuer,
95-
string.Format(AdminJwtScmValidIssuerFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName)),
96-
string.Format(AdminJwtSiteValidIssuerFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName))
94+
AppServiceCoreUri,
95+
string.Format(ScmSiteUriFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName)),
96+
string.Format(SiteUriFormat, ScriptSettingsManager.Instance.GetSetting(AzureWebsiteName))
9797
};
9898
}
9999

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
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+
4+
using System;
5+
using System.IdentityModel.Tokens.Jwt;
6+
using Microsoft.Azure.WebJobs.Script.Config;
7+
using Microsoft.IdentityModel.Tokens;
8+
9+
namespace Microsoft.Azure.WebJobs.Script.WebHost.Security
10+
{
11+
internal static class JwtTokenHelper
12+
{
13+
public static string CreateToken(DateTime validUntil, string audience = null, string issuer = null, byte[] key = null)
14+
{
15+
var tokenHandler = new JwtSecurityTokenHandler();
16+
key = key ?? SecretsUtility.GetEncryptionKey();
17+
var tokenDescriptor = new SecurityTokenDescriptor
18+
{
19+
Audience = audience ?? ScriptConstants.AppServiceCoreUri,
20+
Issuer = issuer ?? string.Format(ScriptConstants.SiteUriFormat, ScriptSettingsManager.Instance.GetSetting(EnvironmentSettingNames.AzureWebsiteName)),
21+
Expires = validUntil,
22+
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
23+
};
24+
var token = tokenHandler.CreateToken(tokenDescriptor);
25+
string tokenValue = tokenHandler.WriteToken(token);
26+
27+
return tokenValue;
28+
}
29+
}
30+
}

src/WebJobs.Script/ScriptConstants.cs

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -124,11 +124,10 @@ public static class ScriptConstants
124124
public const string FeatureFlagEnableMultiLanguageWorker = "EnableMultiLanguageWorker";
125125
public const string FeatureFlagEnableLinuxEPExecutionCount = "EnableLinuxFEC";
126126

127-
public const string AdminJwtSiteFunctionsValidAudienceFormat = "https://{0}.azurewebsites.net/azurefunctions";
128-
public const string AdminJwtSiteValidAudienceFormat = "https://{0}.azurewebsites.net";
129-
public const string AdminJwtScmValidIssuerFormat = "https://{0}.scm.azurewebsites.net";
130-
public const string AdminJwtSiteValidIssuerFormat = "https://{0}.azurewebsites.net";
131-
public const string AdminJwtAppServiceIssuer = "https://appservice.core.azurewebsites.net";
127+
public const string SiteAzureFunctionsUriFormat = "https://{0}.azurewebsites.net/azurefunctions";
128+
public const string ScmSiteUriFormat = "https://{0}.scm.azurewebsites.net";
129+
public const string SiteUriFormat = "https://{0}.azurewebsites.net";
130+
public const string AppServiceCoreUri = "https://appservice.core.azurewebsites.net";
132131

133132
public const string AzureFunctionsSystemDirectoryName = ".azurefunctions";
134133
public const string HttpMethodConstraintName = "httpMethod";

test/WebJobs.Script.Tests.Integration/Management/FunctionsSyncManagerTests.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,8 @@ public async Task TrySyncTriggers_PostsExpectedContent(bool cacheEnabled)
234234
// verify expected headers
235235
Assert.Equal(ScriptConstants.FunctionsUserAgent, _mockHttpHandler.LastRequest.Headers.UserAgent.ToString());
236236
Assert.True(_mockHttpHandler.LastRequest.Headers.Contains(ScriptConstants.AntaresLogIdHeaderName));
237+
Assert.NotEmpty(_mockHttpHandler.LastRequest.Headers.GetValues(ScriptConstants.SiteRestrictedTokenHeaderName));
238+
Assert.NotEmpty(_mockHttpHandler.LastRequest.Headers.GetValues(ScriptConstants.SiteTokenHeaderName));
237239

238240
if (cacheEnabled)
239241
{

test/WebJobs.Script.Tests.Integration/TestFunctionHost.cs

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
using Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection;
2424
using Microsoft.Azure.WebJobs.Script.WebHost.Middleware;
2525
using Microsoft.Azure.WebJobs.Script.WebHost.Models;
26+
using Microsoft.Azure.WebJobs.Script.WebHost.Security;
2627
using Microsoft.Azure.WebJobs.Script.Workers.Http;
2728
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
2829
using Microsoft.Extensions.Configuration;
@@ -405,19 +406,10 @@ public async Task<HostStatus> GetHostStatusAsync()
405406

406407
public string GenerateAdminJwtToken(string audience = null, string issuer = null, byte[] key = null)
407408
{
408-
var tokenHandler = new JwtSecurityTokenHandler();
409-
key = key ?? SecretsUtility.GetEncryptionKey();
410-
var tokenDescriptor = new SecurityTokenDescriptor
411-
{
412-
Audience = audience ?? string.Format(ScriptConstants.AdminJwtSiteFunctionsValidAudienceFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName)),
413-
Issuer = issuer ?? string.Format(ScriptConstants.AdminJwtScmValidIssuerFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName)),
414-
Expires = DateTime.UtcNow.AddHours(1),
415-
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
416-
};
417-
var token = tokenHandler.CreateToken(tokenDescriptor);
418-
string tokenHeaderValue = tokenHandler.WriteToken(token);
409+
audience = audience ?? string.Format(ScriptConstants.SiteAzureFunctionsUriFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName));
410+
issuer = issuer ?? string.Format(ScriptConstants.ScmSiteUriFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName));
419411

420-
return tokenHeaderValue;
412+
return JwtTokenHelper.CreateToken(DateTime.UtcNow.AddHours(1), audience, issuer, key);
421413
}
422414

423415
public void Dispose()

test/WebJobs.Script.Tests/Metrics/LinuxContainerMetricsPublisherTests.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@ private void ValidateRequest(HttpRequestMessage request)
9393
Assert.Equal(request.Headers.GetValues(LinuxContainerMetricsPublisher.HostNameHeader).Single(), _testHostName);
9494
Assert.Equal(request.Headers.GetValues(LinuxContainerMetricsPublisher.StampNameHeader).Single(), _testStampName);
9595
Assert.NotEmpty(request.Headers.GetValues(ScriptConstants.SiteRestrictedTokenHeaderName));
96+
Assert.NotEmpty(request.Headers.GetValues(ScriptConstants.SiteTokenHeaderName));
9697

9798
Assert.Equal(request.RequestUri.Host, _testIpAddress);
9899

0 commit comments

Comments
 (0)