asp tutorials, asp.net tutorials, sample code, and Microsoft news from 15Seconds
Data Access  |   Troubleshooting  |   Security  |   Performance  |   ADSI  |   Upload  |   Email  |   Control Building  |   Component Building  |   Forms  |   XML  |   Web Services  |   ASP.NET  |   .NET Features  |   .NET 2.0  |   App Development  |   App Architecture  |   IIS  |   Wireless
 
Pioneering Active Server
 Power Search





Active News
15 Seconds Weekly Newsletter
• Complete Coverage
• Site Updates
• Upcoming Features

More Free Newsletters
Reference
News
Articles
Archive
Writers
Code Samples
Components
Tools
FAQ
Feedback
Books
Links
DL Archives
Community
Messageboard
List Servers
Mailing List
WebHosts
Consultants
Tech Jobs
15 Seconds
Home
Site Map
Press
Legal
Privacy Policy
internet.commerce














internet.com
IT
Developer
Internet News
Small Business
Personal Technology
International

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers

HardwareCentral
Compare products, prices, and stores at Hardware Central!

Implementing Active Directory Services in ASP.NET 2.0
By Peter Nichols
Rating: 4.1 out of 5
Rate this article


  • email this article to a colleague
  • suggest an article


    The advent of ASP.NET 2.0 and Visual Studio 2005 Express has kicked the door wide open for creating integrated applications. Many of the security tasks required for an applications authentication and authorization mechanisms to be hooked into Active Directory have been dramatically simplified.

    The information below will provide a "cookbook" of recipes to perform both Active Directory integration tasks (using the "LDAP:\\" provider) as well as local member server tasks (using the "WinNT:\\" provider). Each section can be cut and pasted directly into its own aspx.vb code page, and is self sufficient. Remember that you must use challenge response for any of this code to work, so that AD or the local member server has the correct permissions to perform the action. Setting the encryption level and other such communication details between the member server running the code and the directory service domain controller is beyond the scope of this article.

    Although Microsoft provides a deep mechanism for providing security into an application, your business model may not allow independent authentication and or authorization stores. All of these examples were created because a customer did not want to create extranet Sharepoint users in Active Directory (AD mode), so the local machine was the next best alternative.

    Verify That a User is in a Active Directory Group

    The first recipe is to verify a user that has connected to an ASP.NET 2.0 page is in an Active Directory group. Add a new item (Web Form) to your site, called "Test.aspx", placing the code in a separate file. Go to design mode, and double click on the page, which should give you a blank Page_Load subroutine. Paste this code directly over the existing code:

    Imports System.DirectoryServices
    Partial Class Test
        Inherits System.Web.UI.Page

        Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim strUser As String
            Dim binFlag As Boolean

            REM This is equivalent to adsRoot=GetObject("LDAP://OU=ADSI,DC=ds,DC=microsoft,DC=com")
            REM and opens a connection to the root of the directory that you
            REM would want to search. Replace the string with your directory service root.
            Dim adsRoot As New DirectoryEntry("LDAP://OU=ADSI,DC=ent,DC=ds,DC=microsoft,DC=com")

            REM This sets up the filter to be used in searching for the user in AD.
            Dim adsSearch As DirectorySearcher = New DirectorySearcher(adsRoot)

            REM Grab the User ID of the person pulling the page, or the sAMAccountName
            strUser = Page.User.Identity.Name

            REM Strip off domain name (we already know it, although in multi-domain
            REM environments you might find that useful.
            strUser = Mid(strUser, InStr(1, strUser, "\") + 1)

            REM Search Active Directory For the user via
            REM System.DirectoryServices.DirectorySearcher
            Try
                REM We'll load the filter with the items we want to fetch,
                REM similar to a SQL statement.
                REM The first is what we are looking for, the sAMAccountName.
                adsSearch.PropertiesToLoad.Add("sAMAccountName")
                REM We will also need the group membership of the user once
                REM we have found the user.
                adsSearch.PropertiesToLoad.Add("memberof")
                REM We are likely to also need the common name, although
                REM it's not needed for this example.
                adsSearch.PropertiesToLoad.Add("cn")
                REM We don't need the .FullName property for this example,
                REM but you might, so I show it here.
                adsSearch.PropertiesToLoad.Add("FullName")
                REM build the search filter (looking for the user with a login
                REM name that matches who connected to the page.
                adsSearch.Filter = "sAMAccountName=" & strUser

                REM Get some variables ready to receive the results
                Dim oResult As SearchResult
                Dim RetArray As New Hashtable()
                Dim adsGrpcn As String
                binFlag = False

                REM Now get the results (just one), what you get back is
                REM an object that points to the found user
                oResult = adsSearch.FindOne
                REM You can now loop through the list of groups
                For Each adsGrpcn In oResult.GetDirectoryEntry().Properties("memberof").Value
                    REM You'll want to splice this string a bit to match a specific group
                    REM Then test to see if it matches your application group. Make sure to
                    REM use TRIM() to avoid embedded spaces in the common name of the group.
                    Response.Write(adsGrpcn)
                    If adsGrpcn = "MyGroup" Then binFlag = True
                Next
            Catch ex As Exception
                Response.Write("I got the following error while trying to authenticate you: " _                 & ex.Message)
                Response.End()
            End Try
            If binFlag Then
                Response.Write("You are authorized!")
            Else
                Response.Write("You are not authorized!")
            End If
        End Sub
    End Class

    List All Users

    This recipe is for iterating all users on a local machine, which can then populate a list box. This would also likely find its way to the "Page_Load" sub, but is shown separately. It presumes a list control called 'lstUser' is on the page. It will populate the list showing the Full Name, but have the User ID as the value.

    Dim lblDMBase As String
    lblDMBase = "WinNT://LocalMachine"
    REM This is equivalent to adsUser=GetObject("WinNT://LocalMachine/User") and
    REM opens a connection to the local machine. It does not necessarily need to be
    REM the machine the web page is running on.
    Dim adsComputer As New DirectoryEntry(lblDMBase)
    Dim adsUser As DirectoryEntry
    REM This works identically to classic asp, iterate through the parent object.
    For Each adsUser In adsComputer.Children
        REM If it is a user, then add it to the list box.
        If adsUser.SchemaClassName = "User" Then
            lstUser.Items.Add(New ListItem(adsUser.Properties("FullName").Value, adsUser.Name))
        End If
    Next

    Create a New User

    The next recipe is for creating a user on the local machine, easily tested by dropping a button on the previous page and double clicking on it. Remember that the user running the page has to have the permissions create a user (be in the local Administrators group).

    Dim lblDMBase As String
    lblDMBase = "WinNT://LocalMachine"
    REM This is equivalent to adsUser=GetObject("WinNT://LocalMachine/User") and
    REM opens a connection to the local machine. It does not necessarily need to be
    REM the machine the web page is running on.
    Dim adsComputer As New DirectoryEntry(lblDMBase)
    Dim adsUser As DirectoryEntry
    REM Open a connection to the Group
    Dim adsGroup As New DirectoryEntry(lblDMBase & "/Users")
    REM You can also open the object by:
    'Dim adsGroup As DirectoryEntry
    'adsGroup.Path = lblDMBase & "/Users"
    Try
        REM Add a user to the defined computer object
        adsUser = adsComputer.Children.Add("TestUser", "User")
        REM Populate the FullName and Description Properties
        adsUser.Properties("FullName").Add("Test Full Name")
        adsUser.Properties("Description").Add("Test Description")
        REM Set the password (a random password function would be good here).
        adsUser.Invoke("SetPassword", "password")
        REM Identical to .SetInfo
        adsUser.CommitChanges()

        REM Add the User to the Group
        adsGroup.Invoke("Add", New Object() {adsUser.Path.ToString()})
        adsGroup.CommitChanges()
        Response.Write("TestUser created.")
    Catch ex As Exception
        Response.Write("Error in Create User: " & ex.Message)
    End Try

    View a User's Attributes

    The next recipe is to view attributes of a local user. This example builds upon the previous example by using the user selected in the previous examples list box. Create a "View User" button on the form, double click on the button, and add this code into the sub:

    Dim lblDMBase As String
    lblDMBase = "WinNT://LocalMachine"
    Dim strProp As String
    Dim binIL As Boolean

    REM This is equivalent to adsUser=GetObject("WinNT://LocalMachine/User") and
    REM opens a connection to the local machine. It does not necessarily need to be
    REM the machine the web page is running on.
    Try
        Dim adsUser As New DirectoryEntry(lblDMBase & "/" & lstUser.SelectedItem.Value)
        strProp = adsUser.Name & " (" & adsUser.Properties("FullName").Value & "), "
        Response.Write(strProp & adsUser.Properties("Description").Value)
        binIL = adsUser.InvokeGet("IsAccountLocked")
        If binIL Then
            strProp = "Account is Locked."
        Else
            strProp = "Account is not Locked."
        End If
        strProp = strProp & " Last Login: " & adsUser.InvokeGet("LastLogin")
    Catch ex As Exception
        strProp = strProp & " Last Login N/A"
    End Try
    Response.Write(strProp)

    Check for a User in a Local Group

    Simple check for a user in a local group, it presumes you've added the user iteration code above and created another button:

    Dim lblDMBase As String
    REM The object opened here is a local group, but could be an AD Group or OU
    lblDMBase = "WinNT://LocalMachine"
    REM This is equivalent to adsUser=GetObject("WinNT://LocalMachine/User") and
    REM opens a connection to the local machine. It does not necessarily need to be
    REM the machine the web page is running on.
    Dim adsUser As New DirectoryEntry(lblDMBase & "/" & lstUser.SelectedItem.Value)
    REM This is equivalent to adsUser=GetObject("WinNT://LocalMachine/Group")
    Dim adsGroup As New DirectoryEntry(lblDMBase & "/Administrators")
    If adsGroup.Invoke("IsMember", adsUser.Name.ToString()) Then
        Response.Write "You're a Member!"
    Else
        Response.Write "You're a not a Member!"
    End If

    Iterate All Computers in a Container

    This next recipe is more for auditing. It iterates all the computers in a container and then connects to the local administrator of that server to get the account policy.

    Dim adsRoot As New DirectoryEntry("LDAP://OU=ADSI,DC=ent,DC=ds,DC=microsoft,DC=com")
    Dim adsUser, adsComputer As DirectoryEntry
    Dim strCompName As String
    Dim ocnt As Integer

    For Each adsComputer In adsRoot.Children
        If adsComputer.SchemaClassName = "computer" Then
            strCompName = Mid(adsComputer.Name, 4)
            Response.Write(strCompName & " (")
            Response.Write(adsComputer.Properties("OperatingSystemVersion").Value & "): ")
            ocnt = ocnt + 1
            Try
                adsUser = New DirectoryEntry("WinNT://"&Trim(strCompName)&"/Administrator")
                Response.Write(adsUser.Properties("MaxPasswordAge").Value / 86400 & ", ")
                Response.Write(adsUser.Properties("MinPasswordLength").Value & ", ")
                Response.Write(adsUser.Properties("PasswordHistoryLength").Value & ", ")
                Response.Write(adsUser.Properties("MaxBadPasswordsAllowed").Value & ", ")
                Response.Write(adsUser.Properties("AutoUnlockInterval").Value & ", ")
                Response.Write(adsUser.Properties("LockOutObservationInterval").Value & ", ")
            Catch ex As Exception
                Response.Write(ex.Message & "<br>")
            End Try
            Response.Write("<br>")
        End If
    Next
    Response.Write(ocnt & " Servers Flagged.")

    Properties

    There are lots of properties you can pull from the local (WinNT) user account some must be read or written via ".Properties":

    UserFlags HomeDirectory MaxPasswordAge
    MaxStorage LoginScript MinPasswordAge
    PasswordAge Profile PasswordHistoryLength
    PasswordExpired HomeDirDrive AutoUnlockInterval
    LoginHours Parameters LockoutObservationInterval
    FullName PrimaryGroupID MaxBadPasswordsAllowed
    Description Name RasPermissions
    BadPasswordAttempts MinPasswordLength objectSid

    These local (WinNT) or AD (LDAP) user attributes that are "computed" and so must be obtained by "InvokeGet" or written by "InvokeSet":

    SetPassword
    AccountDisabled
    AccountExpirationDate
    IsAccountLocked
    LastLogin

    These are some of the AD (LDAP) user attributes readable via ".Properties". If they are not mandatory, get the property with a "Try".

    Attribute Description/Comments Mandatory
    memberOf Returns a string array of group membership. Yes
    cn The common name, make sure to have a search of samAccountName return this attribute in case you need to rebind to the user object. Yes
    department,
    description,
    division,
    employeeID,
    givenName,
    telephoneNumber,
    facsimileTelephoneNumber,
    postalAddress,
    postalCode,
    homePhone,
    mobile,
    title
    Returns a string containing user information. If the field in the account has never been populated, the code will return an error. No
    displayName FullName No
    lockoutTime IsAccountLocked but returns a date/time. For the flag, use '.InvokeGet("IsAccountLocked")'. No
    lastLogoff Returns a date indicating the last time the user logged off. Although this attribute would appear mandatory, a freshly created user will not have this. No
    lastLogon Returns a date indicating the last time the user logged on (which is NOT when then authenticated to a web page). No
    mail Returns the string containing the user's email address.  
    objectClass For users will always return the string "User". Handy for filtering by object type. Yes
    sAMAccountName Returns the login name, which will match what you get when challenging for credentials on a web page. Yes
    userAccountControl Returns flags that control the behavior of the user account. You're much better off using the "invoke" commands to get info here. Yes
    whenChanged Returns a date for the last time the object was modified. Yes
    whenCreated Returns a date for when the object was created. Yes

    These are the local (WinNT) group attributes readable via ".Properties":

    groupType
    Name
    Description
    objectSid

    These are the AD (LDAP) group attributes readable via ".Properties":

    member distinguishedName sAMAccountType
    cn objectCategory sIDHistory
    description objectClass uSNChanged
    dSCorePropagationData objectGUID uSNCreated
    groupType objectSid whenChanged
    instanceType name whenCreated
    nTSecurityDescriptor sAMAccountName

    These are the AD (LDAP) OU attributes readable via ".Properties":

    dSCorePropagationData objectClass uSNCreated
    instanceType objectGUID whenChanged
    nTSecurityDescriptor ou whenCreated
    distinguishedName name
    objectCategory uSNChanged

    References

    Mapping Between IADsUser Properties and Active Directory Attributes:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/ldap/ldap/ldap.asp

    DirectoryServices Namespace:
    http://msdn.microsoft.com/library/default.asp?url=/library/en-us/sds/sds/directoryservices_namespace.asp

    Querying Active Directory using .NET classes and LDAP queries:
    http://www.codeproject.com/dotnet/activedirquery.asp?df=100&forumid=15636&exp=0&select=847485

  • Rate This Article
    Not HelpfulMost Helpful
    1 2 3 4 5
    Other Articles
    Jul 21, 2005 - N-Tier Web Applications using ASP.NET 2.0 and SQL Server 2005 - Part 1
    While the .NET Framework made building ASP.NET applications easier then it had ever been in the past, .NET 2.0 builds on that foundation in order to take things to the next level. This article shows you to how to construct an N-Tier ASP.NET 2.0 Web application by leveraging the new features of ASP.NET 2.0 and SQL Server 2005.
    [Read This Article]  [Top]
    Apr 28, 2005 - New Files and Folders in ASP.NET 2.0
    With the release of ASP.NET 2.0, Microsoft has greatly increased the power of ASP.NET by introducing a suite of new features and functionalities. As part of this release, ASP.NET 2.0 also comes with a host of new special files and folders that are meant to be used to implement a specific functionality. This article examines these new files and folders in detail and provides examples that demonstrate how to utilize them to create ASP.NET 2.0 applications.
    [Read This Article]  [Top]
    Mar 10, 2005 - The DataSet Grows Up in ADO.NET 2.0 - Part 2, Cont'd
    Alex Homer continues his detailed look at the major changes to the DataSet class. In this part, he looks at two features that allow developers to work with data in a more structured and efficient way when using the DataSet with a SQL Server 2005 database server.
    [Read This Article]  [Top]
    Mar 9, 2005 - The DataSet Grows Up in ADO.NET 2.0 - Part 2
    Alex Homer continues his detailed look at the major changes to the DataSet class. In this part, he looks at two features that allow developers to work with data in a more structured and efficient way when using the DataSet with a SQL Server 2005 database server.
    [Read This Article]  [Top]
    Mar 3, 2005 - The DataSet Grows Up in ADO.NET 2.0 - Part 1, Cont'd
    In this article, Alex Homer looks at the changes between the version 1.x and version 2.0 DataSet and their associated classes, showing you how you can take advantage of the new features to improve your applications' capabilities and performance.
    [Read This Article]  [Top]
    Mar 2, 2005 - The DataSet Grows Up in ADO.NET 2.0 - Part 1
    In this article, Alex Homer looks at the changes between the version 1.x and version 2.0 DataSet and their associated classes, showing you how you can take advantage of the new features to improve your applications' capabilities and performance.
    [Read This Article]  [Top]
    Feb 16, 2005 - Writing a Custom Membership Provider for the Login Control in ASP.NET 2.0
    In ASP.NET 2.0 and Visual Studio 2005, you can quickly program custom authentication pages with the provided Membership Login controls. In this article, Dina Fleet Berry examines the steps involved in using the Login control with a custom SQL Server membership database.
    [Read This Article]  [Top]
    Dec 29, 2004 - ClickOnce Deployment in .NET Framework 2.0
    In this article, Thiru Thangarathinam examines .NET 2.0's new ClickOnce deployment technology that is designed to ease deployment of Windows forms applications. This new technology not only provides an easy application installation mechanism, it also eases deployment of upgrades to existing applications.
    [Read This Article]  [Top]
    Dec 15, 2004 - A Sneak Peek at ASP.NET 2.0's Administrative Tools
    With ASP.NET 2.0, Microsoft has made great strides in increasing developer productivity and has made implementing previously complex solutions relatively easy. Where this version of ASP.NET really shines, however, is in its new administrative tools that allow developers to spend less time managing the configuration of the servers and software and more time developing great code.
    [Read This Article]  [Top]
    Nov 17, 2004 - The ASP.NET 2.0 TreeView Control
    Thiru Thangarathinam introduces ASP.NET 2.0's new TreeView control which provides a seamless way to consume and display information from hierarchical data sources. The article discusses this new control in depth and explains how to use this feature rich control in your ASP.NET applications.
    [Read This Article]  [Top]
    Mailing List
    Want to receive email when the next article is published? Just Click Here to sign up.

    Support the Active Server Industry

    internet.comearthweb.comDevx.commediabistro.comGraphics.com

    Search:

    Jupitermedia Corporation has two divisions: Jupiterimages and JupiterOnlineMedia

    Jupitermedia Corporate Info

    Legal Notices, Licensing, Reprints, Permissions, Privacy Policy.
    Advertise | Newsletters | Tech Jobs | Shopping | E-mail Offers