Copied to clipboard

Flag this post as spam?

This post will be reported to the moderators as potential spam to be looked at


  • Gadadhar 2 posts 72 karma points
    Oct 24, 2018 @ 14:09
    Gadadhar
    0

    OpenId Connect Hybrid flow in Umbraco Front and back office

    Hi All, I am implementing SSO in our Umbraco(7.6.9) Asp.net MVC application using OpenID connect (Hybrid flow). Already we have implemented SSO for the front-end but we are not able implement this in Back office. We implement this using Umbraco & Owin and we write a global filter.

    public class Startup : UmbracoDefaultOwinStartup
    {
        private readonly string authority = ConfigurationManager.AppSettings["xx"];
        private readonly string clientId = ConfigurationManager.AppSettings["xxx"];
        private readonly string clientSecret = ConfigurationManager.AppSettings["xxx"];
        private readonly string redirectUrl = ConfigurationManager.AppSettings["xxx"];
    
        public new void Configuration(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType("ExternalCookie");
            FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters);
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                LoginPath = new PathString("/Login"),
                CookieName = "ExternalCookie",
                AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
                SlidingExpiration = true,
                ExpireTimeSpan = TimeSpan.FromMinutes(20),
                CookieHttpOnly = true,
                CookieSecure =true
            });
            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    AuthenticationMode = AuthenticationMode.Active,
                    ClientId = clientId,
                    Authority = authority,
                    ClientSecret = clientSecret,
                    ResponseType = OpenIdConnectResponseType.Code,
                    UseTokenLifetime = false,
                    SignInAsAuthenticationType = "ExternalCookie",
                    AuthenticationType = "openId",
                    RedirectUri = redirectUrl,
                    Scope = "openid ad_profile email"
                });
    
            base.Configuration(app);
        }
    
    }
    

    Custom Authentication filter code:

    public class AuthenticationFilter : ActionFilterAttribute, IAuthenticationFilter
    {
        private readonly string umbracoPath = ConfigurationManager.AppSettings[SsoConstants.UmbracoPathKey];
        private readonly string umbracoInstallPath = ConfigurationManager.AppSettings[SsoConstants.UmbracoInstallPath];
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            var bypassAction = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
                               filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
                                   typeof(AllowAnonymousAttribute), true)
                               || filterContext.IsChildAction;
            if (bypassAction || BypassBackOfficeAuthentication(filterContext.HttpContext.Request.RawUrl)) return;
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                filterContext.Controller.TempData[SsoConstants.ReturnUrlKey] = filterContext.HttpContext.Request.RawUrl;
                filterContext.Result = new HttpUnauthorizedResult();
            }
        }
    
        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
            var bypassAction = filterContext.ActionDescriptor.IsDefined(typeof(AllowAnonymousAttribute), true) ||
                               filterContext.ActionDescriptor.ControllerDescriptor.IsDefined(
                                   typeof(AllowAnonymousAttribute), true)
                               || filterContext.IsChildAction;
            if (bypassAction || BypassBackOfficeAuthentication(filterContext.HttpContext.Request.RawUrl)) return;
            if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
            {
                filterContext.Controller.TempData[SsoConstants.ReturnUrlKey] = filterContext.HttpContext.Request.RawUrl;
                filterContext.Result = new HttpUnauthorizedResult();
            }
        }
    
        private bool BypassBackOfficeAuthentication(string url)
        {
            var bypassSsoInBackOffice = false;
            bool.TryParse(ConfigurationManager.AppSettings[SsoConstants.BypassSsoInBackOfficeKey],
                out bypassSsoInBackOffice);
    
            if (bypassSsoInBackOffice)
            {
                return IsBackOfficeUrl(url);
            }
    
            return false;
        }
    
        private bool IsBackOfficeUrl(string url)
        {
            if (url != null)
            {
                var umbracoPathInConfig = umbracoPath.Split('/').Where((val, index) => index == 1).FirstOrDefault();
                var umbracoPathInUrl = url.Split('/').Where((val, index) => index == 1).FirstOrDefault();
                var umbracoInstallPathInConfig = umbracoInstallPath.Split('/').Where((val, index) => index == 1).FirstOrDefault();
                if (!string.IsNullOrWhiteSpace(umbracoPathInConfig) && !string.IsNullOrWhiteSpace(umbracoInstallPathInConfig))
                {
                    var isBackOffice= umbracoPathInConfig.Equals(umbracoPathInUrl, StringComparison.InvariantCultureIgnoreCase);
                    var isInstallUmbracoUrl= umbracoInstallPathInConfig.Equals(umbracoPathInUrl, StringComparison.InvariantCultureIgnoreCase);
                    return isBackOffice || isInstallUmbracoUrl;
                }
            }
    
            return false;
        }
    }
    

    As Umbraco back office has form authentication we are bypassed the SSO for back-office.

    Till this everything working fine and expected. But the back office preview is not working as in master page we show logged in user info and those information comes from SSO provider. So to fix this problem we have to implement SSO in back office as well.

    To achieve this I had spent lots of time but unfortunately I can’t. Now I thought I have share this problem. I am in new to Umbraco so I thought I made some mistake or I chose the wrong path.

    Code for the SSO call action:

    [AllowAnonymous]
        [HttpPost]
        [Route("signin-oidc")]
        public async Task<ActionResult> SigninOidc()
        {
            try
            {
                var returnUrl = TempData[SsoConstants.ReturnUrlKey]?.ToString();
                if (!await ValidateUser())
                {
                    returnUrl = string.IsNullOrWhiteSpace(returnUrl) ? GetRedirectUrl() : returnUrl;
                    Request.GetOwinContext().Authentication.Challenge();
                    var claim = new Claim(SsoConstants.ReturnUrlKey, returnUrl);
                    var claimsIdentity = new ClaimsIdentity(new List<Claim> { claim },
                        DefaultAuthenticationTypes.ApplicationCookie);
                    Request.GetOwinContext().Authentication.SignIn(claimsIdentity);
                    return new HttpUnauthorizedResult();
                }
    
                returnUrl = GetRedirectUrl();
                return Redirect(returnUrl);
            }
            catch (Exception exc)
            {
                Logger.Instance.Error(exc.StackTrace);
                return new HttpUnauthorizedResult();
            }
        }
    private async Task<bool> ValidateUser()
            {
                if (!User.Identity.IsAuthenticated)
                {
                    Logger.Instance.Info("User is not authenticated");
                    return false;
                }
    
            var authToken = await authHandler.GetAuthToken(FormUrlEncodedContent);
            if (authToken == null)
            {
                Logger.Instance.Info("Unable to get authentication token");
                return false;
            }
    
            ExpireAllNonceCookies();
    
            var userInfo = await authHandler.GetUserInfo(authToken);
            if (userInfo == null)
            {
                Logger.Instance.Info("Unable to get user information");
                return false;
            }
    
            var identityClaim = User.Identity as ClaimsIdentity;
            if (identityClaim == null)
            {
                Logger.Instance.Info("Unable to get user claims");
                return false;
            }
    
            var identity = claimHandler.CreateClaims(identityClaim, userInfo, authToken);
            HttpContext.GetOwinContext().Authentication.SignIn(identity);
    
    
            return true;
        }
    

    Any help from any one will be appreciated. I can share more details if require.

    Thanks, Gadadhar

  • Shannon Deminick 1526 posts 5272 karma points MVP 3x
    Oct 24, 2018 @ 23:36
    Shannon Deminick
    0

    I don't think you really want to roll your own solution for OAuth to work with the back office. This is why IdentityExtensions exists: https://our.umbraco.com/Documentation/Reference/Security/#custom-oauth-providers

  • Gadadhar 2 posts 72 karma points
    Oct 26, 2018 @ 09:55
    Gadadhar
    0

    Thank you for for the response. One question, is it support MF authentication?

Please Sign in or register to post replies

Write your reply to:

Draft