Login page on different domain

13,354

Solution 1

public class Startup
{
    public void Configuration(IAppBuilder app)
    {
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationMode = AuthenticationMode.Active,
            LoginPath = new PathString("/account/login"),
            LogoutPath = new PathString("/account/logout"),
            Provider = new CookieAuthenticationProvider
            {
                OnApplyRedirect = ApplyRedirect
            },
        });
    }

    private static void ApplyRedirect(CookieApplyRedirectContext context)
    {
        Uri absoluteUri;
        if (Uri.TryCreate(context.RedirectUri, UriKind.Absolute, out absoluteUri))
        {
            var path = PathString.FromUriComponent(absoluteUri);
            if (path == context.OwinContext.Request.PathBase + context.Options.LoginPath)
            {
                context.RedirectUri = "http://accounts.domain.com/login" +
                    new QueryString(
                        context.Options.ReturnUrlParameter,
                        context.Request.Uri.AbsoluteUri);
            }
        }

        context.Response.Redirect(context.RedirectUri);
    }
}

If apps.domain.com is the only return URL base possible, you should strongly consider replacing context.Request.Uri.AbsoluteUri with context.Request.PathBase + context.Request.Path + context.Request.QueryString and build an absolute return URL in your authentication server to protect your apps from abusive redirects.

Hope this helps ;)

EDIT: you might ask yourself why I don't directly apply the redirect using the context.RedirectUri property. In fact, ICookieAuthenticationProvider.ApplyRedirect is responsible of multiple redirects, corresponding to the log-in and log-out flows (yep, I know, it breaks the single responsibility principle...). But there's even worse: context.RedirectUri can either represent the authentication endpoint's absolute URL in the beginning of the log-in flow or the final browser's destination (ie. the real relative "return URL") when the cookie is effectively being sent back to the browser... that's why we need to make sure that context.RedirectUri is absolute and corresponds to the registered context.Options.LoginPath.

Solution 2

I am working through the examples for https://github.com/IdentityServer/IdentityServer3 and I have a different answer. In the example at https://www.scottbrady91.com/Identity-Server/Identity-Server-3-Standalone-Implementation-Part-2 they show an MVC app that uses a standalone IdP and cookies authentication. The example hasn't included getting 401 redirects working, but I stumbled on a way.

The basic scheme is to create an action in the AccountController for logging on.

public ActionResult SignIn() {
  // set up some bookkeeping and construct the URL to the central auth service
  return Redirect(authURL);
}

Now you have a local URL that can be used in the Startup

public class Startup {
  public void Configuration(IAppBuilder app) {
    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
      AuthenticationType = "Cookies",
      LoginPath = new PathString("/Account/SignIn")
    });
}

You also have the added benefit that you can put an action link to the SignIn on the menu bar, for people who want to log on before there is a 401. What we've done here is decoupled the decision of what to do when an unathenticated user asks for a resource from how the authentication is obtained.

Share:
13,354
wired_in
Author by

wired_in

Updated on June 07, 2022

Comments

  • wired_in
    wired_in almost 2 years

    I am completely new to OWIN authentication, and I must be misunderstanding how everything works, but I can't find this mentioned anywhere.

    All I want is to be able to use a central domain for authentication. If someone tries to access apps.domain.com when not authenticated, they will be redirected to accounts.domain.com/login so that all the authentication is separated into it's own domain and application. This was very easy with MVC 4 forms authentication where you can specify a full URL, but doesn't seem to be with OWIN.

    In Startup.Auth.cs:

    app.UseCookieAuthentication(new CookieAuthenticationOptions
    {
        LoginPath = new PathString("/account/login")
    }
    

    It's easy to specify the domain when setting the cookie with the CookieDomain option. However, when you specify the login path to redirect to, it has to be relative to the current application, so how do I go about accomplishing what was so easy in MVC 4 forms authentication?

    Without getting too deep into what OWIN authentication is all about, I could not find anything addressing this after a couple hours of searching.

  • wired_in
    wired_in over 10 years
    Thank you so much for the answer! It looks great, I'll try it out when I get home tonight.
  • Kévin Chalet
    Kévin Chalet over 10 years
    Thanks to Tracher, I've corrected a little bug which prevented this snipped from working when using a PathBase (via app.Map for example). Please see the updated code.
  • Lóri Nóda
    Lóri Nóda over 9 years
    @Pinpoint in are you using another settings near the upper code sample? I trying to use your sample but my application redirects me to "/account/login" by default and the "OnApplyRedirect" event is never called. Can you help me in figuring out the problem?
  • SiberianGuy
    SiberianGuy over 9 years
    @LóriNóda, I have the same problem. May be the solution stopped working due to Owin update. I've created a bountry to draw some attention.
  • Kévin Chalet
    Kévin Chalet over 9 years
    @Idsa I just tested this snippet with both Katana 3 RTM and the latest nightly build (3.0.1-rtw-31016-220-dev) and it worked fine. I used HttpListener but it should work on System.Web or Helios too. You should try to upload a repro somewhere on GitHub so we could try to help you.
  • SiberianGuy
    SiberianGuy over 9 years
    @Pinpoint, could you please upload the working sample you created? May be it would help me to localize my problem
  • SiberianGuy
    SiberianGuy over 9 years
    @Pinpoint, thank you! It was my mistake caused by this: stackoverflow.com/questions/26480414/… So there was an error in my controller constructor and it was thrown before ApplyRedirect should be called
  • infl3x
    infl3x about 6 years
    I much prefer this solution because it uses the framework as intended, rather than overriding ApplyRedirect with custom logic.