Programmer to ProgrammerTM | |||||
|
|
|
|
|
|
|
|
|
|
|
| |||||||||||||||||||
The ASPToday
Article March 7, 2001 |
Previous
article - March 6, 2001 |
||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||
ABSTRACT |
| ||||||||||||||||||||||||||||||
| |||||||||||||||||||||||||||||||
Article Discussion | Rate this article | Related Links | Index Entries | ||||||||
ARTICLE |
In my last article for ASPToday you read about Using ADSI, NT Groups and IIS Authentication. This article focused primarily on Windows NT and IIS 4. Since then, I have had several questions about errors using GetObject and about how to apply my previous article to Windows 2000 and IIS 5. This article answers these questions and explains the differences between Windows NT and 2000 using this approach for authentication and user management.
The most popular question asked is
"I get an error when calling this code - Set objUser = GetObject("WinNT://" & strUserID) Why?"
Usually the solution for this problem is installing ADSI 2.5. The first important difference between using ADSI on Windows NT and Windows 2000 is that ADSI is not installed when Windows NT is loaded. ADSI had to be downloaded from the Microsoft website and installed on Windows NT, whereas with Windows 2000, ADSI 2.6 is already installed with the Operating Systems.
If ADSI was installed on a Windows NT box, the other problem was the ADSI path passed to GetObject. When using ADSI, the path is referred to as ADsPath. Using ADSI on Windows NT or 2000, you must understand ADsPath. Just as a file has a fully qualified path in the file system, objects like a user or a group have a string representation of their exact path in the directory hierarchy, hence ADsPath.
The ADsPath syntax is:
ADSI Provider://Namespace
The provider name is the initial elements of the ADsPath. The provider name is the ProgID (Programmatic Identifier) of the ADSI Provider. The ProgID section of the syntax is case sensitive. The Windows NT directory service ProgID is WinNT. Other ProgIDs are LDAP for Lightweight Directory Access Protocol and NDS for Novell Directory Service. A complete list of ProgIDs and Provider Names (along with a lot more information) can be found on the Microsoft website at:
The :// is just a separator between the Provider and Namespace in the ADsPath.
The Namespace refers to a directory service that has a specific syntax for access. The namespace is a string in that syntax. For example, if the ProgID is WinNT, then a valid namespace would be MyServer/MyUserName. Each ADSI provider has a different syntax for accessing its directory service.
Here are some examples of ADsPaths:
WinNT://MyDomain/SomeUserName WinNT://MyServer/MyUserName LDAP://MyServer:Port/o=OrgName
If you want to setup the project and code as you read the article, please follow these steps:
There are many differences between setting up users, groups, directory security and IIS authentication on Windows NT and 2000. This section explains how to create users to IIS authentication on Windows 2000. Please see my previous article for instructions on how to do this in Windows NT.
For the sample code, you need at least two users. The two users I will be using are cschmidt and the NewUser, which I just created.
The sample code below uses two groups: UserGroup and AdminGroup. The UserGroup has one member: NewUser while the AdminGroup has Administrator as a member. During the development phase, you will want to be a member of both groups so Visual Interdev can access and update the website.
Now we need to configure the NTFS permissions for our ADSIProject. Bear in mind that for this to work, your hard drive needs to be formatted to NTFS, not FAT32. This will be an obvious point to most of you, but one that some may overlook, which is why I have included it. Follow the steps below:
What did you just do? Great Question. You changed the Access Control Entries (ACEs) for the Access Control Lists (ACLs) on each directory to only allow the Groups to access the proper resources. Note: ACLs are only used on NTFS drives. If your drive is FAT, you must convert it to NTFS in order to take advantage of Groups restricting access in the File System.
Next, setting up the IIS authentication:
Basic Authentication works the same as IIS 4.0. For your Netscape users, their usernames and passwords are sent in clear text, so you have to add SSL. For your IE users, Internet Explorer authenticates using Integrated Windows Authentication. This is similar to NTLM in IIS 4.0. You do not need SSL for your IE. Also note that you remove Anonymous Authentication because in this example, we do not want anonymous logins to the web site.
Now it's time to start coding.
Let's start with index.asp. When the user attempts to access this page, IIS takes over and the user is challenged for his username and password. Once the user successfully logs in, the login.asp code is executed. The following is the code for the login.asp:
If (Session("isValidLogin") <> True) Then Dim userObj Dim userGroupsObj Session("isValidLogin") = False If (InStr(1, Request.ServerVariables("AUTH_USER"), "\") > 0) Then ' The Domain was passed in with the user name Session("AUTH_USER") = Replace(Request.ServerVariables("AUTH_USER"), "\", "/") Session("SERVER_NAME") = Left(Session("AUTH_USER"), 10) strADsPath = "WinNT://" & Session("AUTH_USER") Else ' This is a local user Session("AUTH_USER") = Request.ServerVariables("AUTH_USER") Session("SERVER_NAME") = "yosemite" 'Replace with your server strADsPath = "WinNT://" & Session("SERVER_NAME") & "/" & Session("AUTH_USER") End If Set userObj = GetObject(strADsPath) Session("FullName") = userObj.FullName Set userGroupsObj = userObj.Groups() For Each Group In userGroupsObj Select case Group.Name case "UserGroup": Session("isUserGroup") = True Session("isValidLogin") = True case "AdminGroup": Session("isAdminGroup") = True Session("isValidLogin") = True End Select Next Set userObj = Nothing Set userGroupsObj = Nothing End If If (Session("isValidLogin") = False) Then Response.Redirect("invalidlogin.asp") End If
First login.asp checks to see if the isValidLogin session variable is not set to true. If it does not equal true, then this is the first time login.asp has been called in this session.
Since the user is authenticated, the script retrieves the user name and sets up the ADs path to get the user info. Calling the GetObject function in this case returns the ADSI user object (IADsUser).
Next, the Groups() method is called, which returns the collection of groups (IADsGroups). Since all ADSI objects require the IADs interface, we have access to the name of each group in the collection. Now, we can loop through the collection, setting our session variables appropriately. The user is now logged on.
Just in case you were wondering, the solution presented is Netscape 4.51 and IE 4/5 compliant. For Netscape and IE, users can login using this syntax: Domain\UserName. IE 4.0 and 5.0 can be configured to automatically log in on Intranet zones. Although the user never sees an authentication dialog box, IE is passing the authentication information. To force the authentication dialog box to popup, only allow Basic Authentication for IIS. When doing so, users must login with Domain\UserName for the user name. This way the proper syntax can be retrieved when calling Request.ServerVariables("AUTH_USER"). If the user does not login this way, only the username is passed to the AUTH_USER server variables, thus the Groups() method fails in the UserGroups() function. In order to get around this error on a web site where users are local to the web server and belong to various domains, you use the following code (already found in login.asp):
If (InStr(1, Request.ServerVariables("AUTH_USER"), "\") > 0) Then ' The Domain was passed in with the user name Session("AUTH_USER") "/") = Replace(Request.ServerVariables("AUTH_USER"), "\", "/") Session("SERVER_NAME") = Left(Session("AUTH_USER"), 10) strADsPath = "WinNT://" & Session("AUTH_USER") Else ' This is a local user Session("AUTH_USER") = Request.ServerVariables("AUTH_USER") Session("SERVER_NAME") = "yosemite" 'Replace with your server strADsPath = "WinNT://" & Session("SERVER_NAME") & "/" & Session("AUTH_USER") End If
This code checks to see if a backslash exists in the AUTH_USER server variable. If it does then the domain was included in the AUTH_USER server variable. This means we just need to replace the back slash with a forward slash. We can also extract the server out of the AUTH_USER variable for later use. If a backslash does not exist in the AUTH_USER variable, then the user is a local user so the web server and the ADsPath is created by concatenating WinNT:// with SERVER_NAME and AUTH_USER.
Now, since login.asp assigns the full name of the user according to the SAM to a session variable and sets up the session variables isUserGroup and isAdminGroup, we can manipulate a users experience on the website.
Here is one way to manipulate the user experience. This is code from index.asp.
<%If (Session("isUserGroup")) Then %> <A href="User/FormA.asp">Form A</A> <%End If%>
Here is what the user NewUser would see after index.asp is called.
Remember to go into ISM, then get up properties for ADSIProject, then go to the Documents tab and add Index.asp as a default document if you wish to reach it using equivalent to the above URL.
Why did I choose to use Session Variable? Why not use ADSI to query each time the user has to access a restricted area? The answer: Performance. Using ADSI to query for the user info each time hurts performance, especially on large domains. The disadvantage of using the session variables is that the session times out.
How do you handle this? Since the Authentication is still valid, we just need to call login.asp to recreate the session variables. Login.asp checks to see if the session variable isValidLogin is not equal to true. If that's the case then the session variables need to be recreated.
In order to recreate the session variable when the session times out, just add this code to the beginning of each ASP file.
<!-- #include Virtual="/ADSIProject/login.asp" -->
The best part of ADSI is being able to create a simple web interface for user management. Once this site is in production mode, your support division can take over requests from users. Your support division can add or remove users and filter problems to the developers and/or system administrators as needed so your time is freed up to start the next app on your to do list.
In the case of small IT teams that do not have a support division, you could train secretaries or administrative assistants to add/remove users. Most of the companies that my colleagues and I have worked for are starting to take advantage of these secretaries and administrative assistants to help the IT Staff, who, as many companies are hoping (in the long run, after testing the waters), can be trained as full IT Staff.
Back to ADSI - let's display the users that belong to the UserGroup group. This code is located in the usermngt.asp file.
strPath = "WinNT://" & strServer & "/UserGroup" Set objGroup = GetObject(strPath) strHTML = "<SELECT size=10 multiple id=UserGroup name=UserGroup>" For Each objUserInfo In objGroup.Members strHTML = strHTML & "" & Mid(objUserInfo.Parent, 9) & "/" & objUserInfo.Name & "" Next strHTML = strHTML & </SELECT> Set objGroup = Nothing Response.Write(strHTML)
This is fairly simple. First, call the GetObject Function with an ADs path to the local Group. An IADsGroup object is returned which contains a collection of members (a member can be a user or another group). Then, loop though that collection, displaying the members.
To add a user, we need to display a list of users to choose from. Take a look at AddUser.asp:
strPath = "WinNT://" & strServer & "/" & strGroup strDomain = Request.Form("Domain") Set objGroup = GetObject(strPath) For Each Item In Request.Form(Request.Form("Domain"))Request.Form(strDomain) If (NOT(objGroup.IsMember("WinNT://" & strDomain & "/" & Item))) Then objGroup.Add "WinNT://" & strDomain & "/" & Item End If Next Set objGroup = Nothing
This code is very similar to displaying users of a Group except we change the AdsPath to a domain path. In this code, I use a filter to only retrieve the users. You could also retrieve the groups in the Domain, after which you could also add groups to the group.
Here is the code to actually add a user to the group:
strPath = "WinNT://" & strServer & "/" & strGroup Set objGroup = GetObject(strPath) For Each Item In Request.Form(strGroup) objGroup.Remove "WinNT://" & Item Next Set objGroup = Nothing
Once you have all of your user management code working using VBScript, it is important to move your code into a COM+ object. Since your code is already in VBScript, it's easiest to write your COM+ object as an ActiveX DLL written in Visual Basic. The reason you want to do this is because a COM+ object can be executed under the administrator for the domain. The AdminGroup can then be given access to the COM+ object. If you do not do this, then anyone assigned to the user management of the web app must also be an administrator for the domain.
Other great things that you could do:
Using ADSI, Windows 2000, SQL Server 2000 and IIS 5 will help with administration of your web apps as well as how the web app is presented to users with different permissions.
|
| |||||||
|
| |||||||||||||||
|
ASPToday is brought to you by
Wrox Press (http://www.wrox.com/). Please see our terms
and conditions and privacy
policy. ASPToday is optimised for Microsoft Internet Explorer 5 browsers. Please report any website problems to [email protected]. Copyright © 2001 Wrox Press. All Rights Reserved. |