Skip to content
This repository has been archived by the owner on Nov 17, 2023. It is now read-only.

MVC LOGIN REDIRECT #1139

Closed
FrankDupree opened this issue Sep 25, 2019 · 11 comments
Closed

MVC LOGIN REDIRECT #1139

FrankDupree opened this issue Sep 25, 2019 · 11 comments

Comments

@FrankDupree
Copy link

Hi @raimundoteixeira,

I ran curl from my computer's command prompt, not from the container's.

BTW, that's the way it should be, because that's a "redirect" address. That means it's not really a callback from identity.api to the webmvc microservice.

Let's go through the login process as seen with Fiddler (and use this to document the process later in the wiki 😉):

  1. User tries to login into webmvc, but they are not autorized, so it's redirected to check authorization with identity.api:

image

  1. But they're not authorized either (not even uthenticated), so they are redirected, once again, to the login page:

image

  1. So they are shown the login page:

image

  1. When the user logs in, they are redirected to the /connect/authorize/callback (in identity.api):

image

  1. The user is shown an intermediate login page (that you never get to see, unless you don't have JS enabled) that posts the necessary data as hidden inputs to http://localhost:5100/signin-oidc (but this is done from the browser, not from identity.api):

image

You'd see this if JS were disabled:

image

  1. So after posting the login data, the user finally gets redirected directed, one again, to http://localhost/Account/SignIn (this is the MVC app):

image

  1. Where they are redirected, finally, to the MVC home page:

image

So it's a pretty complex flow, but, as you can see, the sign in is done from the browser, in steps 5-6.

Just to be 100% sure, I added a SerilogLoggingMiddleware to the request pipeline, and the events correlate perfectly with the above:

image

Hope this helps.

Originally posted by @mvelosop in #1050 (comment)

@FrankDupree
Copy link
Author

@mvelosop Thanks for the detailed fiddler workflow, its making more sense now. But i seem to have hit a snag, on visual studio with debugging turned on, I set a break point on the Account/Signin controller, for some strange reasons its not being hit. a look at the ClientRedirectUris table shows the entry is correct. any help please?

@FrankDupree
Copy link
Author

I'm trying to access the token thats stored in the ViewData, if the endpoint doesn't get hit, i cant access it. Or is there another means of accessing it?

[Authorize]
        public async Task<IActionResult> SignIn(string returnUrl)
        {
            var user = User as ClaimsPrincipal;

            var token = await HttpContext.GetTokenAsync("access_token");
            _logger.LogInformation("----- User {@User} authenticated into {AppName}", user, Program.AppName);

            if (token != null)
            {
                ViewData["access_token"] = token;
            }

            // "Catalog" because UrlHelper doesn't support nameof() for controllers
            // https://github.com/aspnet/Mvc/issues/5853
            return RedirectToAction(nameof(HomeController.Index), "Home");
        }

@mvelosop
Copy link
Collaborator

Hi @FrankDupree,

That controller is probably from an old version, because currently the authentication is handled by the oidc handler in the request pipeline, so it never gets to reach the controller.

However, taking a look at the Using the access token section in the IdentityServer documentation might help you.

I also pushed a the explore/identity-server-login-flow branch I used while exploring for issue #1050, so you can explore commit bcf7b72 with the changes to peek into the request pipeline with logging.

Hope this helps.

@FrankDupree
Copy link
Author

FrankDupree commented Sep 26, 2019

Hi @mvelosop

Thank you for the quick response. Will check it out. I also noticed there is no ordering.signalr mapping in ocelot (ApiGateways folder). any reasons why?

@mvelosop
Copy link
Collaborator

Great, let me know how it goes.

About SignalR, I've merely scratch the surface but, could this be what you're looking for?:

"DownstreamPathTemplate": "/{everything}",
"DownstreamScheme": "http",
"DownstreamHostAndPorts": [
{
"Host": "ordering.signalrhub",
"Port": 80
}
],
"UpstreamPathTemplate": "/hub/{everything}",
"UpstreamHttpMethod": []

Hope this helps.

@FrankDupree
Copy link
Author

FrankDupree commented Sep 27, 2019

@mvelosop Thanks for the link, i was able to get signalr up, but i keep getting a 401 unauthorized. Placing the authorize attribute on a controller works just fine as ocelot validates the request, but the same authorize attribute on the signalr hub class throws 401.

I was able to get a stable connection after tweaking the following method in startup.cs:

private void ConfigureAuthService(IServiceCollection services)
        {
            // prevent from mapping "sub" claim to nameidentifier.
            JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Remove("sub");

            var identityUrl = Configuration.GetValue<string>("IdentityUrl");

            services.AddAuthentication(options =>
            {
                options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;

            }).AddJwtBearer(options =>
            {
                options.Authority = identityUrl;
                options.RequireHttpsMetadata = false;
                options.Audience = "chats";

                **options.Events = new JwtBearerEvents
                {
                    OnMessageReceived = context =>
                    {
                        var accessToken = context.Request.Query["access_token"];
                        // If the request is for our hub...
                        var path = context.HttpContext.Request.Path;
                        if (!string.IsNullOrEmpty(accessToken) &&
                            (path.StartsWithSegments("/hub")))
                        {
                            // Read the token out of the query string
                            context.Token = accessToken;
                        }
                        return Task.CompletedTask;
                    }
                };**
            });
        }

How does the eshopOnContainer Ordering.SignalrHub service work around this?

@mvelosop
Copy link
Collaborator

mvelosop commented Oct 9, 2019

Hi @FrankDupree, I'm a bit confused, is this happening in eShopOnContainers?

@FrankDupree
Copy link
Author

@mvelosop i'm sorry, will be closing this issue now. figured it out. I'm actually running the project from visual studio.

@mvelosop
Copy link
Collaborator

mvelosop commented Oct 9, 2019

Great @FrankDupree, it'd be nice if you could share some of your findings for the community 😉

@FrankDupree
Copy link
Author

FrankDupree commented Oct 9, 2019

@mvelosop you know how these things are. could be specific problems related to different environments. but i did complain about my signalr client and i noticed something quite strange.

ocelot maps the "order-signalr" route well, but the connection always fails because the javascript signalr client decides to use "ws:localhost:xxxx" and ocelot isn't configured to listen to a web socket connection. again, i am running the application outside docker but directly from visual studio.

I'm actively scanning through the issues and will be happy to share insights if i can. Nice work on the eshop project. learning alot.

@mvelosop
Copy link
Collaborator

Thanks for the insight @FrankDupree!

Anyway, it might be interesting for you to know that eShop is migrating to Envoy in the upcoming .NET Core 3 migration.

Cheers.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants