44using System ;
55using System . Collections . Generic ;
66using System . Diagnostics ;
7+ using System . IdentityModel . Tokens . Jwt ;
78using System . IO ;
89using System . Linq ;
910using System . Net . Http ;
1415using Microsoft . AspNetCore . Builder ;
1516using Microsoft . AspNetCore . Hosting ;
1617using Microsoft . AspNetCore . TestHost ;
18+ using Microsoft . Azure . Web . DataProtection ;
1719using Microsoft . Azure . WebJobs . Host . Executors ;
1820using Microsoft . Azure . WebJobs . Script . ExtensionBundle ;
19- using Microsoft . Azure . WebJobs . Script . Grpc ;
2021using Microsoft . Azure . WebJobs . Script . Models ;
2122using Microsoft . Azure . WebJobs . Script . WebHost ;
23+ using Microsoft . Azure . WebJobs . Script . WebHost . Authentication ;
2224using Microsoft . Azure . WebJobs . Script . WebHost . DependencyInjection ;
2325using Microsoft . Azure . WebJobs . Script . WebHost . Middleware ;
2426using Microsoft . Azure . WebJobs . Script . WebHost . Models ;
3234using Microsoft . Extensions . Logging ;
3335using Microsoft . Extensions . Logging . Abstractions ;
3436using Microsoft . Extensions . Options ;
37+ using Microsoft . IdentityModel . Tokens ;
3538using Microsoft . WebJobs . Script . Tests ;
3639using Newtonsoft . Json . Linq ;
3740using IApplicationLifetime = Microsoft . AspNetCore . Hosting . IApplicationLifetime ;
@@ -59,9 +62,10 @@ public TestFunctionHost(string scriptPath,
5962 Action < IWebJobsBuilder > configureScriptHostWebJobsBuilder = null ,
6063 Action < IConfigurationBuilder > configureScriptHostAppConfiguration = null ,
6164 Action < ILoggingBuilder > configureScriptHostLogging = null ,
62- Action < IServiceCollection > configureScriptHostServices = null )
65+ Action < IServiceCollection > configureScriptHostServices = null ,
66+ Action < IConfigurationBuilder > configureWebHostAppConfiguration = null )
6367 : this ( scriptPath , Path . Combine ( Path . GetTempPath ( ) , @"Functions" ) , configureWebHostServices , configureScriptHostWebJobsBuilder ,
64- configureScriptHostAppConfiguration , configureScriptHostLogging , configureScriptHostServices )
68+ configureScriptHostAppConfiguration , configureScriptHostLogging , configureScriptHostServices , configureWebHostAppConfiguration )
6569 {
6670 }
6771
@@ -70,7 +74,9 @@ public TestFunctionHost(string scriptPath, string logPath,
7074 Action < IWebJobsBuilder > configureScriptHostWebJobsBuilder = null ,
7175 Action < IConfigurationBuilder > configureScriptHostAppConfiguration = null ,
7276 Action < ILoggingBuilder > configureScriptHostLogging = null ,
73- Action < IServiceCollection > configureScriptHostServices = null )
77+ Action < IServiceCollection > configureScriptHostServices = null ,
78+ Action < IConfigurationBuilder > configureWebHostAppConfiguration = null ,
79+ bool addTestSettings = true )
7480 {
7581 _appRoot = scriptPath ;
7682
@@ -126,7 +132,10 @@ public TestFunctionHost(string scriptPath, string logPath,
126132 } )
127133 . ConfigureScriptHostAppConfiguration ( scriptHostConfigurationBuilder =>
128134 {
129- scriptHostConfigurationBuilder . AddTestSettings ( ) ;
135+ if ( addTestSettings )
136+ {
137+ scriptHostConfigurationBuilder . AddTestSettings ( ) ;
138+ }
130139 configureScriptHostAppConfiguration ? . Invoke ( scriptHostConfigurationBuilder ) ;
131140 } )
132141 . ConfigureScriptHostLogging ( scriptHostLoggingBuilder =>
@@ -149,7 +158,11 @@ public TestFunctionHost(string scriptPath, string logPath,
149158 }
150159
151160 config . Add ( new ScriptEnvironmentVariablesConfigurationSource ( ) ) ;
152- config . AddTestSettings ( ) ;
161+ if ( addTestSettings )
162+ {
163+ config . AddTestSettings ( ) ;
164+ }
165+ configureWebHostAppConfiguration ? . Invoke ( config ) ;
153166 } )
154167 . UseStartup < TestStartup > ( ) ;
155168
@@ -185,7 +198,9 @@ public TestFunctionHost(string scriptPath, string logPath,
185198
186199 public ScriptJobHostOptions ScriptOptions => JobHostServices . GetService < IOptions < ScriptJobHostOptions > > ( ) . Value ;
187200
188- public ISecretManager SecretManager => _testServer . Host . Services . GetService < ISecretManagerProvider > ( ) . Current ;
201+ public ISecretManagerProvider SecretManagerProvider => _testServer . Host . Services . GetService < ISecretManagerProvider > ( ) ;
202+
203+ public ISecretManager SecretManager => SecretManagerProvider . Current ;
189204
190205 public string LogPath => _hostOptions . LogPath ;
191206
@@ -195,6 +210,11 @@ public TestFunctionHost(string scriptPath, string logPath,
195210
196211 public async Task < string > GetMasterKeyAsync ( )
197212 {
213+ if ( ! SecretManagerProvider . SecretsEnabled )
214+ {
215+ return null ;
216+ }
217+
198218 HostSecretsInfo secrets = await SecretManager . GetHostSecretsAsync ( ) ;
199219 return secrets . MasterKey ;
200220 }
@@ -348,13 +368,44 @@ public async Task<FunctionStatus> GetFunctionStatusAsync(string functionName)
348368
349369 public async Task < HostStatus > GetHostStatusAsync ( )
350370 {
351- HostSecretsInfo secrets = await SecretManager . GetHostSecretsAsync ( ) ;
352- string uri = $ "admin/host/status?code={ secrets . MasterKey } ";
353- HttpResponseMessage response = await HttpClient . GetAsync ( uri ) ;
371+ HttpRequestMessage request = new HttpRequestMessage ( HttpMethod . Get , "admin/host/status" ) ;
372+
373+ if ( SecretManagerProvider . SecretsEnabled )
374+ {
375+ // use admin key
376+ HostSecretsInfo secrets = await SecretManager . GetHostSecretsAsync ( ) ;
377+ request . Headers . Add ( AuthenticationLevelHandler . FunctionsKeyHeaderName , secrets . MasterKey ) ;
378+ }
379+ else
380+ {
381+ // use admin jwt token
382+ string token = GenerateAdminJwtToken ( ) ;
383+ request . Headers . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , token ) ;
384+ }
385+
386+ HttpResponseMessage response = await HttpClient . SendAsync ( request ) ;
354387 response . EnsureSuccessStatusCode ( ) ;
355388 return await response . Content . ReadAsAsync < HostStatus > ( ) ;
356389 }
357390
391+ public string GenerateAdminJwtToken ( )
392+ {
393+ var tokenHandler = new JwtSecurityTokenHandler ( ) ;
394+ string defaultKey = Util . GetDefaultKeyValue ( ) ;
395+ var key = Encoding . ASCII . GetBytes ( defaultKey ) ;
396+ var tokenDescriptor = new SecurityTokenDescriptor
397+ {
398+ Audience = string . Format ( ScriptConstants . AdminJwtValidAudienceFormat , Environment . GetEnvironmentVariable ( EnvironmentSettingNames . AzureWebsiteName ) ) ,
399+ Issuer = string . Format ( ScriptConstants . AdminJwtValidIssuerFormat , Environment . GetEnvironmentVariable ( EnvironmentSettingNames . AzureWebsiteName ) ) ,
400+ Expires = DateTime . UtcNow . AddHours ( 1 ) ,
401+ SigningCredentials = new SigningCredentials ( new SymmetricSecurityKey ( key ) , SecurityAlgorithms . HmacSha256Signature )
402+ } ;
403+ var token = tokenHandler . CreateToken ( tokenDescriptor ) ;
404+ string tokenHeaderValue = tokenHandler . WriteToken ( token ) ;
405+
406+ return tokenHeaderValue ;
407+ }
408+
358409 public void Dispose ( )
359410 {
360411 if ( ! _isDisposed )
0 commit comments