Apply Single-Sign-On to your application
Brief :
In this ever-evolving world of technology, applications are getting more
complex by the day but the economies of scale is not there when business users
want them up to market faster and place great emphasis on ease of use.
The concept of Distributed computing has been around for almost a decade.
However, distributed computing has mainly been confined within the walls of the
organization and most importantly, vendor-specific platforms.
In the recent years, professional bodies have come topgether and has worked
together with all the major platform vendors out there and came up with
widely-accepted standards. Suddenly, platforms are not a major hindrance to
communication anymore .The current explosion of bandwidth supply, coupled with
the lower cost of utilizing it, plus other reasons, has also caused blurring of
lines and boundaries between Local Area Network (LAN) and the Wide-Area Network
(WAN). We are now seeing evolution of technology where a single application can
span across multiple platforms and transcend physical barriers, parameters and
boundaries.
While I dont want to go into details of what was described above, the topic of
my article will touch one aspect of application development which I believe
makes some sense to be farmed out to distributed computing and that is Identity
Management.
Businesses of today are getting more difficult and complex and span across to
other business domains as well. Software Vendors are finding it difficult to
meet the requirements as the ways to do business are changing all the time as
well. A full enterprise-resource planning suite is hard to built without third
party involvement in terms of tools and support. After that, enterprises will
demand that what is being deployed must work seamlessly with the other
incumbent or new applications. One problem of that is the entry point of an
application --- the Sign-on / Log-on Interface. If an enterprise should deploy
a portal for the users to choose and use whichever application the need
desires, the question is who holds the user indentity. If application A holds
the main key to the user database, how would application B and C communicate
with it seamlessly. Of course, with the use of widely-adopted web services and
XML, the next question would be are Application A, B and C built in a way where
identity management is loosely-coupled in their application architecture ? If
so, who should hold the key, what are to be kept in this database and very
importantly, who manages it ?
Ideal :
One of the way I am recommending here is the use of the
organizational directory. One of the key differences between a directory and a
database is the frequency of the usage and of the data and also the rate of
change. A Directory is very much like the Yellow Pages. You dont refer to it
every minute or second of the day (frequency of usage) and it gets published
only once a year (rate of change). All basic essential User identity is being
stored in a company's directory within the IT Infrastructure. This can be in a
IBM or Unix Mainframes, Novell Servers or Windows Active Directory. What is
needed is a way to query and lookup the indexes of these directories to find
the user and authenticate them. This is achieved by a common, widely-adopted
and widely-accepted standard called Lightweight Directory Access Protocol
(LDAP). Just like how Structured Query Language (SQL) queries databases, LDAP
is used to query directories to return certain information.
In more ways than you think, it doesnt make sense for an application to hold
another set of user data where the host platform of the application already
holds a copy. The LDAP Directory is managed, rightfully, by the System Owner
and he / she will also rightfully assign the proper rights to the different
roles each application requires. Each user is authenticated just once with
their user-credentials at logon time. From then on, their user-session is
mapped onto their user-credentials, policies and authorization.
Launching an application will involve retrieving their current user session
details and then querying the LDAP Directory for their user-roles and rights
with that information. This is all transparent to the user and once the user
gets authenticated and authorized by the LDAP Query, he/she will have access to
all or portions of the application, depending on the roles of the user. Once
that happens, Single-Sign-On is achieved.
Critics :
Of course, the concept of Single-Sign-On in Identity Management has its
critics. The most important flaw is that once a user signs-on at point of
entry, he / she is signed-on as long as he / she is in the company's domain.
Theorectically speaking, if he / she doesn't logged-off his / her machine, the
session will always be authenticated regardless of who uses the same session
later. In other words, while the user identity is not compromised, the current
user session can be hijacked. This can easily happen when the user leaves his /
her machine unattended and another person takes over the computer and the
session. The main criteria of Single-Sign-On is that the user will only need to
sign-on once (as the name suggests) and therefore, there should not be a logout
button. Having one serves no purpose as it is the session that is
authenticated, not the user anymore. The user only serves to create a valid
session. If there is a login after a logout, then the rule of Single-Sign-On is
flouted.
Another flaw of it includes the authentication of the user when the user is
coming in from across domain. This will likely if he or she uses the same
application via a Internet Interface with the same application sitting on the
office domains. The user can be in their own personal own domain from home or
elsewhere or using another person's machine, then their own personal
user-credentials will be different from the one that is stored in the
organization's domain. This will require users to do multiple logins which goes
against the concepts of Single-Sign-On.
Some of the flaws can be solved by user-education. Educate the users to protect
their machines whenever they are not around by locking up their sessions with a
password-protected screen-saver or by other similar means. As of the second
flaw, until a accepted secure and accepted tunelling protocol follows the user
wherever he or she goes, that ideal may still be a way away.
Benefits :
However, the benefits are heavy. User-rights, coupled with
user and company policies are all centralized in a single place within the
organization directory. Users have only one identity (userIds and Passwords) to
maintain. Business owners will have the peace of mind that all entry points to
applications and data are kept within a secure LDAP Directory with the
company's user policy, password-policy in mind. This should be dictated by the
business owners not by the software vendors. Different applications will all
query one single user directory for their own authentication and should they
require more application-specific data and field, redirect the user to collect
more specific information from them. The storing of other information will
ultimately be mapped onto the user common name in the LDAP Directory.
Solution(s) :
Therefore, the best for now would be a hybrid of both scenarios, taking the
pros and cons of both. Have an application architecture with a single user
repository at the Organization's LDAP Directory but letting users sign on again
for added security with the same user-credentials. This may solve the problem
at hand. Still the ideal is to be and can be achieved. Imagine your client
email application asking you for your password each time its goes out to
receive or send your emails.
Microsoft .NET has made it easy to do both with just some switches of commands
at a configuration file. Therefore, it doesnt take much to deploy either
solutions depending on client needs.
I will dive into some VB.NET Coding to explain how both can be achieved.
Scenario A : True-Blue Single-Sign-On
1) At launch of application, query LDAP and see if the user is in the proper
user-groups to access the application. I am, of course, assuming that groups
are assigned to application, not individuals.
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load
Dim p As WindowsPrincipal = Thread.CurrentPrincipal
Dim a As New LDAPQuery
Dim objCook As New HttpCookie("LDAPCookie")
'Check for authentication and write into Cookie
Dim sLDAPCN As String = (a.GetCNByLDAP(p.Identity.Name))
'Check for LDAP Authentication First
If sLDAPCN <> "" And _
(a.blnFindCNinGroups(a.GetCNByLDAP(p.Identity.Name), "AppAUserGroups")) Then
objCook.Value = (sLDAPCN)
Response.Cookies.Add(objCook)
'Check for LDAP User Existence in Application Database
'If User exists in Application DB, Start Application
If (FindLDAPCNinDB(sLDAPCN)) Then
'DROP Authentication Cookie token
'Compute a hashed value of the current session ID
'into a cookie to signal authentication success
'Be sure to check for this cookie for every page load
'if value doesnt match or cookie doesnt exists,
'Re-do the whole authentication process again.
'Single-sign-on should continue, the cookies drop
'prevent authenticated LDAP Users from not having
'their CN mapped with other application-specific
'fields or data.
Response.Redirect("Welcome.aspx")
Else 'If False, do Database mapping
Response.Redirect("CollectOtherInfo.aspx")
End If
Else
Response.Redirect("LoginError.htm")
End If
End Sub
Private Function FindLDAPCNinDB(ByVal sLDAPCN As String) As Boolean
'For ease of setup, I am using a Flat XML File as a database
'However, a proper way would be to use a relational database
'You may use the ADO.NET to query and get information from the databse
Dim xmldoc As New XmlDocument
Dim xmlnode As XmlNode
Dim xmlnodelist As XmlNodeList
xmldoc.Load("D:\WebDeploy\LDAPQuery\FlatDB.xml")
xmlnodelist = xmldoc.SelectNodes("/Users/User")
For Each xmlnode In xmlnodelist
'Find LDAPCN
If xmlnode.ChildNodes.Item(0).InnerText = sLDAPCN Then
Return True
End If
Next
Return False
End Function
'###########
'###########
Imports System.DirectoryServices
Public Class LDAPQuery
'This function returns the Common Name (CN) of the Login information of the
'LDAP Directory. The CN is an unique identity and cannot be changed or edited
in LDAP
Public Function GetCNByLDAP(ByVal strLogin As String) As String
Dim str As String = ""
'Parse the string to check if domain name is present.
Dim idx As Integer = strLogin.IndexOf("\")
If (idx = -1) Then
idx = strLogin.IndexOf("@")
End If
Dim strDomain As String
Dim strName As String
If (idx <> -1) Then
strDomain = strLogin.Substring(0, idx)
strName = strLogin.Substring(idx + 1)
Else
strDomain = Environment.MachineName
strName = strLogin
End If
Dim obDirEntry As DirectoryEntry = Nothing
Try
Dim strPath As String = "LDAP://DC=Softwaremaker,DC=net"
obDirEntry = New DirectoryEntry(strPath)
Dim rootSearch As New DirectorySearcher(obDirEntry)
Dim SearchResult As SearchResult
Dim spn As String = strName & "@" & strDomain
rootSearch.Filter = ("(&(objectCategory=user)(userPrincipalName=" & spn
& "))")
For Each SearchResult In rootSearch.FindAll 'Or FindOne
Dim i As Integer
'Check here - Should only return ONE result
For i = 0 To SearchResult.Properties("cn").Count - 1
str += SearchResult.Properties("cn")(i)
Next
Next
Catch ex As Exception
str = ex.Message
End Try
Return str
End Function
'Function finds and returns if User if in the specified user group
Public Function blnFindCNinGroups(ByVal sLogonUserCN As String, ByVal sGroup As
String) As Boolean
Try
Dim sDirEnt As String = "LDAP://server/CN= " &
sLogonUserCN&",CN=Users,DC=Softwaremaker,DC=net"
Dim user As DirectoryEntry = New DirectoryEntry(sDirEnt)
Dim pcoll As PropertyCollection = user.Properties
Dim i As Integer
Dim s As String
'The loop will return all Groups of which the CN is a member Of
For i = 0 To pcoll("memberOf").Count - 1
s = pcoll("memberOf")(i).ToString
If QueryLDAP(s, sGroup) = True Then Return True
Next
Return False
Catch ex As Exception
Return False
End Try
End Function
Public Function QueryLDAP(ByVal strQuery As String, ByVal sGroup As String) As
Boolean
Dim obDirEntry As DirectoryEntry = Nothing
Try
Dim strPath As String = "LDAP://" & strQuery
Dim s As String
obDirEntry = New DirectoryEntry(strPath)
Dim rootSearch As New DirectorySearcher(obDirEntry)
Dim SearchResult As SearchResult
For Each SearchResult In rootSearch.FindAll
Dim i As Integer
'Check here - Should only return ONE result
For i = 0 To SearchResult.Properties("cn").Count - 1
s += SearchResult.Properties("cn")(i)
Next
If s = sGroup Then Return True
Next
Catch ex As Exception
Return False
End Try
End Function
End Class
'###########
2) I am not a LDAP Query guru or expert. I am sure I am taking one step too
many just to query if the user exists within the specified user group in the
LDAP Directory. But I am selling idea not code so you should get the idea :)
3) Things that can be applied includes :
a) Using Windows Authentication in the IIS Settings
b) At the web.config file level
'###########
<identity impersonate="true" /> <authentication mode="Windows" />
<authorization> <allow roles="SoftwaremakerNet\AppAUserGroup" />
</authorization>
'###########
Scenario B : Hybrid Forms Authentication with LDAP
Please see the Microsoft link below for a detailed working version.
http://support.microsoft.com/default.aspx?scid=kb;EN-US;326340
Conclusion :
The above examples only show the code implementations on the Microsoft .NET
Platform. You can implement the same ideas with J2EE. As long as you built LDAP
Capability into your application, it will work.
I hope you are able to see how you can integrate user identity management of a
organizational directory into your application and map them onto your own
databases. The users will still exist in the database but the management of
their identity should be centralized within a LDAP Directory implementing
companies policies and securities. There are a couple of ways that True-Blue
Single-Sign-On can be applied across multiple domains. However, these implement
rather new and expensive technologies such as physical authentication tokens
which acts like your fingerprints. I will leave that topic for furthur
discussions later.
|