Capitalize on the Platform’s Identity Infrastructure for Single Signon (SSO)
Providing SSO across desktop applications is certainly a desired goal in application development, but many developers think it is either not achievable, too difficult to implement, or lean on third-party solutions to provide this capability. In Keith Brown’s paper, The .NET Developer’s Guide to Identity , he states, “There are companies that spend fortunes trying to implement SSO across the myriad of applications they've developed or purchased over the years. What I'm here to tell you is that you can get this feature for free; all you have to do is agree to write less code and instead rely on the platform to do the heavy lifting.” He also discusses in some detail the nuts-and-bolts of authentication that developers should be aware of, but his guidance is to let the platform infrastructure carry that load. Developers should simply tap into what the authentication event makes available to them through the WindowsIdentity and WindowsPrincipal classes. Keith discusses these two classes in the paper so I will not elaborate here, but my intent is to show a bit of code and point you to a couple resources so you can experiment with this on your own.
Essentially, a developer can leverage the desktop’s login for their application in just a couple lines of code. You can see in this screenshot, https://blogs.msdn.com/photos/donovanf/images/874326/original.aspx, some of the information available in each of the instantiated objects.
So how does one tap into this? First, the developer must pull in a couple namespaces, System.Security.Principal and System.Threading. Then if your application needs to do repeated access for role-based validation (such as for .IsInRole checks), it is more efficient to simply drive off the WindowsPrincipal object because there is no need to repeatedly instantiate the WindowsIdentity object. These two lines of code will accomplish this:
AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
WindowsPrincipal myPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
If you need the additional information that the identity object provides, you can instantiate a WindowsIdentity object and then use it to subsequently instantiate a corresponding WindowsPrincipal object. This is shown in the following two lines of code:
WindowsIdentity myIdentity = WindowsIdentity.GetCurrent();
WindowsPrincipal myPrincipal = new WindowsPrincipal(myIdentity);
Now, does leveraging the platform’s authentication absolve the application from doing its own due diligence? Most likely not. Therefore, the application could interrogate the DOMAIN provided in the .Name property or use any of the other data values provided in the objects to assess whether or not to let the application continue. Or by the presence or absence of specific data values, it could make the determination to pop-up a login window that could collect and validate credentials against AD, ADAM or another LDAP store for that matter. My point here is to simply take tactical advantage of what you can from the platform and then extend it as needed. A short seven-minute screencast presenting a coding example for this is found here on Channel9 https://channel9.msdn.com/Showpost.aspx?postid=154885. And the companion, downloadable code sample is available here https://channel9.msdn.com/ShowPost.aspx?PostID=154871. Lastly, the code example shows how to use .IsInRole with a WindowsPrincipal object to validate if the user is in any one of the WindowsBuiltInRoles. It also shows how to use the .Groups of a WindowsIdentity object to list all the group security identifiers (SIDs) to which the logged on user belongs.