Reputation: 3978
I am trying to setup availability testing (URL Ping Test) with Azure Application Insights on an endpoint that requires basic authentication. It seems that the standard approach with
https://username:[email protected]
isn't accepted by Azure (error message says that the URL is malformed and maybe I am missing https/http at the beginning).
Is there any other way to achieve this except of using multi-step web test or Azure Functions, assuming I want to stay in Azure ecosystem? :)
Upvotes: 4
Views: 5688
Reputation: 16138
For reference: Based on the snippet in the answer of @kaushal above, I was able to extend the Basic URL Ping test :) I use the XML in Terraform but you can also submit this via the REST API directly. In my case I needed to add an arbitrary header
<WebTest Name="appinsights-webtest" Id="ABD48585-0831-40CB-9069-682EA6BB3583" Enabled="True" CssProjectStructure="" CssIteration="" Timeout="30" WorkItemIds="" xmlns="http://microsoft.com/schemas/VisualStudio/TeamTest/2010" Description="" CredentialUserName="" CredentialPassword="" PreAuthenticate="True" Proxy="default" StopOnError="False" RecordedResultFile="" ResultsLocale="">
<Items>
<Request Method="GET" Guid="a5f10126-e4cd-570d-961c-cea43999a200" Version="1.1" Url="https://example.com/health/stamp" ThinkTime="0" Timeout="30" ParseDependentRequests="False" FollowRedirects="False" RecordResult="True" Cache="False" ResponseTimeGoal="0" Encoding="utf-8" ExpectedHttpStatusCode="200" ExpectedResponseUrl="" ReportingName="" IgnoreHttpStatusCode="False">
<Headers>
<Header Name="X-Azure-FDID" Value="xxxxxxxxxxxx-xxxxxxxx-xxx" />
</Headers>
</Request>
</Items>
</WebTest>
I didn't find this documented anywhere but works just as expected for me.
Upvotes: 1
Reputation: 5787
Ping test should be relatively simple, there are currently several possibilities to prevent such url from anonymous access, like policies or action filters.
Let's create a simple policy that requires a Secret key in the query string.
First, create the requirement with handler e.g.:
public class HasSecretKeyRequirement : IAuthorizationRequirement
{
}
public class HasSecretKeyRequirementHandler : AuthorizationHandler<HasSecretKeyRequirement>
{
private readonly IHttpContextAccessor _httpContextAccessor;
private readonly IConfiguration _configuration;
public HasSecretKeyRequirementHandler(IHttpContextAccessor httpContextAccessor, IConfiguration configuration)
{
_httpContextAccessor = httpContextAccessor;
_configuration = configuration;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasApiKeyRequirement requirement)
{
var httpContext = _httpContextAccessor.HttpContext;
if (httpContext == null)
{
context.Fail();
return Task.CompletedTask;
}
if (httpContext.Request.Query.TryGetValue("SecretKey", out extractedSecretKey))
{
var secretKey= _configuration.GetValue<string>("SecretKey");
if (secretKey.Equals(extractedSecretKey))
{
context.Succeed(requirement);
return Task.CompletedTask;
}
}
httpContext.Response.ContentType = "text/plain";
httpContext.Response.StatusCode = (int)HttpStatusCode.Unauthorized;
context.Fail();
return Task.CompletedTask;
}
}
Then create a new policy with requirement and register requirement handler:
services.AddAuthorization(options =>
{
options.AddPolicy("HasSecretKey", policy =>
policy.Requirements.Add(new HasSecretKeyRequirement()));
);
services.AddSingleton<IAuthorizationHandler, HasSecretKeyRequirementHandler>();
Apply policy to your ping endpoint:
[Authorize(Policy = "HasSecretKey")]
[HttpGet("api/ping")]
public IActionResult Ping()
{
return Ok();
}
Finallddd configure your availability test:
https://yourapi.com/api/ping?SecretKey=yoursecretkey
This is just an example, you can create your own requirement and handling logic. You can reuse these policies in your application, e.g. in the healthcheck endpoint:
endpoints.MapHealthChecks("/health")
.RequireAuthorization("HasSecretKey");
This form of authorization may be sufficient in such a simple case, but definitely should not be used in more advanced scenarios.
Upvotes: 1
Reputation: 2467
Passing the basic auth credentials in the URL has been deprecated by RFC 3986 (Here is a snippet from the RFC)
3.2.1. User Information
The userinfo subcomponent may consist of a user name and, optionally, scheme-specific information about how to gain authorization to access the resource. The user information, if present, is followed by a commercial at-sign ("@") that delimits it from the host.
userinfo = *( unreserved / pct-encoded / sub-delims / ":" )
Use of the format "user:password" in the userinfo field is deprecated.
The alternate would be to use the Authorization header to pass the credentials. Here is a snippet from Wikipedia (Basic Auth) on how this header is constructed.
The Authorization field is constructed as follows:[6]
- The username and password are combined with a single colon. (:)
- The resulting string is encoded into an octet sequence.[7]
- The resulting string is encoded using a variant of Base64.[8]
- The authorization method and a space is then prepended to the encoded string, separated with a space (e.g. "Basic ").
For example, if the browser uses Aladdin as the username and OpenSesame as the password, then the field's value is the base64-encoding of Aladdin:OpenSesame, or
QWxhZGRpbjpPcGVuU2VzYW1l
. Then the Authorization header will appear as:Authorization: Basic QWxhZGRpbjpPcGVuU2VzYW1l
You can create a Web Test file in Visual Studio Enterprise and then upload it in Application insights and use that. Refer this doc: https://learn.microsoft.com/en-us/azure/application-insights/app-insights-monitor-web-app-availability
<Request> <Headers> <Header Name="Authorization" Value="Basic QWxhZGRpbjpPcGVuU2VzYW1l" /> </Headers> </Request>
Upvotes: 4