Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make ASP.NET create authenticated session with Owin OpenId Connect library?

After searching through lots of examples online I'm struggling with what seems to be a fairly simple requirement.

I'm trying to extend an existing ASP.NET Application that uses Form Authentication today so that it can use OpenID Connect for authentication as well as some role information coming from the Identity Provider. In particular I'm integrating with an existing hosted Identity Provider that I do not have control over.

I'm using ASP.NET MVC with the Owin components for OpenIdConnect. Namely,

Microsoft.Owin.Security
Microsoft.Owin.Security.Cookies
Microsoft.Owin.Security.OpenIdConnect

I am successfully able to:

  1. In a web browser -- navigate to a controller method that is secured with the [Authorize] attribute
  2. The Owin components properly redirect me to the Identity Provider where I can authenticate and then and I'm redirected back to my app (NOTE: my Identity Provider requires that a redirect_uri be passed in, so I'm currently setting that as part of the OpenIdConnectAuthenticationOptions startup configuration.)
  3. When the redirect back to my app happens, I'm able to see the access_token and the id_token as part of the query string. Additionally, I've been able to use the access_token to call into the user info endpoint and properly derive information about the user using that token.

So far so good! HOWEVER.

What I'm failing to grasp and what most Owin examples I've seen don't seem to explain: what, if any, extra configuration is required to get ASP.NET to actually create an authenticated session in my application based on the redirect from the Identity Provider back to my application.

The general feeling I get from the documentation is that I should NOT have to do extra configuration within the Owin libraries -- that once I've configured the system to use cookie authentication and the OpenId Connect libraries -- that it should just work. However, this doesn't seem to be as easy as it looks. I'm guessing I'm missing something.

Some specific considerations/observations:

  1. Many examples I've found don't require the RedirectUri to be set in the OpenIdConnectAuthenticationOptions, but my Identity Provider requires this parameter to be set each time.
  2. Very few examples that I've found explain whether the controller method that fires as a result of the RedirectUri being hit should be secured with [Authorize] or left anonymous. In my testing, if I mark it as [Authorize] I get into an infinite redirect loop. If I leave it anonymous, I'm able to see the tokens in the request info but the ASP.NET Session is never created. For example, Request.IsAuthenticated is always false.
  3. As a test I've set breakpoints inside several of the OpenIdConnectAuthenticationNotifications() events and currently I'm only seeing my code break into the RedirectToIdentityProvider event, and NONE of the others seem to hit -- which leads me to believe I'm not configuring this right.
  4. Per suggestions I've found, I've set the authentication node this way in the web.config, but it doesn't seem to make a difference if I exclude this node.

    <system.web>
        <authentication mode="None" />
    </system.web>
    

To summarize:

  1. Do I need to specifically write code to handle the returning redirect from the Identity Provider to manually set up the ASP.NET Session (cookie etc.) for the given user? and
  2. If so, should this code go in the controller method that is called as a result of RedirectUri being hit, or should the code go into one of the "Notifications" events available within OpenIdConnectAuthenticationNotifications()?

Lastly, if I'm NOT supposed to be setting up the Authenticated session manually after redirect from the Identity Provider (if it's supposed to work automatically), any suggestions for common mistakes on this configuration?

For completeness:

My Owin pipeline Startup Configuration method:

public void Configuration(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            //no problems on these as far as I can tell
            ClientId = "client_id_string",
            ClientSecret = "client_secret_string",
            Authority = "url_to_identity_provider",
            Scope = "email name etc",

            //I'm properly redirected to this URL but not sure 
            //if I should need to create the session manually
            RedirectUri = "http://mymachine/mymvcapp/authorize",

            //this causes the redirection to come with the access_token, 
            //which is valid
            ResponseType = "token",
            SignInAsAuthenticationType = "Cookies",
            Notifications = new OpenIdConnectAuthenticationNotifications()
            {
                RedirectToIdentityProvider = (context) =>
                {
                    //I'm able to break into this method
                    return Task.FromResult(0);
                },
                MessageReceived = (context) =>
                {
                    //doesn't seem to run this line
                    return Task.FromResult(0);
                },
                SecurityTokenReceived = (context) =>
                {
                    //doesn't seem to run this line
                    return Task.FromResult(0);
                },
                SecurityTokenValidated = (context) =>
                {
                    //doesn't seem to run this line
                    return Task.FromResult(0);
                },
                AuthorizationCodeReceived = (context) =>
                {
                    //doesn't seem to run this line
                    return Task.FromResult(0);
                },
                AuthenticationFailed = (context) =>
                {
                    //doesn't seem to run this line
                    return Task.FromResult(0);
                },
            },
        });
}

My secured method that properly initiates the login flow:

[Authorize]
public class HomeController : Controller
{
    //I'm sent to the login flow the first time this is hit
    public ActionResult Index()
    {
        return View();
    }
}

My method at the RedirectUri that does get called but does indicate that the ASP.NET authenticated session was created:

public class AuthorizeController : Controller
{
    // [Authorize] -- currently this Authorize attribute is turned off 
    //so the method is anonymous. 

    //If I turn that back on, I get infininte redirect loops to 
    //the Identity Provider
    public ActionResult Index()
    {
        //the incoming request to this controller method from the 
        //identity provider DOES include valid access_token and id_token 
        //(which can be used against the user info endpoint) but does not 
        //create a valid ASP.NET session for my web app

        //Request.IsAuthenticated is always false

        //should there be a manual creation of the ASP.NET 
        //session/cookie information in this controller method?

        //note: to me it would make most sense if this attribute was not
        //anonymous since it's unlikely that the Request would ever appear
        //as IsAuthenticated == true, but if you read the entire question
        //it will be clear why I'm trying this method with anonymous access

        return View();
    }
}
like image 287
Fitz Avatar asked Oct 30 '22 11:10

Fitz


1 Answers

As you found out, you can't put an [Authorize] attribute on the method the external server uses to notify you the user was authorized - the session isn't authorized yet, you're just being notified that it should be.

Fortunately, creating that session is not difficult: How can I manually create a authentication cookie instead of the default method?

(I'm pretty sure you have to do this yourself with the basic Microsoft Owin stuff - and you always can do it yourself if you want.)

like image 190
Dave Avatar answered Nov 15 '22 05:11

Dave