-
Notifications
You must be signed in to change notification settings - Fork 65
Remote authentication not working as expected #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
Hi! I just ran into this as well. I don't have a fix, but I think I'm one step nearer to a solution. I noticed that when I hit the @br3nt, can you confirm if you're seeing that as well? |
Frustratingly, when I try to inspect the traffic with Telerik Fiddler, the issue disappears. But running without Fiddler, I only get the one cookie. When Fiddler is open and I'm getting all 3 cookies, login works correctly. |
Hi @zsharp-gls. Nice to have some company :) I also have a one cookie when A normal authenticated request has lots of cookies set:
The <authentication mode="Forms">
<forms loginUrl="~/Account/Login" timeout="2880" />
</authentication> I'll see if I can inspect the traffic too. |
I have used the "Open Browser" button in Telerik Fiddler to inspect the traffic. When using the Telerik browser there is no difference in the cookies when navigating to a page from the .NET app vs from
In However, the I don't know what to debug from here. I'm curious why Fiddler produces a different response than when using the default browser. |
So, I've started debugging the .Net Core side of things. I had similar troubles debugging because all the classes and interfaces are internal... I had to make local copies and manually configure them into the DI container. The response returned to
This is an unexpected response as It still doesn't explain why the request to Again, I'm now a little lost as to what I should try to debug next. Are cookies meant to be added to the |
This comment was marked as off-topic.
This comment was marked as off-topic.
Yes, cookies are one of the headers listed in the I looked closer at the cookie header that the .NET Framework app is receiving (in When it's not working, The cookies are being forwarded from the ASP.NET Core app to the This seems to me to be the core issue, but I'm not sure how to confirm that or how to fix it. |
@br3nt @zsharp-gls Thanks for reporting this and doing some debugging! We'll take a look. |
@adityamandaleeka @mjrousos have you had any success? I have continued trying to look into this issue. Thank you @zsharp-gls for identifying the Cookie delimiter issue. The problem of the Cookie header format was also logged here: dotnet/aspnetcore#22351 According to https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Cookie and https://httpwg.org/specs/rfc6265.html#cookie, the correct Cookie header format is to delimit the cookie values with I can confirm that when I manually set the I was able to get this to work with the addition of internal partial class RemoteAppAuthenticationService : IRemoteAppAuthenticationService
{
// Add configured headers to the request, or all headers if none in particular are specified
private static void AddHeaders(IEnumerable<string> headersToForward, HttpRequest originalRequest, HttpRequestMessage authRequest)
{
// Add x-forwarded headers so that the authenticate API will know which host the HTTP request was addressed to originally.
// These headers are also used by result processors - to fix-up redirect responses, for example, to redirect back to the
// correct host.
authRequest.Headers.Add(AuthenticationConstants.ForwardedHostHeaderName, originalRequest.Host.Value);
authRequest.Headers.Add(AuthenticationConstants.ForwardedProtoHeaderName, originalRequest.Scheme);
// The migration authentication request header indicates that the request is from the ASP.NET Core app
// with the intention of authenticating the user. Without this header, the request will be interpreted
// as a callback after authenticating with an identity provider.
authRequest.Headers.Add(AuthenticationConstants.MigrationAuthenticateRequestHeaderName, "true");
IEnumerable<string> headerNames = originalRequest.Headers.Keys;
if (headersToForward.Any())
{
headerNames = headerNames.Where(headersToForward.Contains);
}
foreach (var headerName in headerNames)
{
switch (headerName)
{
case "Cookie":
AddCookieHeaders(originalRequest, authRequest);
break;
default:
authRequest.Headers.Add(headerName, originalRequest.Headers[headerName].ToArray());
break;
}
}
}
private static void AddCookieHeaders(HttpRequest originalRequest, HttpRequestMessage authRequest)
{
var cookies = originalRequest.Cookies.ToArray();
var cookieValues = cookies.Select(c => $"{c.Key}={c.Value}").ToArray();
var cookieHeaderValue = string.Join("; ", cookieValues);
if (cookies.Any()) authRequest.Headers.Add("Cookie", cookieHeaderValue);
}
} It seems like a workaround will be required in this library, until Unfortunately, there may be additional issues past this point. Event though the request is authenticated and the ASP.NET Core app receives the ClaimsPrincipal, the browser receives a completely blank page. There is not HTML in the response to the browser. |
Just chucking an alternative approach out here: perhaps you could allow your asp.net core app to understand the forms authentication cookie natively and login / restore the claims principal from it, without having to do remote proxy auth. You can do that with this library I made: https://github.com/dazinator/AspNetCore.LegacyAuthCookieCompat |
@br3nt, I think you're right that the issue is the cookie delimiter. It seems that HttpClient is incorreclty delimiting with , instead of ;. There was actually a similar workaround needed in our YARP code. That same code change is likely to address this issue. I'll test it out and get a PR opened. |
Note we tracked this down to an HTTP/2 bug in Kestrel and fixed it in .NET 7. We'll add a workaround here for prior versions. |
In cases of multi-headers, HttpClient concatenates the headers with , . In the case of multi-header cookie headers, though (which can happen because of dotnet/aspnetcore#26461), RFC 6265 specifies that multiple cookies must be concatenated with ; when writing the Cookie header. HttpClient doesn't special case the Cookie header as it should, so this updates the RemoteAppAuthenticationService to special case cookie headers and concatenate them itself, if needed. Fixes #228
For anyone looking for alternative options, I believe @br3nt has got this working now using native forms authentication for .net core rather than remote proxy auth - based on his updates here (of course which I am quite proud, because re-implementing legacy forms auth with all of it's varying modes is not trivial): There are also benefits to doing this natively - mainly:-
|
Describe the bug
I have followed the incremental migration blog post series.
The setup correctly proxies to pages from the ASP.NET MVC application. I am able to login and navigate the existing site as an authenticated user. I can also see remote session variables are being requested successfully and accessible in ASP.NET Core MVC controller actions.
When I protect an endpoint in the ASP.NET Core MVC app with
[Authorize]
such as ,UserInfoController.Index
, I can see that a request to the endpoint results in a request to the remote authentication endpoint,http://localhost:52187/systemweb-adapters/authenticate?original-url=%2FUserInfo
, as expected. However, the authentication fails and I am redirected to the ASP.NET MVC login page.By adding a breakpoint in
AccountController.Login
, I can verify thatHttpContext.User.Identity.IsAuthenticated
istrue
as I expect because I haven't logged out.To debug the what was happening in
/systemweb-adapters/authenticate
, I had to copy several internal classes from Microsoft.AspNetCore.SystemWebAdapters, and configure them manually.I found that
context.User.Identity.IsAuthenticated
inRemoteAppAuthenticationHttpHandler.ProcessRequest()
isfalse
.This results in a
401
response, hence why I am being redirected back to the login page.But then, in
AccountController.Login
the user is authenticated.I don't know how to debug further than this. I don't understand why
context.User.Identity.IsAuthenticated
inRemoteAppAuthenticationHttpHandler.ProcessRequest()
isfalse
andHttpContext.User.Identity.IsAuthenticated
inAccountController.Login
istrue
. According to the blog post, the request should be authenticated and the user redirected back to the page from ASP.NET Core MVC app.To Reproduce
I am unsure how to reproduce this.
I have simply followed the examples in the incremental migration blog post series.
Exceptions (if any)
None.
Further technical details
Please include the following if applicable:
ASP.NET Framework Application:
ASP.NET Core Application:
The text was updated successfully, but these errors were encountered: