Search code examples
openidorchardcmsowin

OpenId Connect Owin Middleware with Orchard CMS 1.9.2


I am trying to take over the Orchard admin authentication flow and replace it with OpenId Connect using Azure AD instead (for SSO purposes). After the user is authenticated with OpenId I want to then sign the user in to Orchard to use Orchard's roles for authorization.

This is the code I have so far

OwinMiddlewareProvider:

public class OpenIdConnectMiddleware : IOwinMiddlewareProvider
{
    public IEnumerable<OwinMiddlewareRegistration> GetOwinMiddlewares()
    {
        return new[]
        {
            new OwinMiddlewareRegistration
            {
                Priority = "1",

                Configure = app => {
                    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

                    app.UseCookieAuthentication(new CookieAuthenticationOptions());

                    app.UseOpenIdConnectAuthentication(
                        new OpenIdConnectAuthenticationOptions
                        {
                            ClientId = "<My Client Id>",
                            Authority = "<My Authority>",
                            RedirectUri = "https://localhost:44357/"
                        });
                }
            }
        };
    }
}

My route for taking over the default access denied route:

new RouteDescriptor {
    Priority = 1,
    Route = new Route(
        "Users/Account/AccessDenied",
        new RouteValueDictionary {
                                {"area", "BCS.Authentication"},
                                {"controller", "Account"},
                                {"action", "LogOn"}
        },
        new RouteValueDictionary (),
        new RouteValueDictionary {
                                {"area", "BCS.Authentication"}
        },
        new MvcRouteHandler())
    }

And finally, my AccountController has the following:

public ActionResult LogOn(string returnUrl)
{
    if (!Request.IsAuthenticated)
    {
        HttpContext.GetOwinContext().Authentication.Challenge(
            new AuthenticationProperties { RedirectUri = string.IsNullOrEmpty(returnUrl) ? "/" : returnUrl },
            OpenIdConnectAuthenticationDefaults.AuthenticationType);

        return new EmptyResult();
    }

    var currentUser = _authenticationService.GetAuthenticatedUser();

    if (currentUser == null)
    {
        // temporary, just for testing purposes
        var user = _membershipService.GetUser("douwinga");
        _authenticationService.SignIn(user, false);
    }

    return new RedirectResult(returnUrl);
}

With this code when I navigate to https://localhost:44357/admin Request.IsAuthenticated is false so it takes me to our ADFS login page. After I sign in I am taken back to the LogOn action and Request.IsAuthenticated is now true. It then tries to use the authenticationService to see if I am authenticated with Orchard and obviously returns null, so it then signs me in to Orchard. If I check the authenticationService to see if I am logged in after the sign in, it returns my user, so I am authenticated with Orchard at this point.

Then comes the issue. I am redirected to /admin now that I am authenticated and it does another authentication check, so I am sent back to the LogOn action of my controller. This time Request.IsAuthenticated is still true, but currentUser is still null, so I am no longer authenticated with Orchard, so it tries to login to Orchard again. This then puts me in a loop.

Is there something I am missing? Is there a better approach?


Solution

  • There is a new module that Radio Systems has been working on. It's also used internally at Microsoft and will be included in Orchard ASAP

    https://github.com/RadioSystems/RadioSystems.AzureAuthentication