Thursday, March 22, 2012

C# Code to look up current user in Active Directory

C# Code to look up Current User in Active Directory

Here's some re-usable C# code to lookup the currently logged-in user in Active Directory to get various AD properties such as FirstName, Last Name, and Email. The method IsExistInAD() below is handy in intranet applications where your ASCX or ASPX can assume the current user is authenticated in the domain and you need properties of the user from Active Directory. Method IsExistInAD() takes, as input the user name in the format DOMAIN\\alias and performs a Directory search using .NET Directory Services using System.DirectoryServices.ActiveDirectory. If successful, it populates the private SearchResult _result variable with the various properties from Active Directory and returns true. If the Directory search does not find the current user, the IsExistInAD() method returns false.  Note this code handles multiple domains, so if some of your users have username e.g. NORTHAMERICA\\bobsmith and other users have e.g. SOUTHAMERICA\\juanparamo, this code handles it by parsing the domain name and using it in the rootDirectory of the Directory Searcher, so it will find the user in the correct ActiveDirectory Domain.

Note that your ASP.NET application gets this user name to pass as input to IsExistInAD() automatically for the currently logged in user from the Page.User.Identity.Name property when your web application is configured for Windows Authentication.

The first time you setup the target server that will run the Site Info Web Application, you must configure IIS to use Windows Authentication. The Site Info Web Application depends on this and it is not the default configuration of IIS.  This configuration setting is Windows/IIS and does not require adjustment on future deployments of new builds or upgrades.

How to Configure Windows Authentication 


On the target IIS server
From Server Manager, Open Internet Information Services (IIS) Manager

In the left side panel, select the server (e.g. ZLMRCWEB31)

Double-click the  Authentication icon to open the Authentication Applet

  1. Enable Windows Authentication

  1. Disable Anonymous Authentication





Code Default.aspx.cs

using System;
using System.Collections.Generic;
using System.Collections;
using System.Linq;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
namespace TestADLookupUsersEmail
{
    public partial class _Default : System.Web.UI.Page
    {
        public class ContactADFields
        {
            public string FirstName;
            public readonly string FirstNameProp = "givenname";
            public string LastName;
            public readonly string LastNameProp = "sn";
            public string Email;
            public readonly string EmailProp = "mail";
            public string FullName;
            public readonly string FullNameProp = "displayname";
        }
        private SearchResult _result;
        private ContactADFields contact = new ContactADFields();       

        protected void Page_Load(object sender, EventArgs e)
        {
        }
        public string getUserIdentityName()
        {
            return Page.User.Identity.Name;
        }
        public string getUserEmail()
        {
            if (IsExistInAD(Page.User.Identity.Name))
            {
                if (_result.Properties.Contains(contact.FirstNameProp))
                {
                    contact.FirstName = (string)_result.Properties[contact.FirstNameProp][0];
                }
                if (_result.Properties.Contains(contact.LastNameProp))
                {
                    contact.LastName = (string)_result.Properties[contact.LastNameProp][0];
                }
                if (_result.Properties.Contains(contact.EmailProp))
                {
                    contact.Email = (string)_result.Properties[contact.EmailProp][0];
                }
                if (_result.Properties.Contains(contact.FullNameProp))
                {
                    contact.FullName = (string)_result.Properties[contact.FullNameProp][0];
                }
                int propCount = _result.Properties.PropertyNames.Count;
                foreach (string propName in _result.Properties.PropertyNames)
                {
                    try
                    {
                        string propVal = (string)_result.Properties[propName][0] as String;
                    }
                    catch (Exception)
                    {
                        continue;
                    }
                }
            }
            return contact.Email;
        }
        /// <summary>
        /// Parse a User Identity Name e.g. "REDMOND\\billg" setting the out accountName and out domainName
        /// </summary>
        /// <param name="path"></param>
        /// <param name="accountName"></param>
        /// <param name="domainName"></param>
        /// <returns>true if successful parsing the input user name</returns>
        private bool ParseUserName(string path, out string accountName, out string domainName)
        {
            bool retVal = false;
            accountName = String.Empty;
            domainName = String.Empty;
            string[] userPath = path.Split(new char[] { '\\' });
            if (userPath.Length > 0)
            {
                retVal = true;
                accountName = userPath[userPath.Length - 1];
                if (userPath.Length > 1)
                {
                    domainName = userPath[userPath.Length - 2];
                }
            }
            return retVal;
        }
        /// <summary>
        /// Lookup user in AD, and if successful, set SearchResult _result and return true.
        /// </summary>
        /// <param name="loginName">The Page.User.Identity.Name e.g. "REDMOND\\billg"</param>
        /// <returns>True if found in AD. Also sets SearchResult _result.</returns>
        private bool IsExistInAD(string loginName)
        {
            DirectorySearcher search = null;
            string userName;
            string domainName;
            if (ParseUserName(loginName, out userName, out domainName))
            {
                DirectoryContext dirCtx = new DirectoryContext(DirectoryContextType.Domain, domainName);
                if (dirCtx != null)
                {
                    Domain usersDomain = System.DirectoryServices.ActiveDirectory.Domain.GetDomain(dirCtx);
                    if (usersDomain != null)
                    {
                        DirectoryEntry rootDirEntry = usersDomain.GetDirectoryEntry();
                        if (rootDirEntry != null)
                        {
                            search = new DirectorySearcher(rootDirEntry);
                            search.Filter = String.Format("(SAMAccountName={0})", userName);
                        }
                    }
                }
            }
            else
            {
                search = new DirectorySearcher();
                search.Filter = String.Format("(SAMAccountName={0})", loginName);
            }
            // Adding properties to the DirectorySearcher is supposed to make the
            // query more efficient by only returning the fields we want. However,
            // doing so seems to always make teh Last Name prop ("sn") return blank.
            //search.PropertiesToLoad.Add(contact.FirstNameProp);
            //search.PropertiesToLoad.Add(contact.LastNameProp);
            //search.PropertiesToLoad.Add(contact.EmailProp);
            //search.PropertiesToLoad.Add(contact.FullNameProp);
            _result = search.FindOne();
           
            if (_result == null)
            {
                return false;
            }
            else
            {
                return true;
            }
        }
    }
}

 

Tuesday, January 31, 2012

I led a team last spring to develop a Software Development Kit for Windows Phone. Today I just got word that Microsoft has published it:  a beta of its Amazon Web Services (AWS) software development kit (SDK) for Windows Phone. This was a fun challenge taking Amazon Web Services (which are awesome) and making a Sliverlight + Windows Phone 7 library and set of sample programs available to consume those services.

Thursday, November 3, 2011

Folks still use WSPBuilder even with 2010

I learned today that many Visual Studio 2010/SharePoint 2010 solution developers are still using Carsten Keutmann's WSPBuilder tool, despite all the new WSP package, deploy, and debug facilities built into Visual Studio 2010.

I had used WSPBuilder extensively in all my MOSS (SharePoint) 2007 projects but not with any of my 2010 projects. Now come to find out, people like David Stampfli at Microsoft still use WSPBuilder despite all the built-in stuff in 2010!

One word to the wise: there is a separate version of WSP Builder for SharePoint 2010/Visual Studio 2010. It's called WSP Builder Extensions 2010 Beta 1.4 and you get it from here: http://wspbuilder.codeplex.com/releases/30858/download/94507. At first, I made the mistake of downloading the "Recommended Download" (WSP Builder Extension 1.06...) and after installing, I could not find any WSP Builder project templates available in my Visual Studio 2010. Browsing Carsten Keutmann's blog, I noticed that it mentions "Please look on codeplex under Download. It's the last file of the 4 available." After I got the WSP Builder Extensions 2010 Beta 1.4 the templates became available as expected.

Thursday, October 27, 2011

My Goals launching this new blog

Today is my three year anniversary of working at Neudesic LLC. It seems like an auspicious occasion to launch this new blog.

My goal is to share with you some of the tips, tricks, and lessons I've learned building enterprise solutions to business problems using SharePoint, C#, Visual Studio, Workflow, and the Office Business Platform.
What a terrific company Neudesic is! I get a steady stream of challenging engagements to work on. Derek Drennan is a terrific boss. Just today I got confirmation that Noam Topaz has joined Neudesic as a Director of SharePoint Solutions for out region (Pacific Northwest). And to think, just three years ago he was trying to hire me!
Here at at Neudesic we have quite a number of interesting initiatives going on. The Portals and Collaboration practice is working on a major upgrade of our system for capturing and re-using Intellectual Capital. We are capturing accelerators, code and procedures that we turn around and use to build better solutions to common problems our clients run into. This IC-capture system faces all the classic challenges faced by knowledge management systems, including ease of use, searchability, and user adoption.
Just a few weeks back Simeon Cathey -- the General Manager of our Portals and Collaboration Practice -- led our huge presence at the SharePoint Conference 2011 in Anaheim.
Our Mobility practice is going great guns, with very interesting developments in the intersection of Cloud, Mobility, and SharePoint.
The Custom Application Development practice is leading the whole Microsoft Business Partner community into the Cloud/Azure world with user groups, sample programs, and training opportunities.
Just last week I joined a company-wide campaign to with other consultants in the Custom App Dev practice to learn HTML 5. We're a bit dismayed at having to learn yet another language (I was just getting the hang of jQuery) but now that I'm seeing what I can do in the markup without any code, I'm convinced this is an endeavor worthy of my investment.
I'll need a couple of weeks to post my SharePoint best practices here but I am really looking forwards to it. I have quite a long backlog of useful and helpful tips and code snippets I want to share. I just have to factor out the most useful, bloggable pieces and test to make sure they will work for you. Stay tuned.