Problem in login with firefox with using Open IdConnect (OKTA Integration)

dotnet

#1

Hi,

Application:
.Net 4.5 framework
MVC

In my login page i have two type of login. One is normal database login and another one is OKTA login. Where OKTA login is not working for first time, it always asking the below dialog,

image

And my code snippet is below,

startup.cs

    // These values are stored in Web.config. Make sure you update them!
    private readonly string clientId = ConfigurationManager.AppSettings["okta:ClientId"];
    private readonly string redirectUri = ConfigurationManager.AppSettings["okta:RedirectUri"];
    private readonly string authority = ConfigurationManager.AppSettings["okta:OrgUri"];
    private readonly string clientSecret = ConfigurationManager.AppSettings["okta:ClientSecret"];
    private readonly string postLogoutRedirectUri = ConfigurationManager.AppSettings["okta:PostLogoutRedirectUri"];
    public void Configuration(IAppBuilder app)
    {            
        app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

        app.UseCookieAuthentication(new CookieAuthenticationOptions());

        //For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
        app.UseCookieAuthentication(
           new CookieAuthenticationOptions
           {
               AuthenticationType = "ApplicationCookie",
               LoginPath = new PathString("/account/login")                   
           });            
        ServicePointManager.SecurityProtocol = (SecurityProtocolType)3072;
        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
        {                
            ClientId = clientId,
            ClientSecret = clientSecret,
            Authority = authority,
            RedirectUri = redirectUri,
            ResponseType = OpenIdConnectResponseType.CodeIdToken,
            Scope = OpenIdConnectScope.OpenIdProfile,
            PostLogoutRedirectUri = postLogoutRedirectUri,
            TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
            {
                NameClaimType = "name"
            },

            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthorizationCodeReceived = async n =>
                {
                    // Exchange code for access and ID tokens
                    var tokenClient = new TokenClient(authority + "/v1/token", clientId, clientSecret);
                    var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, redirectUri);

                    if (tokenResponse.IsError)
                    {
                        throw new Exception(tokenResponse.Error);
                    }

                    var userInfoClient = new UserInfoClient(authority + "/v1/userinfo");
                    var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
                    var claims = new List<Claim>();
                    claims.AddRange(userInfoResponse.Claims);
                    claims.Add(new Claim("id_token", tokenResponse.IdentityToken));
                    claims.Add(new Claim("access_token", tokenResponse.AccessToken));

                    if (!string.IsNullOrEmpty(tokenResponse.RefreshToken))
                    {
                        claims.Add(new Claim("refresh_token", tokenResponse.RefreshToken));
                    }

                    n.AuthenticationTicket.Identity.AddClaims(claims);
                    return;
                },

                RedirectToIdentityProvider = n =>
                {
                    // If signing out, add the id_token_hint
                    if (n.ProtocolMessage.RequestType.ToString() == "LogoutRequest")
                    {
                        var idTokenClaim = n.OwinContext.Authentication.User.FindFirst("id_token");

                        if (idTokenClaim != null)
                        {
                            n.ProtocolMessage.IdTokenHint = idTokenClaim.Value;
                        }
                        else
                        {
                            n.HandleResponse();
                        }
                    }
                    //extra
                    return Task.FromResult(0);
                },                    
            },
        });
    }

Accountcontroller.cs
public ActionResult OKTALogin()
{

        if (!HttpContext.User.Identity.IsAuthenticated)
        {
            HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
            return new HttpUnauthorizedResult();
        }
        var identity = (System.Security.Claims.ClaimsIdentity)HttpContext.User.Identity;
        var email = identity.Claims.FirstOrDefault(c => c.Type == "preferred_username").Value;
        var user = userBL.ValidateUserByEmail(email);
        if (user != null && user.AccountStatus == "active")
        {
            return RedirectToAction("index", "home");
        }
        else
        {
            if (HttpContext.User.Identity.IsAuthenticated)
            {
                HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType, OpenIdConnectAuthenticationDefaults.AuthenticationType);
            }
            Session["ActivationStatus"] = "invaliduser";
            Session["EmailId"] = email;
            return RedirectToAction("status");
        }
    }

    //
    // GET: /Account/Logout
    public ActionResult Logout()
    {
        Request.GetOwinContext()
    .Authentication
    .SignOut(HttpContext.GetOwinContext()
                        .Authentication.GetAuthenticationTypes().Select(o => o.AuthenticationType).ToArray());

        System.Web.HttpContext.Current.Application["UserRefId"] = "";
        Response.Cookies.Clear();
        Session.Clear();
        Session["UserBase"] = null;

        Session.Abandon();
        if (HttpContext.User.Identity.IsAuthenticated)
        {
            HttpContext.GetOwinContext().Authentication.SignOut(CookieAuthenticationDefaults.AuthenticationType, OpenIdConnectAuthenticationDefaults.AuthenticationType);
        }

        return RedirectToAction("login");
    }

    public ActionResult PostLogout()
    {
        return RedirectToAction("Login", "Account");
    }

    private ActionResult RedirectToLocal(string returnUrl)
    {
        if (Url.IsLocalUrl(returnUrl))
        {
            return Redirect(returnUrl);
        }
        return RedirectToAction("index", "home");
    }

OKTALogin : this action triggers when OKTA login is clicked and this is triggering continuously in the firefox and edge browser. So user not getting login.

I have found the issue in chrome after OKTALogin claimprinciple sets but in firefox and edge isauthenthicated property is still false even after the login.

So please kindly help us how to resolve this problem?

Regards,
Venu Perumal


#2

Hey @Venu,

I’ve seen that popup a few times when attempting to use the http scheme, as opposed to https. Can you verify the Okta organization you’re attempting to authenticate against contains the https scheme?

If that doesn’t work, which versions of Firefox and Edge are you seeing this in?


#3

Hi @jmelberg,

i have verified and it is https.

Find my version below,

Firefox : 61.0.1
Internet Explorer 11

In chrome its working correctly. I have compared whats happening between chrome and firefox.

In chrome:
After i am giving OKTA credentials it triggers to the OKTALogin(my controller action). where i have trigger to the startup function by checking below codes,

if (!HttpContext.User.Identity.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
return new HttpUnauthorizedResult();

}
return RedirectToAction(“index”, “home”);

And this action goes to the start up class and find the code snippet below,

AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var tokenClient = new TokenClient(authority + “/v1/token”, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, redirectUri);

                    if (tokenResponse.IsError)
                    {
                        throw new Exception(tokenResponse.Error);
                    }

                    var userInfoClient = new UserInfoClient(authority + "/v1/userinfo");
                    var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
                    var claims = new List<Claim>();
                    claims.AddRange(userInfoResponse.Claims);
                    claims.Add(new Claim("id_token", tokenResponse.IdentityToken));
                    claims.Add(new Claim("access_token", tokenResponse.AccessToken));

                    if (!string.IsNullOrEmpty(tokenResponse.RefreshToken))
                    {
                        claims.Add(new Claim("refresh_token", tokenResponse.RefreshToken));
                    }

                    n.AuthenticationTicket.Identity.AddClaims(claims);
                    return;
                },

Where here claim principle value set automatically and it triggers back to the login page and if condition failed and go to my home page

In firefox:
After i am giving OKTA credentials it triggers to the OKTALogin(my controller action). where i have trigger to the startup function by checking below codes,

if (!HttpContext.User.Identity.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
return new HttpUnauthorizedResult();

}
return RedirectToAction(“index”, “home”);

And this action go to the start up class and please find the code snippet below,

AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var tokenClient = new TokenClient(authority + “/v1/token”, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, redirectUri);

                    if (tokenResponse.IsError)
                    {
                        throw new Exception(tokenResponse.Error);
                    }

                    var userInfoClient = new UserInfoClient(authority + "/v1/userinfo");
                    var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken);
                    var claims = new List<Claim>();
                    claims.AddRange(userInfoResponse.Claims);
                    claims.Add(new Claim("id_token", tokenResponse.IdentityToken));
                    claims.Add(new Claim("access_token", tokenResponse.AccessToken));

                    if (!string.IsNullOrEmpty(tokenResponse.RefreshToken))
                    {
                        claims.Add(new Claim("refresh_token", tokenResponse.RefreshToken));
                    }

                    n.AuthenticationTicket.Identity.AddClaims(claims);
                    return;
                },

Where here claim principle value should set automatically but after it triggers back to the login page and authentication is still false so condition satisfied and it triggers again to the startup class. So this process continuously happening hence dialog comes again and again in firefox or IE.

Regards,
Venu Perumal


#4

Hi @jmelberg,

In chrome its working correctly. I have compared whats happening between chrome and firefox.

In chrome:
After i am giving OKTA credentials it triggers to the OKTALogin(my controller action). where i have trigger to the startup function by checking below codes,

if (!HttpContext.User.Identity.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
return new HttpUnauthorizedResult();

}
return RedirectToAction(“index”, “home”);

And this action goes to the start up class and find the code snippet below,

AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var tokenClient = new TokenClient(authority + “/v1/token”, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, redirectUri);

                    if (tokenResponse.IsError) { throw new Exception(tokenResponse.Error); } var userInfoClient = new UserInfoClient(authority + "/v1/userinfo"); var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken); var claims = new List<Claim>(); claims.AddRange(userInfoResponse.Claims); claims.Add(new Claim("id_token", tokenResponse.IdentityToken)); claims.Add(new Claim("access_token", tokenResponse.AccessToken)); if (!string.IsNullOrEmpty(tokenResponse.RefreshToken)) { claims.Add(new Claim("refresh_token", tokenResponse.RefreshToken)); } n.AuthenticationTicket.Identity.AddClaims(claims); return; },

Where here claim principle value set automatically and it triggers back to the login page and if condition failed and go to my home page

In firefox:
After i am giving OKTA credentials it triggers to the OKTALogin(my controller action). where i have trigger to the startup function by checking below codes,

if (!HttpContext.User.Identity.IsAuthenticated)
{
HttpContext.GetOwinContext().Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
return new HttpUnauthorizedResult();

}
return RedirectToAction(“index”, “home”);

And this action go to the start up class and please find the code snippet below,

AuthorizationCodeReceived = async n =>
{
// Exchange code for access and ID tokens
var tokenClient = new TokenClient(authority + “/v1/token”, clientId, clientSecret);
var tokenResponse = await tokenClient.RequestAuthorizationCodeAsync(n.Code, redirectUri);

                    if (tokenResponse.IsError) { throw new Exception(tokenResponse.Error); } var userInfoClient = new UserInfoClient(authority + "/v1/userinfo"); var userInfoResponse = await userInfoClient.GetAsync(tokenResponse.AccessToken); var claims = new List<Claim>(); claims.AddRange(userInfoResponse.Claims); claims.Add(new Claim("id_token", tokenResponse.IdentityToken)); claims.Add(new Claim("access_token", tokenResponse.AccessToken)); if (!string.IsNullOrEmpty(tokenResponse.RefreshToken)) { claims.Add(new Claim("refresh_token", tokenResponse.RefreshToken)); } n.AuthenticationTicket.Identity.AddClaims(claims); return; },

Where here claim principle value should set automatically but after it triggers back to the login page and authentication is still false so condition satisfied and it triggers again to the startup class. So this process continuously happening hence dialog comes again and again in firefox or IE.

Regards,

Venu Perumal