Skip to content

Commit a81c13a

Browse files
committed
Removing ping endpoint and expanding host/status endpoint
1 parent 7c2371b commit a81c13a

File tree

6 files changed

+71
-54
lines changed

6 files changed

+71
-54
lines changed

src/WebJobs.Script.WebHost/Controllers/AdminController.cs

Lines changed: 23 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -86,29 +86,35 @@ public FunctionStatus GetFunctionStatus(string name)
8686

8787
[HttpGet]
8888
[Route("admin/host/status")]
89+
[AllowAnonymous]
8990
public HostStatus GetHostStatus()
9091
{
91-
HostStatus status = new HostStatus
92-
{
93-
Id = _scriptHostManager.Instance?.ScriptConfig.HostConfig.HostId
94-
};
92+
var status = new HostStatus();
9593

96-
var lastError = _scriptHostManager.LastError;
97-
if (lastError != null)
94+
// based on the authorization level we determine
95+
// the additional level of detail to return
96+
var authorizationLevel = Request.GetAuthorizationLevel();
97+
if (authorizationLevel == AuthorizationLevel.Admin)
9898
{
99-
status.Errors = new Collection<string>();
100-
status.Errors.Add(Utility.FlattenException(lastError));
101-
}
99+
status.State = _scriptHostManager.State.ToString();
100+
status.Version = ScriptHost.Version;
101+
status.Id = _scriptHostManager.Instance?.ScriptConfig.HostConfig.HostId;
102102

103-
return status;
104-
}
103+
var lastError = _scriptHostManager.LastError;
104+
if (lastError != null)
105+
{
106+
status.Errors = new Collection<string>();
107+
status.Errors.Add(Utility.FlattenException(lastError));
108+
}
105109

106-
[HttpPost]
107-
[Route("admin/host/ping")]
108-
[AllowAnonymous]
109-
public HttpResponseMessage Ping()
110-
{
111-
return new HttpResponseMessage(HttpStatusCode.OK);
110+
return status;
111+
}
112+
else
113+
{
114+
// for Anonymous requests, we don't return any
115+
// detailed info
116+
return status;
117+
}
112118
}
113119

114120
[HttpPost]

src/WebJobs.Script.WebHost/Filters/AuthorizationLevelAttribute.cs

Lines changed: 11 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,28 @@ public async override Task OnAuthorizationAsync(HttpActionContext actionContext,
3232
throw new ArgumentNullException("actionContext");
3333
}
3434

35-
if (SkipAuthorization(actionContext))
36-
{
37-
return;
38-
}
39-
40-
ISecretManager secretManager = actionContext.ControllerContext.Configuration.DependencyResolver.GetService<ISecretManager>();
35+
// determine the authorization level for the function and set it
36+
// as a request property
37+
var secretManager = actionContext.ControllerContext.Configuration.DependencyResolver.GetService<ISecretManager>();
4138
var settings = actionContext.ControllerContext.Configuration.DependencyResolver.GetService<WebHostSettings>();
39+
var requestAuthorizationLevel = await GetAuthorizationLevelAsync(actionContext.Request, secretManager);
40+
actionContext.Request.Properties[ScriptConstants.AzureFunctionsHttpRequestAuthorizationLevel] = requestAuthorizationLevel;
4241

43-
if (!settings.IsAuthDisabled && !await IsAuthorizedAsync(actionContext.Request, Level, secretManager))
42+
if (settings.IsAuthDisabled ||
43+
SkipAuthorization(actionContext) ||
44+
Level == AuthorizationLevel.Anonymous)
4445
{
45-
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
46+
return;
4647
}
47-
}
4848

49-
public static async Task<bool> IsAuthorizedAsync(HttpRequestMessage request, AuthorizationLevel level, ISecretManager secretManager, string functionName = null)
50-
{
51-
if (level == AuthorizationLevel.Anonymous)
49+
if (requestAuthorizationLevel < Level)
5250
{
53-
return true;
51+
actionContext.Response = new HttpResponseMessage(HttpStatusCode.Unauthorized);
5452
}
55-
56-
AuthorizationLevel requestLevel = await GetAuthorizationLevelAsync(request, secretManager, functionName);
57-
return requestLevel >= level;
5853
}
5954

6055
internal static async Task<AuthorizationLevel> GetAuthorizationLevelAsync(HttpRequestMessage request, ISecretManager secretManager, string functionName = null)
6156
{
62-
// TODO: Add support for validating "EasyAuth" headers
63-
6457
// first see if a key value is specified via headers or query string (header takes precedence)
6558
IEnumerable<string> values;
6659
string keyValue = null;

src/WebJobs.Script.WebHost/Models/HostStatus.cs

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,18 @@ namespace Microsoft.Azure.WebJobs.Script.WebHost.Models
99
{
1010
public class HostStatus
1111
{
12-
public HostStatus()
13-
{
14-
Version = ScriptHost.Version;
15-
}
16-
1712
/// <summary>
1813
/// Gets or sets the host id.
1914
/// </summary>
2015
[JsonProperty(PropertyName = "id", DefaultValueHandling = DefaultValueHandling.Ignore)]
2116
public string Id { get; set; }
2217

18+
/// <summary>
19+
/// Gets or sets the current status of the host.
20+
/// </summary>
21+
[JsonProperty(PropertyName = "state", DefaultValueHandling = DefaultValueHandling.Ignore)]
22+
public string State { get; set; }
23+
2324
/// <summary>
2425
/// Gets or sets the host version.
2526
/// </summary>

src/WebJobs.Script/Extensions/HttpRequestMessageExtensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,21 @@ namespace Microsoft.Azure.WebJobs.Script
1010
{
1111
public static class HttpRequestMessageExtensions
1212
{
13+
public static AuthorizationLevel GetAuthorizationLevel(this HttpRequestMessage request)
14+
{
15+
return request.GetRequestPropertyOrDefault<AuthorizationLevel>(ScriptConstants.AzureFunctionsHttpRequestAuthorizationLevel);
16+
}
17+
18+
public static TValue GetRequestPropertyOrDefault<TValue>(this HttpRequestMessage request, string key)
19+
{
20+
object value = null;
21+
if (request.Properties.TryGetValue(key, out value))
22+
{
23+
return (TValue)value;
24+
}
25+
return default(TValue);
26+
}
27+
1328
public static IDictionary<string, string> GetQueryParameterDictionary(this HttpRequestMessage request)
1429
{
1530
var keyValuePairs = request.GetQueryNameValuePairs();

src/WebJobs.Script/ScriptConstants.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ public static class ScriptConstants
1111
public const string AzureFunctionsWebHookDataKey = "MS_AzureFunctionsWebHookData";
1212
public const string AzureFunctionsHttpResponseKey = "MS_AzureFunctionsHttpResponse";
1313
public const string AzureFunctionsHttpRouteDataKey = "MS_AzureFunctionsHttpRouteData";
14+
public const string AzureFunctionsHttpRequestAuthorizationLevel = "MS_AzureFunctionsAuthorizationLevel";
1415

1516
public const string TracePropertyPrimaryHostKey = "MS_PrimaryHost";
1617
public const string TracePropertyFunctionNameKey = "MS_FunctionName";

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

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -907,16 +907,7 @@ public async Task ServiceBusTopicTrigger_ManualInvoke_Succeeds()
907907
}
908908

909909
[Fact]
910-
public async Task HostPing_Succeeds()
911-
{
912-
string uri = "admin/host/ping";
913-
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Post, uri);
914-
HttpResponseMessage response = await this._fixture.HttpClient.SendAsync(request);
915-
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
916-
}
917-
918-
[Fact]
919-
public async Task HostStatus_Succeeds()
910+
public async Task HostStatus_AdminLevel_Succeeds()
920911
{
921912
string uri = "admin/host/status";
922913
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, uri);
@@ -948,28 +939,38 @@ public async Task HostStatus_Succeeds()
948939
Assert.Equal(expectedVersion, node.Value);
949940
node = doc.Descendants(XName.Get("Id", ns)).Single();
950941
Assert.Equal(expectedId, node.Value);
942+
node = doc.Descendants(XName.Get("State", ns)).Single();
943+
Assert.True(node.Value == "Running" || node.Value == "Created");
951944

952945
node = doc.Descendants(XName.Get("Errors", ns)).Single();
953946
Assert.True(node.IsEmpty);
954947
}
955948

956949
[Fact]
957-
public async Task HostStatus_FunctionLevelRequest_Fails()
950+
public async Task HostStatus_FunctionLevelRequest_Succeeds()
958951
{
959952
string uri = "admin/host/status";
960953
var request = new HttpRequestMessage(HttpMethod.Get, uri);
961954
request.Headers.Add("x-functions-key", "zlnu496ve212kk1p84ncrtdvmtpembduqp25ajjc");
962955
var response = await this._fixture.HttpClient.SendAsync(request);
963-
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
956+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
957+
958+
string json = await response.Content.ReadAsStringAsync();
959+
JObject obj = JObject.Parse(json);
960+
Assert.Equal(0, obj.Properties().Count());
964961
}
965962

966963
[Fact]
967-
public async Task HostStatus_AnonymousLevelRequest_Fails()
964+
public async Task HostStatus_AnonymousLevelRequest_Succeeds()
968965
{
969966
string uri = "admin/host/status";
970967
var request = new HttpRequestMessage(HttpMethod.Get, uri);
971968
var response = await this._fixture.HttpClient.SendAsync(request);
972-
Assert.Equal(HttpStatusCode.Unauthorized, response.StatusCode);
969+
Assert.Equal(HttpStatusCode.OK, response.StatusCode);
970+
971+
string json = await response.Content.ReadAsStringAsync();
972+
JObject obj = JObject.Parse(json);
973+
Assert.Equal(0, obj.Properties().Count());
973974
}
974975

975976
private async Task<HttpResponseMessage> GetHostStatusAsync()

0 commit comments

Comments
 (0)