Skip to content

Commit 23ae5d2

Browse files
authored
Including admin JWT on outbound platform calls (#9197)
1 parent 5c6c379 commit 23ae5d2

File tree

8 files changed

+54
-29
lines changed

8 files changed

+54
-29
lines changed

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

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

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

714716
if (_environment.IsManagedAppEnvironment())

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
@@ -129,11 +129,10 @@ public static class ScriptConstants
129129
public const string HostingConfigDisableLinuxAppServiceDetailedExecutionEvents = "DisableLinuxExecutionDetails";
130130
public const string HostingConfigDisableLinuxAppServiceExecutionEventLogBackoff = "DisableLinuxLogBackoff";
131131

132-
public const string AdminJwtSiteFunctionsValidAudienceFormat = "https://{0}.azurewebsites.net/azurefunctions";
133-
public const string AdminJwtSiteValidAudienceFormat = "https://{0}.azurewebsites.net";
134-
public const string AdminJwtScmValidIssuerFormat = "https://{0}.scm.azurewebsites.net";
135-
public const string AdminJwtSiteValidIssuerFormat = "https://{0}.azurewebsites.net";
136-
public const string AdminJwtAppServiceIssuer = "https://appservice.core.azurewebsites.net";
132+
public const string SiteAzureFunctionsUriFormat = "https://{0}.azurewebsites.net/azurefunctions";
133+
public const string ScmSiteUriFormat = "https://{0}.scm.azurewebsites.net";
134+
public const string SiteUriFormat = "https://{0}.azurewebsites.net";
135+
public const string AppServiceCoreUri = "https://appservice.core.azurewebsites.net";
137136

138137
public const string AzureFunctionsSystemDirectoryName = ".azurefunctions";
139138
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
@@ -239,6 +239,8 @@ public async Task TrySyncTriggers_PostsExpectedContent(bool cacheEnabled)
239239
// verify expected headers
240240
Assert.Equal(ScriptConstants.FunctionsUserAgent, _mockHttpHandler.LastRequest.Headers.UserAgent.ToString());
241241
Assert.True(_mockHttpHandler.LastRequest.Headers.Contains(ScriptConstants.AntaresLogIdHeaderName));
242+
Assert.NotEmpty(_mockHttpHandler.LastRequest.Headers.GetValues(ScriptConstants.SiteRestrictedTokenHeaderName));
243+
Assert.NotEmpty(_mockHttpHandler.LastRequest.Headers.GetValues(ScriptConstants.SiteTokenHeaderName));
242244

243245
if (cacheEnabled)
244246
{

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

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
using System;
55
using System.Collections.Generic;
66
using System.Diagnostics;
7-
using System.IdentityModel.Tokens.Jwt;
87
using System.IO;
98
using System.Linq;
109
using System.Net.Http;
@@ -15,7 +14,6 @@
1514
using Microsoft.AspNetCore.Builder;
1615
using Microsoft.AspNetCore.Hosting;
1716
using Microsoft.AspNetCore.TestHost;
18-
using Microsoft.Azure.Web.DataProtection;
1917
using Microsoft.Azure.WebJobs.Host.Executors;
2018
using Microsoft.Azure.WebJobs.Script.ExtensionBundle;
2119
using Microsoft.Azure.WebJobs.Script.Models;
@@ -24,6 +22,7 @@
2422
using Microsoft.Azure.WebJobs.Script.WebHost.DependencyInjection;
2523
using Microsoft.Azure.WebJobs.Script.WebHost.Middleware;
2624
using Microsoft.Azure.WebJobs.Script.WebHost.Models;
25+
using Microsoft.Azure.WebJobs.Script.WebHost.Security;
2726
using Microsoft.Azure.WebJobs.Script.Workers.Http;
2827
using Microsoft.Azure.WebJobs.Script.Workers.Rpc;
2928
using Microsoft.Extensions.Configuration;
@@ -34,7 +33,6 @@
3433
using Microsoft.Extensions.Logging;
3534
using Microsoft.Extensions.Logging.Abstractions;
3635
using Microsoft.Extensions.Options;
37-
using Microsoft.IdentityModel.Tokens;
3836
using Microsoft.WebJobs.Script.Tests;
3937
using Newtonsoft.Json.Linq;
4038
using IApplicationLifetime = Microsoft.AspNetCore.Hosting.IApplicationLifetime;
@@ -411,19 +409,10 @@ public async Task<HostStatus> GetHostStatusAsync()
411409

412410
public string GenerateAdminJwtToken(string audience = null, string issuer = null, byte[] key = null)
413411
{
414-
var tokenHandler = new JwtSecurityTokenHandler();
415-
key = key ?? SecretsUtility.GetEncryptionKey();
416-
var tokenDescriptor = new SecurityTokenDescriptor
417-
{
418-
Audience = audience ?? string.Format(ScriptConstants.AdminJwtSiteFunctionsValidAudienceFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName)),
419-
Issuer = issuer ?? string.Format(ScriptConstants.AdminJwtScmValidIssuerFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName)),
420-
Expires = DateTime.UtcNow.AddHours(1),
421-
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
422-
};
423-
var token = tokenHandler.CreateToken(tokenDescriptor);
424-
string tokenHeaderValue = tokenHandler.WriteToken(token);
412+
audience = audience ?? string.Format(ScriptConstants.SiteAzureFunctionsUriFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName));
413+
issuer = issuer ?? string.Format(ScriptConstants.ScmSiteUriFormat, Environment.GetEnvironmentVariable(EnvironmentSettingNames.AzureWebsiteName));
425414

426-
return tokenHeaderValue;
415+
return JwtTokenHelper.CreateToken(DateTime.UtcNow.AddHours(1), audience, issuer, key);
427416
}
428417

429418
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)