Tuesday, December 1, 2009

Active Directory Using VB.NET

This article discusses working within the Active Directory (AD) using VB.NET, how to query the AD, How to authenticate the user, how to retrieve the user details using Domain User ID, how to retrieve the user details using domain e-mail id etc

The Active Directory is the Windows directory service that provides a unified view of the entire network. Working with the Active Directory is a lot like working with a database, you write queries based on the information you want to retrieve.

Recently, at work, I was tasked with creating a single signon for the application I am currently programming to allow the user to use the application without entering the userid and password details; Also I had to ensure that in the event the application was ever taken off-site, that it couldn't run; This would prevent an individual from taking the application off-site and attempting to use it.

Then I thought of using the Active Directory of the company network to achieve the Single Signon as well as Security.

Active directory seemed to be the most secure way as only a select group of people actually have the permissions to alter the Active Directory in any way.

I built the logic using the System.DirectoryServices namespace.

System.DirectoryServices: The System.DirectoryServices namespace built into the .NET Framework is designed to provide programming access to LDAP directories (Active Directory).

To start querying Active Directory from your VB.NET code, you simply add a reference to the System.DirectoryServices.dll in your project and the following Imports statement to your code:


Imports
System.DirectoryServices

When the application is launched, it will check the name the user was logged in as:

Environment.UserName.ToString. It will return the user name in the format: DOMAIN\USERNAME

After getting the user name the application will query the Active Directory to ensure this is a valid network account and they have permissions to be using this application.

The first thing to do when working with the Active Directory is to create a connection to the Active Directory:

dirEntry = New System.DirectoryServices.DirectoryEntry("LDAP://" & DOMAIN_NAME)

You can replace the path with the one specific to your network.

The next thing to search for the provided user to ensure that the login provided is a valid one.

dirSearcher = New

System.DirectoryServices.DirectorySearcher(dirEntry)

dirSearcher.Filter = "(samAccountName=" & m_LoginName & ")"

Dim sr As SearchResult = dirSearcher.FindOne()

If sr Is Nothing Then 'return false if user isn't found
lblStatus.Text = "User authentication failed"
Return False
End If

The condition used here to Search for an entry for the logged in user. The "samAccountName" is the name of the field used to store Domain User ID.

If the user does not exist in the Active Directory, the result will be nothing.

The .FindOne() method will be used to stop searching as soon as the match is found.

 

Sample Code 1:

The IsLogonValid is used to validate the logged in user. It will search for the provided user in the Active Directory. The function will return true or false depending if the login provided is a valid one. With this function, if the selected user is found, and then True is returned, else False is returned, letting the programmer know that this isn't a valid user in the Active Directory.

Private m_ServerName As String
Private m_LoginName As String

Private m_Authenicate As String

Public Sub New()
' This call is required by the Windows Form Designer.
InitializeComponent() 

' Add any initialization after the InitializeComponent() call.
m_ServerName = DOMAIN_NAME ' Your Domain Name
m_LoginName = Environment.UserName.ToString
m_Authenicate = My.User.Name 
End Sub 
 

Public Function IsLogonValid() As Boolean

Dim m_LoginName As String
Dim dirEntry As System.DirectoryServices.DirectoryEntry

Dim dirSearcher As System.DirectoryServices.DirectorySearcher

lblStatus.Text = "Validating User Account" 

Try 
m_LoginName = Environment.UserName.ToString 'The logged in user ID
dirEntry = New System.DirectoryServices.DirectoryEntry("LDAP://" & DOMAIN_NAME) 
dirSearcher = New System.DirectoryServices.DirectorySearcher(dirEntry) 
dirSearcher.Filter = "(samAccountName=" & m_LoginName & ")"

       'Use the .FindOne() Method to stop as soon as a match is found

Dim sr As SearchResult = dirSearcher.FindOne() 

If sr Is Nothing Then 'return false if user isn't found
lblStatus.Text = "User authentication failed"
Return False
End If

Dim de As System.DirectoryServices.DirectoryEntry = sr.GetDirectoryEntry()

sUserName = de.Properties("GivenName").Value.ToString()
 

lblStatus.Text = "User authentication success"


Return True  'Valid user


Catch ex As Exception ' return false if exception occurs

lblStatus.Text = "User authentication failed"


Return False


End Try


End Function


 

Sample Code 2:

The DisplayActiveDirUserDetails function is used to retrieve the FirstName, Last Name and e-mail adddress of the logged in user.

The PropertiesToLoad property of the DirectorySearcher object is a collection containing attribute names of AD objects that we want the query to return. By analogy with SQL query, the Filter property serves as the WHERE clause and the PropertiesToLoad property works as a list of column names that the query will return.

To retrieve specific properties, we need add them to the Collection before we begin the search. For example, searcher.ProperiesToLoad("GivenName") will add the GivenName property to the list of properties to retrieve in the search.

Some of the directory entry properties are

  • SAMAccountName – Users Login Name
  • Mail –E-Mail
  • Sn – SurName or Last Name
  • GivenName – First Name
  • Title – User Title
  • Phone – User telephone number
  • Department – User's Department etc.
  • Mobile – Mobile Phone number
  • City – User's City


 

In this example I have retrieved only FirstName, LastName and e-mail address.


 

Basically, this is a good practice to limit the amount of returning properties as much as you can. It can reduce execution time of the query significantly.


 

Private Function DisplayActiveDirUserDetails(ByVal USERID As
String) As Boolean


Dim dirEntry As System.DirectoryServices.DirectoryEntry


Dim dirSearcher As System.DirectoryServices.DirectorySearcher

lblStatus.Text = "Validating User Account"

Try dirEntry = New System.DirectoryServices.DirectoryEntry("LDAP://" & DOMAIN_NAME)

dirSearcher = New System.DirectoryServices.DirectorySearcher(dirEntry) 

 dirSearcher.Filter = "(samAccountName=" & USERID & ")"

        'The PropertiesToLoad.Add method will be useful when retrieving only the selected properties.

'In this example I have retrieved only GivenName, Mail and sn

'There are many other properties are available


dirSearcher.PropertiesToLoad.Add("GivenName")
'Users First Name
dirSearcher.PropertiesToLoad.Add("Mail")
'Users e-mail address
dirSearcher.PropertiesToLoad.Add("sn")
'Users last name

Dim sr As SearchResult = dirSearcher.FindOne()

If sr Is Nothing Then 'return false if user isn't found
lblStatus.Text = "Invalid UserID"
Return False
End If

'Retrieve the user's First Name, e-mail and Last Name and assigns them to text boxes

Dim de As System.DirectoryServices.DirectoryEntry = sr.GetDirectoryEntry() 

If Not de.Properties("GivenName").Value Is Nothing Then
txtUserName.Text = de.Properties("GivenName").Value.ToString()
End If 

If Not de.Properties("Mail").Value Is Nothing Then
txtEmail.Text = de.Properties("Mail").Value.ToString()
End If

If Not de.Properties("LastName").Value Is Nothing Then
txtLastName.Text = de.Properties("LastName").Value.ToString()
End If

Return True
'Valid user

Catch e As Exception ' return false if exception occurs

MsgBox("User Authetication Exception: " & e.Message)

Return False

End Try

End Function 
 

Sample Code 3:

The GetUserPropsUsingEmail function is used to retrieve the domain user Id using domain e-mail address.

The userPrincipalName property of Active directory determines the Domain e-mail address of the User.
 

Public Function GetUserPropsUsingEmail() As String


Dim strFullName As String = ""

Dim sPath As String = ""

Dim objDirEnt As New DirectoryEntry("LDAP://" & DOMAIN_NAME)

Dim objSearcher As New DirectorySearcher(objDirEnt)
Dim objSearchRes As SearchResult

' Filter by Lotus Notes internet name

objSearcher.Filter = "(userPrincipalName=" & txtInternetName.Text & ")"


Try
' count should be 1

If objSearcher.FindAll.Count > 0 Then

For Each objSearchRes In objSearcher.FindAll
sPath = objSearchRes.GetDirectoryEntry.Path

Next
objDirEnt.Close()

objDirEnt.Path = sPath


'get domain short name

strFullName = objDirEnt.Invoke("GET", "samAccountName")


End If


Catch ' return nothing if user isn't found

strFullName = ""


End Try


Return strFullName


End Function


 

SQL Query: Removing leading zeroes from SQL Server field

The SQL Query for Removing leading zeroes from SQL Server field

The following SQL Query removes the leading zeroes from "Field" field

Select replace(ltrim(replace(Field1, '0', ' ')) , ' ', '0') FROM TestTable


 

ERROR [HY000] [IBM][iSeries Access ODBC Driver][DB2 UDB]SQL0666 - Estimated query processing time xxx exceeds limit yyy

ERROR [HY000] [IBM][iSeries Access ODBC Driver][DB2 UDB]SQL0666 - Estimated query processing time xxx exceeds limit yyy.


 Where xxx and yyy represent the estimated amount of time it will take to process the query and the OS/400 query time limit, respectively.

The error occurs when the estimated SQL Query run time exceeds the system's query processing limit.

Solution:

You can turn off the query timeout limit in the iSeries Access ODBC Driver.

 

IBM now provides you with a mechanism for turning off query timeout value support for applications that use a particular ODBC Data Source Name (DSN).

 

You can turn off query timeout limit processing in a DSN by performing the following steps:

  • Open the ODBC Data Source Administrator on the client machine that is experiencing the SQL0666 error
  • In the Administrator window, highlight the DSN that you want to change and click on the Configure button
  • Click on the Performance tab in the Windows Setup dialogue
  • Click on the Advanced button under the Performance options. This will bring up the Advanced performance options window
  • Turn off the checkmark in the Allow Query Timeout checkbox. Click on OK to exit this screen
  • In the Windows Setup screen, click on the Apply button followed by the OK button. This allows you to exit the screen and save your changes


    image 

  • image 
     

Once this option is turned off, applications using this particular ODBC DSN will automatically disable support for query timeout value checking.

Note:

But remember that while this option is handy for allowing longer running queries to automatically finish, it also removes a safeguard against run-away queries that will throttle PC and AS/400 performance. So use it only when it's needed and leave it on the rest of the time.

Another Tip:

The ODBC Progress database can store binary or array of data into "CHAR" field type.

The SQLBulkCopy error "The byte array of data cannot be converted to nvarchar/varchar" might throw while migrating the data into SQL Server table's nvarchar/varchar (equivalent SQL data types)field.

Reason: While retrieving the data will be reaching into the destination table as an array of bytes which is supposed to be a text or string of characters.

IBM provides a mechanism to convert the binary data into text. This is achieved by performing the following steps:
 

  • Open the ODBC Data Source Administrator on the client machine that is experiencing this error
  • In the Administrator window, highlight the DSN that you want to change and click on the Configure button
  • Click on the Translation tab in the Windows Setup dialogue that appears
  • Turn on the checkmark in the Convert binary data (CCSID 65535) to text checkbox.
  • Click on the Apply button. This allows you to exit the screen and save your changes


     image

How to display a PDF document in browser using ASP.NET and VB.NET?

The below example would explain on how to Display a PDF document in browser using ASP.NET/VB.NET

Dim Fs As FileStream
Dim FileSize As Long
Dim filePath As String = "C:\Test.Pdf"

'Open the file.


Fs = New FileStream(filePath, FileMode.Open)
FileSize = Fs.Length

'Convert the file into array of bytes.
Dim Buffer(CInt(FileSize)) As Byte
Fs.Read(Buffer, 0, CInt(FileSize))
Fs.Close()

'Write the binary content directly to the HTTP Output Stream.

Response.ContentType = "application/pdf"
Response.OutputStream.Write(Buffer, 0, FileSize)
Response.Flush()
Response.Close()