Reputation: 5624
Related questions
Problem
I have a service running under a specific path on a domain, e.g. https://www.example.com/myservice. The myservice path is dedicated to my service and other services have other paths at the same domain. It is setup like this in startup configure:
app.Map("/myservice", builder =>
{
builder.UseStaticFiles();
builder.UseMvcWithDefaultRoute();
});
I am using a library that implements a custom RemoteAuthenticationHandler
. By default, the callback path routes to /x-callback
which results in the browser trying to access https://www.example.com/x-callback.
Since my service does not process url's without the /myservice
prefix I get a 404. Changing the URL in the browser to /myservice/x-callback
manually loads the callback and all is fine.
I can set the callback path for the handler in startup options as expected in startup configure services.
services.AddSomething(options =>
{
options.AddThingX((o) =>
{
o.CallbackPath = new PathString($"/myservice{o.CallbackPath}");
});
});
When I set the callback path like that the browser tries to load /myservice/x-callback
. But, this URL now returns a 404. It seems the handler for the callback also has its URL changed. Changing the URL in the browser to /myservice/myservice/x-callback
loads the callback as expected.
The RemoteAuthenticationHandler
This is the code in the handler that handles the challenge and uses the callback path. It sets the callback path as a query parameter to the login url.
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
{
// Add options etc
// ...
// ...
// This defines the login url, with a query parameter for the CallbackPath
var loginUrl = GetLoginUrl(loginOptions);
Response.Redirect(loginUrl);
return Task.CompletedTask;
}
private string GetLoginUrl(MyServiceLoginOptions loginOptions)
{
// This is where the return url is set. The return url
// is used after login credentials are verified.
return $"{Options.LoginPath}" +
$"?returnUrl={UrlEncoder.Encode(Options.CallbackPath)}" +
$"&loginOptions={UrlEncoder.Encode(_loginOptionsProtector.Protect(loginOptions))}";
}
The login controller
This is where the user can provide the credentials and have them verified. After verification, the user is redirected to the callback path.
private async Task<ActionResult> ChallengeComplete(LoginStatusRequest request, ChallengeResponse challengeResponse)
{
// auth logic
// ...
// All is fine, the users credentials have been verified. Now
// we can redirect to the CallbackPath.
return Ok(Response.Finished(returnUri));
}
Note
I could do a URL rewrite but if possible, I would like to use the "correct" /myservice
path to avoid confusion and perhaps causing issues for other services (though very unlikely).
Question
How can I prefix the callback path with /myservice
so my application can process it without also adding the duplicate prefix?
Upvotes: 4
Views: 3221
Reputation: 15005
MapMiddleware
is adding the matched path to the Request.PathBase
, so you can use it when creating the return url
string returnUrl = Context.Request.PathBase + Options.CallbackPath;
Upvotes: 5