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
@@ -123,7 +129,10 @@ public TestFunctionHost(string scriptPath, string logPath,
123129 } )
124130 . ConfigureScriptHostAppConfiguration ( scriptHostConfigurationBuilder =>
125131 {
126- scriptHostConfigurationBuilder . AddTestSettings ( ) ;
132+ if ( addTestSettings )
133+ {
134+ scriptHostConfigurationBuilder . AddTestSettings ( ) ;
135+ }
127136 configureScriptHostAppConfiguration ? . Invoke ( scriptHostConfigurationBuilder ) ;
128137 } )
129138 . ConfigureScriptHostLogging ( scriptHostLoggingBuilder =>
@@ -146,7 +155,11 @@ public TestFunctionHost(string scriptPath, string logPath,
146155 }
147156
148157 config . Add ( new ScriptEnvironmentVariablesConfigurationSource ( ) ) ;
149- config . AddTestSettings ( ) ;
158+ if ( addTestSettings )
159+ {
160+ config . AddTestSettings ( ) ;
161+ }
162+ configureWebHostAppConfiguration ? . Invoke ( config ) ;
150163 } )
151164 . UseStartup < TestStartup > ( ) ;
152165
@@ -182,7 +195,9 @@ public TestFunctionHost(string scriptPath, string logPath,
182195
183196 public ScriptJobHostOptions ScriptOptions => JobHostServices . GetService < IOptions < ScriptJobHostOptions > > ( ) . Value ;
184197
185- public ISecretManager SecretManager => _testServer . Host . Services . GetService < ISecretManagerProvider > ( ) . Current ;
198+ public ISecretManagerProvider SecretManagerProvider => _testServer . Host . Services . GetService < ISecretManagerProvider > ( ) ;
199+
200+ public ISecretManager SecretManager => SecretManagerProvider . Current ;
186201
187202 public string LogPath => _hostOptions . LogPath ;
188203
@@ -192,6 +207,11 @@ public TestFunctionHost(string scriptPath, string logPath,
192207
193208 public async Task < string > GetMasterKeyAsync ( )
194209 {
210+ if ( ! SecretManagerProvider . SecretsEnabled )
211+ {
212+ return null ;
213+ }
214+
195215 HostSecretsInfo secrets = await SecretManager . GetHostSecretsAsync ( ) ;
196216 return secrets . MasterKey ;
197217 }
@@ -345,13 +365,44 @@ public async Task<FunctionStatus> GetFunctionStatusAsync(string functionName)
345365
346366 public async Task < HostStatus > GetHostStatusAsync ( )
347367 {
348- HostSecretsInfo secrets = await SecretManager . GetHostSecretsAsync ( ) ;
349- string uri = $ "admin/host/status?code={ secrets . MasterKey } ";
350- HttpResponseMessage response = await HttpClient . GetAsync ( uri ) ;
368+ HttpRequestMessage request = new HttpRequestMessage ( HttpMethod . Get , "admin/host/status" ) ;
369+
370+ if ( SecretManagerProvider . SecretsEnabled )
371+ {
372+ // use admin key
373+ HostSecretsInfo secrets = await SecretManager . GetHostSecretsAsync ( ) ;
374+ request . Headers . Add ( AuthenticationLevelHandler . FunctionsKeyHeaderName , secrets . MasterKey ) ;
375+ }
376+ else
377+ {
378+ // use admin jwt token
379+ string token = GenerateAdminJwtToken ( ) ;
380+ request . Headers . Authorization = new System . Net . Http . Headers . AuthenticationHeaderValue ( "Bearer" , token ) ;
381+ }
382+
383+ HttpResponseMessage response = await HttpClient . SendAsync ( request ) ;
351384 response . EnsureSuccessStatusCode ( ) ;
352385 return await response . Content . ReadAsAsync < HostStatus > ( ) ;
353386 }
354387
388+ public string GenerateAdminJwtToken ( )
389+ {
390+ var tokenHandler = new JwtSecurityTokenHandler ( ) ;
391+ string defaultKey = Util . GetDefaultKeyValue ( ) ;
392+ var key = Encoding . ASCII . GetBytes ( defaultKey ) ;
393+ var tokenDescriptor = new SecurityTokenDescriptor
394+ {
395+ Audience = string . Format ( ScriptConstants . AdminJwtValidAudienceFormat , Environment . GetEnvironmentVariable ( EnvironmentSettingNames . AzureWebsiteName ) ) ,
396+ Issuer = string . Format ( ScriptConstants . AdminJwtValidIssuerFormat , Environment . GetEnvironmentVariable ( EnvironmentSettingNames . AzureWebsiteName ) ) ,
397+ Expires = DateTime . UtcNow . AddHours ( 1 ) ,
398+ SigningCredentials = new SigningCredentials ( new SymmetricSecurityKey ( key ) , SecurityAlgorithms . HmacSha256Signature )
399+ } ;
400+ var token = tokenHandler . CreateToken ( tokenDescriptor ) ;
401+ string tokenHeaderValue = tokenHandler . WriteToken ( token ) ;
402+
403+ return tokenHeaderValue ;
404+ }
405+
355406 public void Dispose ( )
356407 {
357408 if ( ! _isDisposed )
0 commit comments