Search code examples
authenticationsharepoint12factor

Sharepoint 2013 - FBA and 2FA with custom login page


I'm a complete noob in Sharepoint. I've just started learning sharepoint 2 weeks ago coz my boss assigned me to a sharepoint project. I have to implement 2FA and FBA in an existing claims based intranet web application. I though it would be a simple task to do just by researching but I haven't found a clear guide or answer for my question.

Here are a few of my tasks:

1) Add forms based authentication to the site and use custom login page.

2) Authentication

  • Check user's name and password with AD upon login.
  • If valid, have to request OTP code from the 3rd party provider for 2FA.
  • User is authenticated after passing both.

Configurations and custom login page were not much trouble and it didn't take long to get them done. But I'm stuck at the 2FA part.

1) How to customize the authentication process? I don't remember where did I get the below code but I really hoped that I would be able to do something with it. So, can I do something with it or I'm going the wrong path? I'd really appreciate any help and thanks a lot in advance.

protected void btnLogin_Click(object sender, EventArgs e)
    {
        bool status = SPClaimsUtility.AuthenticateFormsUser(
            Context.Request.UrlReferrer,
            txtUsername.Value.ToString(),
            txtPassword.Value.ToString());

        if (!status) // if auth failed
        {
            lblInvalid.InnerText = "Wrong Username or Password";
            lblInvalid.Visible = true;
        }
        else //if success
        {       
    //What do I do here to change the user back to not authenticated?   

        }
    }

Solution

  • After you properly log in set federated authentication cookie domain.

    HttpCookie httpCookie = current.Response.Cookies["FedAuth"];
    httpCookie.Domain = "." + ConfigurationManager.AppSettings["yourdomain"];
    

    Sign out method is more complicated, long time ago i based my solution on this post

    And sign out method (sorry for variable names but i'm decompiling my old dll) based on sharepoint SignOut page and fix from the post:

    public static void SignOut(SPSite site, SPWeb web, IClaimsPrincipal principal)
    {
        HttpContext current = HttpContext.Current;
        if (current.Session != null)
        {
            current.Session.Clear();
        }
        string value = string.Empty;
        if (current.Request.Browser["supportsEmptyStringInCookieValue"] == "false")
        {
            value = "NoCookie";
        }
        HttpCookie httpCookie = current.Request.Cookies["WSS_KeepSessionAuthenticated"];
        bool flag = false;
        for (int i = 0; i < current.Request.Cookies.Count; i++)
        {
            HttpCookie httpCookie2 = current.Request.Cookies.Get(i);
            if (httpCookie2.Name == "FedAuth" && !flag)
            {
                flag = true;
                httpCookie2.Domain =  WebConfigurationManager.AppSettings["yourdomain"];
            }
        }
        if (httpCookie != null)
        {
            httpCookie.Value = value;
            current.Response.Cookies.Remove("WSS_KeepSessionAuthenticated");
            current.Response.Cookies.Add(httpCookie);
        }
        HttpCookie httpCookie3 = current.Request.Cookies["MSOWebPartPage_AnonymousAccessCookie"];
        if (httpCookie3 != null)
        {
            httpCookie3.Value = value;
            httpCookie3.Expires = new DateTime(1970, 1, 1);
            current.Response.Cookies.Remove("MSOWebPartPage_AnonymousAccessCookie");
            current.Response.Cookies.Add(httpCookie3);
        }
        SPIisSettings iisSettingsWithFallback = site.WebApplication.GetIisSettingsWithFallback(site.Zone);
        if (iisSettingsWithFallback.UseClaimsAuthentication)
        {
            string iPUrl = Authentication.GetIPUrl(principal);
            if (iPUrl != string.Empty)
            {
                string str = HttpUtility.UrlEncode(SPContext.Current.Site.RootWeb.Url);
                string url = iPUrl + "?wa=wsignout1.0&wreply=" + str;
                FederatedAuthentication.SessionAuthenticationModule.SignOut();
                if (current.Session != null)
                {
                    current.Session.Abandon();
                }
                current.Response.Redirect(url);
            }
            else
            {
                FederatedAuthentication.SessionAuthenticationModule.SignOut();
                int num = 0;
                foreach (SPAuthenticationProvider current2 in iisSettingsWithFallback.ClaimsAuthenticationProviders)
                {
                    num++;
                }
                if (num != 1 || !iisSettingsWithFallback.UseWindowsIntegratedAuthentication)
                {
                    if (current.Session != null)
                    {
                        current.Session.Abandon();
                    }
                    SPUtility.Redirect(web.ServerRelativeUrl, 0, current);
                    return;
                }
            }
        }
        if (AuthenticationMode.Forms == SPSecurity.AuthenticationMode)
        {
            FormsAuthentication.SignOut();
            if (current.Session != null)
            {
                current.Session.Abandon();
            }
            SPUtility.Redirect(web.ServerRelativeUrl, 0, current);
        }
        else if (AuthenticationMode.Windows != SPSecurity.AuthenticationMode)
        {
            throw new SPException();
        }
    }
    
    private static string GetIPUrl(IClaimsPrincipal principal)
    {
        string result;
        if (principal == null)
        {
            result = string.Empty;
        }
        else
        {
            string text = string.Empty;
            try
            {
                string text2 = principal.Identity.Name.Split(new char[] {'|'})[1];
                if (SPSecurityTokenServiceManager.Local.TrustedLoginProviders[text2] != null)
                {
                    text = SPSecurityTokenServiceManager.Local.TrustedLoginProviders[text2].ProviderUri.AbsoluteUri;
                }
            }
            catch (Exception ex)
            {
                // log
            }
            result = text;
        }
        return result;
    }
    

    Further reading: