<$BlogRSDUrl$>

Tuesday, February 03, 2004

meetup 



find out more at longhorn.meetup.com

Friday, January 23, 2004

new blog 

I've started a newer, fresher, better blog - head over there now! Oh, it's also crispier and more fragrant.

Thursday, January 22, 2004

user authentication 

Ever so often I get totally baffled, surprised, and even emotional when I see the way some developers authenticate users in their ASP sites.
Last week I spoke to a guy who wrote static methods to encrypt and decrypt credentials, as well as classes to do the validation and authentication for the site. I guess this all carries over from days before .NET (can you imagine that?!) where this had to be done often enough. With the lovely .NET foundation beneath you, it's so easy to use the built-in methods provided. Here's how you authenticate using ASP.NET's "Forms Authentication Mode" and encrypted user credentials in a database.

Authenticated users are issued with a cookie. Unauthenticated users are redirected via client-side HTTP to an authentication-form, where the cookie is issued. Authentication can happen in any way the developer finds fit. I find using the built-in .NET support for MD5 encryption suffices.

Let's set it up. First, in your web.config file, set your authentication-mode:

<authentication mode="Forms">
    <forms name=".ASPXAUTH" protection="All" timeout="60" loginUrl="Login.aspx" />
</authentication>

This would redirect the client to a page named Login.aspx if the user is not authenticated. Once authenticated, a cookie named .ASPXAUTH will be issued to the user, who will hence be authenticated on all other pages.

Create a simple login-page named Login.aspx, and do the following in the click-event for your 'submit' button in code-behind:

private void cmdSubmit_ServerClick(object sender, System.EventArgs e)
{
    DataSet ds = new DataSet();
    //I'm leaving the exercise of building a dataset containing usernames & (encrypted) passwords
    //to the reader.

    String cmd = "username='" + txtUsername.Text + "'";
    DataTable users = ds.Tables[0];
    DataRow[] matches = users.Select(cmd);

    if (matches != null && matches.Length > 0
    {
        DataRow row = matches[0];
        string hashedpwd =
            FormsAuthentication.HashPasswordForStoringInConfigFile(txtPassword.Text, "MD5");
        String pass = (String)row["password"];
        if(0 != String.Compare(pass, hashedpwd, false))
        {
            result.InnerHtml = "Invalid Credentials: Please try again.";
        }
        else
        {
            FormsAuthentication.RedirectFromLoginPage(txtUsername.Text, true);
        }
    }
    else
    {
        result.InnerHtml = "Invalid Credentials: Please try again.";
    }
}

Notice the use of the HashPasswordForStoringInConfigFile-method. I chose the MD5 encryption algorythm here, but the method also accepts "SHA1" as a parameter. No need for customized encryption classes!

To validate user-authentication on pages in your app, do the following in the Page_Load events:

private void Page_Load(object sender, System.EventArgs e)
{
    if(!User.Identity.IsAuthenticated)
    {
        Response.Redirect("login.aspx");
    }
}

Once a client hits any page in your app, validation will fail, and redirection to your login-page will occur. After authentication, the user will be redirected to the originally requested page.

More info on Forms Authentication methods is available here.

Friday, January 09, 2004

back in the swing 

The holidays were totally, unexpectedly wicked. None of my plans worked out, but the time off was excrutiatingly relaxing nonetheless :) There came a point where we could literally cut the relaxation with a knife. I decided that 2004 will ROCK. May it do the same for you guys reading this!

My bro & me
Pic taken of me (on the left) and my younger, but not smaller, brother during the holidays.

Friday, December 12, 2003

last day in the office 

A long awaited holiday starts as soon as I leave the office today!!!
Getting away from the office would enable me to do some *serious* relaxation, but more importantly (possibly more exciting): I'll have more time for private venturing :) whatever the heck that might be...

I'm developing my first large-scale ASP.NET based site, which should be live in January if all goes well. I'm using mySQL on the backend, and I'm quite worried about that part of it. I've heard many doomsday prophecies about it, but then I say there's only one way to find out. (Testing does not yield any problems so far).

Yeehah. I'm outta here.

Monday, December 08, 2003

dynamic enums 

Like most people in the software industry, I have these (amongst a gazillion others) few simple requirements:

1)  I want developers' code to be as readable as possible. (!)
2)  I want to simplify the task of writing code as much as possible
     (In this case, by using intellisense)
3)  I like the idea of increased control over what's available to developers, as this increases the degree to which code adheres to an internal standard.

I came up with the far-fetched idea of having a table in a database where values can be set, specifying certain enums available to developers.

Let me provide a simple example:
Suppose a base class for users of an app (let's call this class 'User') has one public property called 'AuthorityLevel', which contains an integer-value to denote a user's level of authority. A user with level 3 will have access to admin-functions, whereas a user with level 2 will only be able to print certain reports, for instance. Don't look too much into this class - it's purpose is to merely serve as an example!

The following enum will provide you with what you need:

    public enum AuthorityLevel {Minion = 1, Worker, Manager}

Once it's hard-coded, however, there's no easy way of changing it. It would be nice to be able to change the values or descriptions in this enum, knowing that developers will write code against whatever you specified.
I thought of this solution last week: The enums you want your developers to use should reside in a seperate DLL, to be referenced at design-time. As soon as this DLL changes, new descriptions will be available and used in subsequent code.

Let's take our example. If I create a table in a database as follows:

table AuthorityLevel:
VAL DESCRIPTION
1 Minion
2 Worker
3 Manager

I can dynamically generate a DLL with the described enum. As soon as I change any of the DB-values, my DLL would need to be regenerated. It's easy to write a simple .exe (shown below) that gets called whenever any of these values change. This .exe will use Reflection.Emit to create and compile the DLL containing the needed enums.

The C# source for the .exe would look something like this:

using System;
using System.Collections;
using System.Threading;
using System.Reflection;
using System.Reflection.Emit;


namespace Ernst.Test
{
    public class EnumBuilder
    {
        static AssemblyBuilder myAssemblyBuilder;
        static ModuleBuilder myModuleBuilder;
        static EnumBuilder myEnumBuilder;

        public static void BuildEnum()
        {
            try
            {
                CreateEnums(Thread.GetDomain(), AssemblyBuilderAccess.Save);
                Type[] myTypeArray = myModuleBuilder.GetTypes();
                foreach(Type myType in myTypeArray)
                {
                    Console.WriteLine("Enum Builder defined in the module builder is: "
                        + myType.Name);
                }

                Console.WriteLine("Enum TypeToken is :"
                    + myEnumBuilder.TypeToken.ToString());
                Console.WriteLine("Enum UnderLyingField is :"
                    + myEnumBuilder.UnderlyingField.ToString());
                Console.WriteLine("Enum UnderLyingSystemType is :"
                    + myEnumBuilder.UnderlyingSystemType.ToString());
                Console.WriteLine("Enum GUID is :"
                    + myEnumBuilder.GUID.ToString());
                myAssemblyBuilder.Save("EmittedAssembly.dll");
            }
            catch(NotSupportedException ex)
            {
                Console.WriteLine("The following is the exception is raised: " + ex.Message);
            }
            catch(Exception e)
            {
                Console.WriteLine("The following is the exception raised: " + e.Message);
            }
        }

        private static void CreateEnums(AppDomain myAppDomain, AssemblyBuilderAccess access)
        {
            // Create a name for the assembly.
            AssemblyName myAssemblyName = new AssemblyName();
            myAssemblyName.Name = "DBEnums";
            // Create the dynamic assembly.
            myAssemblyBuilder = myAppDomain.DefineDynamicAssembly(myAssemblyName,
                AssemblyBuilderAccess.Save);
            // Create a dynamic module.
            myModuleBuilder = myAssemblyBuilder.DefineDynamicModule("DBEnums",
                "DBEnums.mod");
            // Create a dynamic Enum.
            myEnumBuilder = myModuleBuilder.DefineEnum((string)GetNameSpace(),
                TypeAttributes.Public, typeof(Int32));

            string[] Fields = GetFields();
            int index = 1;
            foreach (string field in Fields)
            {
                FieldBuilder myFieldBuilder = myEnumBuilder.DefineLiteral(field, index++);
            }

            myEnumBuilder.CreateType();
        }

        private static string GetNameSpace()
        {
            //There's obviously a better way to name your enum,
            //for instance retrieving it from your DB
            return "Ernst.Test.DBEnums";
        }

        private string[] GetFields()
        {
            //Code to connect to DB and retrieve enum-values, return as string-array
        }
    }
}

Note that the code above assumes that your enum will be of type Int32. This is easy to change by hard-coding, or even by specifying a type in your database-values. You can even decide on a type based on the datatype of the SQL column.

I have tried to foresee compatibility issues regarding this process, and will keep you posted on my findings.

Tuesday, December 02, 2003

pirates 

Avast, me hearties?!
Unbelievable how quick it happens in the wild wild east. Pirated Longorn CD's are for sale in Malaysia, for less than $2 a piece! Shiver me timbers!!!

This page is powered by Blogger. Isn't yours?