IdentityServer / IdentityServer4

OpenID Connect and OAuth 2.0 Framework for ASP.NET Core
https://identityserver.io
Apache License 2.0
9.23k stars 4.02k forks source link

IS4 doesn't work when used in a subpath, messes with base path, breaks redirects #1257

Closed artiomchi closed 7 years ago

artiomchi commented 7 years ago

Issue / Steps to reproduce the problem

I'm upgrading an older MVC 5 app to .NET Core, and as part of that upgrading IS3 to IS4. Because of the way it worked (and following guidelines at the time), IdentityServerwas regustered under a subpath (/auth). Since I have existing customers authenticating with the app, I want to register IS4 under the same path, to keep compatibility, and not break integrations.

I've registered it as follows:

app.Map("/auth", authApp =>
{
    authApp.UseIdentityServer();
});

This causes a "idp claim is missing" error, mentioned in #277. Following that discussion, I've been told that UseIdentityServer() should be called before the call to UseMvc(). Since I'm in a subpath, I've been told to call UseMvc() there as well. I've filtered it to the connect controller, so that it doesn't clash with regular controllers, and I got this:

app.Map("/auth", authApp =>
{
    authApp.UseIdentityServer();
    authApp.UseMvc(routes =>
    {
        routes.MapRoute(
            name: "default",
            template: "connect/{action=Index}/{id?}",
            defaults: new { Controller = "Connect" });
    });
});

The issue is that the redirects from within IS4 think that the whole website is running under /auth. Specifically, when it tries to redirect to the login page, it instead redirects to /auth/account/login. I've tracked it a little, and I believe that's due to what BaseUrlMiddleware is doing.

Relevant parts of the log file

The log isn't much helpful, but it shows the request flow when I'm trying to authenticate. I've copied below the Information lines from the log to display the top level flow, and attached the rest of the log (only contains this request, but has debug lines): identityserver4_log.txt

2017-06-14 10:45:10.062 +01:00 [Information] Request starting HTTP/1.1 GET http://localhost:5000/auth/.well-known/openid-configuration
2017-06-14 10:45:10.228 +01:00 [Information] Invoking IdentityServer endpoint: "IdentityServer4.Endpoints.DiscoveryEndpoint" for "/.well-known/openid-configuration" 2017-06-14 10:45:10.385 +01:00 [Information] Request finished in 334.843ms 200 application/json 2017-06-14 10:45:10.519 +01:00 [Information] Request starting HTTP/1.1 GET http://localhost:5000/auth/.well-known/openid-configuration/jwks
2017-06-14 10:45:10.521 +01:00 [Information] Invoking IdentityServer endpoint: "IdentityServer4.Endpoints.DiscoveryEndpoint" for "/.well-known/openid-configuration/jwks" 2017-06-14 10:45:10.547 +01:00 [Information] Request finished in 27.9845ms 200 application/json 2017-06-14 10:45:10.701 +01:00 [Information] Request starting HTTP/1.1 GET http://localhost:5000/auth/connect/authorize?client_id=mvc&redirect_uri=http%3A%2F%2Flocalhost%3A5002%2Fsignin-oidc&response_type=code%20id_token&scope=openid%20profile%20api1%20offline_access&response_mode=form_post&nonce=636330303105678415.NWJlMjMyMjctYzdmYy00YmZjLWFiYTQtMmViNjFiNTIxMWQ0Njk0OTg5YzgtZjBkZC00YWJlLWJjMTUtNzU1MDFjMzM3Njlm&state=CfDJ8L5xKbxI_OFBmrvA_BJvOS8nGN0YBxk0DEo235q_T1oJPl3xJCQqrsnB8sZlO7i3sy21yowfLwn2o7jBHd0UkzUdxn6LDoZfoYOCE6sI5dbvaE_hu4-8Eh1KzIPtuKPPCDPppizy43vbbj0jLO0RCZ82RpRZjSnw44TL-9c3CZJmBiMJOaSUwZuRVTXO2fmU5HTqlnEFy7ceoTXtEwd6bOc8iceYv_44OdC9AIE5rZaqevG981gIU7maIORDs7hk_Oez1o30NlpN0aYsCZqfnyu7Wzk3ULSeC3XllEzP19yJc3NEEdXBn_EWZ16TiKPOgkDv_3B67jxG56yGyiLmlQM
2017-06-14 10:45:10.707 +01:00 [Information] Invoking IdentityServer endpoint: "IdentityServer4.Endpoints.AuthorizeEndpoint" for "/connect/authorize" 2017-06-14 10:45:10.754 +01:00 [Information] ValidatedAuthorizeRequest "{[…]}" 2017-06-14 10:45:10.757 +01:00 [Information] Showing login: User is not authenticated 2017-06-14 10:45:10.764 +01:00 [Information] Request finished in 62.6917ms 302 2017-06-14 10:45:10.768 +01:00 [Information] Request starting HTTP/1.1 GET http://localhost:5000/auth/account/login?returnUrl=%2Fauth%2Fconnect%2Fauthorize%2Flogin%3Fclient_id%3Dmvc%26redirect_uri%3Dhttp%253A%252F%252Flocalhost%253A5002%252Fsignin-oidc%26response_type%3Dcode%2520id_token%26scope%3Dopenid%2520profile%2520api1%2520offline_access%26response_mode%3Dform_post%26nonce%3D636330303105678415.NWJlMjMyMjctYzdmYy00YmZjLWFiYTQtMmViNjFiNTIxMWQ0Njk0OTg5YzgtZjBkZC00YWJlLWJjMTUtNzU1MDFjMzM3Njlm%26state%3DCfDJ8L5xKbxI_OFBmrvA_BJvOS8nGN0YBxk0DEo235q_T1oJPl3xJCQqrsnB8sZlO7i3sy21yowfLwn2o7jBHd0UkzUdxn6LDoZfoYOCE6sI5dbvaE_hu4-8Eh1KzIPtuKPPCDPppizy43vbbj0jLO0RCZ82RpRZjSnw44TL-9c3CZJmBiMJOaSUwZuRVTXO2fmU5HTqlnEFy7ceoTXtEwd6bOc8iceYv_44OdC9AIE5rZaqevG981gIU7maIORDs7hk_Oez1o30NlpN0aYsCZqfnyu7Wzk3ULSeC3XllEzP19yJc3NEEdXBn_EWZ16TiKPOgkDv_3B67jxG56yGyiLmlQM
2017-06-14 10:45:10.864 +01:00 [Information] Request finished in 95.4729ms 404

brockallen commented 7 years ago

Why are you loading the MVC client and IdSvr in the same host? Doing this it looks like you want the MVC client to use the same cookie as IdSvr. Normally the MVC client issues its own cookie from the OIDC authentication result. I feel like I'm missing some context to your problem.

artiomchi commented 7 years ago

@brockallen well, in my project I've got IdSrv and the MVC app in the same host, but that's a separate discussion.

The issue above uses the sample project in your repo (specifically the QuickStart #6), with minimal adjustments. In there, the IdSrv and the MVC client are separate projects. But if I try to use the IdSrv middleware in a subpath, it doesn't work well.

Ultimately, as I understand, most Owin middleware should handle running under a subpath just fine, so that seems like an issue with IdentityServer4.

brockallen commented 7 years ago

If you want IdentityServer to run under a Map, that's fine -- it's just that the redirects will be relative to that mapped path. So this means your MVC code for the UI must respond to those correct paths.

artiomchi commented 7 years ago

So going over the quockstarts once again, and delving more into this, I think I have a slightly clearer view on the situation.

What I'm trying to achieve is to have a web app that users can log in into using ASP.NET Identity (basic local logins), but also host IdentityServer in that app so that it can be the OpenID Connect Authority for the API (and a couple other sites).

For several reasons, when I did this previously, the authority was hosted under a subpath (~/auth/), so I'm trying to replicated that in the migration from ASP.NET to AspNetCore. I'm also trying to have the app have only a single login page (/Account/Login) instead of having two login pages, one for the local login, and one used by the IdentityServer.

What I was hoping to get is have the IdentityServer discovery document be hosted under /auth/.well-known/openid-configuration, but have it use the existing login page at /Account/Login

My initial attempt was to run IS under a Map, but that screws with the base uri inside IS (is that really necessary?). So maybe there's a different way to achieve what I'm trying to do?

brockallen commented 7 years ago

Are you putting MVC in the pipeline twice (once under ~/auth and once under ~/)? Not sure if that's somehow messing with things. MVC is not designed to be in the pipeline twice (from what MSFT has said).

leastprivilege commented 7 years ago

Any update on the issue? closing for now - feel free to re-open if it needs further discussion.

lock[bot] commented 4 years ago

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.