[Last Call] Learn how to a build a cloud-first strategyRegister Now

x
?
Solved

FormsAuthentication problems

Posted on 2009-12-21
5
Medium Priority
?
509 Views
Last Modified: 2013-12-17
I'm having some odd problems. I'm programming my own login system for a .Net application. I was using another website that I didn't build but do maintain as the basis for my code. What is happening is that I want the User.Identity.Name to be a GUID that I pull from a database. Instead, what is occuring is that the username is being saved. Here's the pertinent parts of the code that I'm using... User is simply a custom class that has code to load itself from the database.  If the user is found in the database, then the GUID is loaded, otherwise a new GUID is loaded. After that it has the ability to flag if a submitted password matches the encrypted password stored in the DB. The call for User(string, bool, bool) is for a username, flag to load the password, flag to include deleted users.

The login system seems to work, except that any data I try to put in the userData variable of the FormsAuthenticationTicket cannot be retrieved, and the Identity.Name, which I intended to be a GUID, comes back as the username.



---------------------
login.aspx.cs snippet
---------------------

protected void loginBox_Authenticate(object sender, AuthenticateEventArgs e)
{
    bool isOK = Page.IsValid;
    IPrincipal p = null;
    Authentication.LoginFailure loginResponse;
    if (isOK)
    {
        p = Authentication.AuthenticateUserAsMember(loginBox.UserName, loginBox.Password, out loginResponse);
        switch (loginResponse)
        {
            case Authentication.LoginFailure.LockedOut:
            case Authentication.LoginFailure.Deleted:
                loginBox.FailureText = "Please contact support to reactivate your account.";
                isOK = false;
                break;
            case Authentication.LoginFailure.Inactive:
                loginBox.FailureText = "Please contact support to activate your account.";
                isOK = false;
                break;
            case Authentication.LoginFailure.PasswordNone:
            case Authentication.LoginFailure.PasswordUnknown:
                loginBox.FailureText = "Invalid Password or Username.";
                isOK = false;
                break;
            case Authentication.LoginFailure.UsernameNone:
            case Authentication.LoginFailure.UsernameUnknown:
                loginBox.FailureText = "Invalid User Name or Password.";
                isOK = false;
                break;
            case Authentication.LoginFailure.None:
                isOK = true;
                break;
            default: //Covers Unknown and Other
                loginBox.FailureText = "An error occured. Please contact support.";
                isOK = false;
                break;
        }
        e.Authenticated = isOK;
        if (e.Authenticated)
        {
            DateTime now = DateTime.UtcNow;
            FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                    1,
                    p.Identity.Name,
                    now,
                    now.AddMinutes(30),
                    false,
                    string.Empty,
                    FormsAuthentication.FormsCookiePath);
            string encryptedTicket = FormsAuthentication.Encrypt(ticket);
            HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, encryptedTicket);
            cookie.Expires = ticket.Expiration;
            cookie["TimeZoneOffset"] = Session["TimeZoneOffset"] == null ? "0" : (int.Parse(Session["TimeZoneOffset"].ToString()) / 60).ToString();
            Response.Cookies.Add(cookie);
        }
    }
}

protected void loginBox_LoggedIn(object sender, EventArgs e)
{
    Response.Redirect(FormsAuthentication.GetRedirectUrl(User.Identity.Name, true));
}

-----------------
Authentication.cs
-----------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Security;
using System.Security.Principal;

namespace Site.Security
{
    public abstract class Authentication
    {
        public enum LoginFailure
        {
            Unknown = 0,
            None = 10,
            UsernameNone = 20,
            UsernameUnknown = 30,
            PasswordNone = 40,
            PasswordUnknown = 50,
            Inactive = 60,
            LockedOut = 70,
            Deleted = 80,
            Other = 100
        }

        private static IPrincipal GetPrincipalFromUserId(Guid userID, Users.UserType userType)
        {
            return new GenericPrincipal(GetIdent(userID.ToString()), new string[1] { userType.ToString() });
        }

        private static IPrincipal GetUnauthenticatedPrincipal()
        {
            return new GenericPrincipal(GetIdent(string.Empty), new string[0]);
        }

        private static IIdentity GetIdent(string userID)
        {
            return new GenericIdentity(userID);
        }

        public static IPrincipal AuthenticateUserAsMember(string userName, string password, out LoginFailure loginResponse)
        {
            User u = null;
            loginResponse = LoginFailure.Unknown;
            if (string.IsNullOrEmpty(userName))
            {
                loginResponse = LoginFailure.UsernameNone;
            }
            else if (string.IsNullOrEmpty(password))
            {
                loginResponse = LoginFailure.PasswordNone;
            }
            else
            {
                u = new User(userName, true, true);
                if (u.UserID == Guid.Empty)
                {
                    loginResponse = LoginFailure.UsernameUnknown;
                }
                else if (u.IsDeleted)
                {
                    loginResponse = LoginFailure.Deleted;
                }
                else if (u.IsLockedOut)
                {
                    loginResponse = LoginFailure.LockedOut;
                }
                else if (u.IsActive != true)
                {
                    loginResponse = LoginFailure.Inactive;
                }
                else if (u.MatchPassword(password) != true)
                {
                    loginResponse = LoginFailure.PasswordUnknown;
                }
            }
            if (loginResponse != LoginFailure.Unknown)
            {
                return GetUnauthenticatedPrincipal();
            }
            else
            {
                loginResponse = LoginFailure.None;
                u.UpdateLastLoginDate();
                return GetPrincipalFromUserId(u.UserID, u.UserType);
            }
        }
    }
}
-----------------------
root web.config snippet
-----------------------
<authentication mode="Forms">
            <forms name=".FoxTrotCorpAuth" loginUrl="~/Login.aspx" defaultUrl="~/secure/Default.aspx" protection="All" timeout="30" path="/" requireSSL="false" slidingExpiration="true" enableCrossAppRedirects="false" cookieless="UseCookies" domain="" />
        </authentication>
        <authorization>
            <allow users="*"/>
        </authorization>

--------------------------------
web.config of secured directory
--------------------------------
<configuration>
    <appSettings/>
    <connectionStrings/>
    <system.web>
        <authorization>
            <deny users="?" />
        </authorization>
    </system.web>
</configuration>

Open in new window

0
Comment
Question by:CCongdon
  • 2
  • 2
5 Comments
 
LVL 11

Expert Comment

by:five22bags
ID: 26097158
If its any help, you can get the UserID from the users table like so:


MembershipUser myObject = Membership.GetUser();
string UserID = myObject.ProviderUserKey.ToString();

Open in new window

0
 
LVL 9

Author Comment

by:CCongdon
ID: 26097171
I'm not actually using any membership provider to run this login system.
0
 
LVL 11

Accepted Solution

by:
five22bags earned 2000 total points
ID: 26097408
The cookie used for authentication is a persistent one. This article has been mentioned on other forums regarding this exact issue and it has worked several times for several people. It might take some work, but it has been working for other people like yourself.

http://www.asp.net/learn/security/tutorial-03-cs.aspx
0
 
LVL 41

Expert Comment

by:guru_sami
ID: 26097565
FormsAuthenticationTicket ticket = new FormsAuthenticationTicket(
                    1,
                    p.Identity.Name, ....)

whatever you pass in as second parameter to FormsAuthenticationTicket( i.e. here p.Identity.Name) will show up as User.Identity.Name.
So if you pass your Guid it will give you Guid....your pass "ABCD" it will give you "ABCD".

But again you will lose the username and so you need to fetch it if you want to use/display it.
Instead us the Userdata parameter(i.e. here   string.Empty) to store the Guid.
0
 
LVL 9

Author Comment

by:CCongdon
ID: 26100322
@guru_sami: That was actually the problem with the code I was showing. I was passing the GUID into the p.Identity.Name paramater, and passing that into the ticket...but was getting the login name back. In the end, I think it might be because I was using a Login control. I think there was some extra stuff going on behind the scenes with that.
@five22bags: Thanks for pointing me in the right direction. I see that some of the code I was using is completely unnecessary. In addition, I finally figured out an easier way to keep the extra details I need. Since I'm using a GUID, I've got a unique key for each user...so, I am passing my custom user object into the System.Web.Cache with a key of the GUID for the user. Then, I've created a public property on my master page for accessing the cached user object with intelligence to re-load it if the cached version isn't found. That property grabs Cache.Get(Context.User.Identity) and casts it as my User object. Works like a charm!
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Problem Hi all,    While many today have fast Internet connection, there are many still who do not, or are connecting through devices with a slower connect, so light web pages and fast load times are still popular.    If your ASP.NET page …
Hello there! As a developer I have modified and refactored the unit tests which was written by fellow developers in the past. On the course, I have gone through various misconceptions and technical challenges when it comes to implementation. I would…
In a question here at Experts Exchange (https://www.experts-exchange.com/questions/29062564/Adobe-acrobat-reader-DC.html), a member asked how to create a signature in Adobe Acrobat Reader DC (the free Reader product, not the paid, full Acrobat produ…
As many of you are aware about Scanpst.exe utility which is owned by Microsoft itself to repair inaccessible or damaged PST files, but the question is do you really think Scanpst.exe is capable to repair all sorts of PST related corruption issues?
Suggested Courses
Course of the Month18 days, 2 hours left to enroll

830 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question