ASP.NET 2.0 - Playing with ActiveDirectory (check whether user exists, etc)
It had been a wonderful day of my programming life. I was given an assignment to look into active directory, and test out the web development authentication with it. It was really a challenging one. Just imagine I have zero active directory experiences but I am still able to cope in 2 days.
This is my scenario:
*I configured my 1st active directory and domain controller + DNS. Cool :P Now I understand a lot on OU, CN, LDAP by configuring. Never like infra stuff in the past, but I enjoyed this time.
You have an active directory in a domain controller (under this domain community.com). You have a web server which is connected to this domain. The member’s profile of the system is stored in the database. There is a column in the member’s table that consists of the active directory account. So it means that certain user has access to the active directory and some cannot. The column must be null by default. The reason why there is a profile in the database as we are working on a huge system. Within the huge system, there is already existing application utilizing the database for member’s profile. There are around 10,000 members within this private system and I don’t think it is a good idea to move to Active Directory, then ask each of the members to change password. There are more design considerations on this.
User A: PC connected to the domain
A user runs this web application; he will be auto authenticated and able to access certain resources on the site
User B: PC not connected to the domain
A user runs this web application. He will be prompted to enter username, domain and password to authenticate. If fail, will get a 401.1 error.
Looks simple right.
So at first, when I heard it was related to ActiveDirectory I tried to look into System.DirectoryServices and ActiveDirectoryMembershipProvider. Trust me that it might looks very easy from the outside, but it was not a simple task to work on the API. You need to understand ActiveDirectory and LDAP first before taking this adventure ride. It was really a pain to me working on this.
I tried a number of ways:
a) To force to use System.DirectoryServices, in the directory security I assign the process to be a domain user or admin account. By doing this, all your web application has the access to this specific account, which sounds kind of stupid. Coz I will have so many members and each of them must be authenticated by itself.
Mission Failed.
b) I try to look into ActiveDirectoryMembershipProvider. Looks cool. You have to store a specific user account inside the web.config itself which did not make any sense to me. Just like point a. Try not to place a domain admin account inside here. You need to specify the account name and password.
Mission Failed.
c) How about doing some impersonation? Then get the logon user name by “Environment.UserName” or “System.Web.HttpContext.Current.User.Identity.Name”. Then pass this windows logon id for DirectoryEntry + DirectorySearch query. Sigh … it does not work. But if you do it manually, you will work. Kind of tough to explain on this one. You must set impersonation here or else you will not get accurate information. Furthermore, maybe I did a badly job on my DirectorySearch query. Oops L
d) Then I thought it could be authorization issues. But thinking twice, it should not be.
Life moves on and on… still not able to solve it. Suddenly something hit my mind :D
Anyway you will be surprised that I do not use any codes that involve System.DirectoryServices or ActiveDirectoryMembershipProvider on this one. I did not use the LogonUser API as well. So how did I solve this problem?
The answer is there is a solution for everything. When someone is being assigned a task, try to think if there is a simpler way of doing thing. Learn a lot this time.
With this implementation, I do not need to configure anything in the IIS, which is the best part. So anonymous user will be prompted to login. Hehe :D
if (!Page.IsPostBack)
{
string test = System.Web.HttpContext.Current.Request.ServerVariables["LOGON_USER"].ToString();
if (System.Web.HttpContext.Current.Request.ServerVariables["LOGON_USER"] == "")
{
System.Web.HttpContext.Current.Response.StatusCode = 401;
System.Web.HttpContext.Current.Response.End();
}
else
{
// Request.ServerVariables["LOGON_USER"] has a valid domain user now!
string changeDomainName = (Environment.UserDomainName).Substring(0, Environment.UserDomainName.Length - 1) + ".com";
string account = Environment.UserName + "@" + changeDomainName;
enObj.sADAccount = account;
Response.Write(brObj.GetFullName(enObj));
}
}
The rule is simple here. If you are authenticated, you will query the database and get the full name of the member’s profile. If not, you will be prompted login screen (max 3 times). If failed, then you will get “you are not authorized error”. If you manage to login, you still can get the full name. Sound easy right J
Anyway the term to find here is single sign on. I never thought of that till 5 minutes ago – 10.55 p.m.