Building and Integrating a Small Office Intranet

This “how we did it” story includes valuable tips for building an intranet that integrates enterprise services in a user-friendly way.
Active Directory Integration

Another valuable addition to our intranet was integrating it with our Active Directory user database via LDAP. We use this to provide a company directory that lists all of our employees. The directory is built in real time whenever it is accessed, and that is a major time-saver for administrators. Whenever new users are added using the normal Active Directory tools, they instantly show up in the intranet directory. We also allow our users to edit their own personal information, and those edits are put into the Active Directory by the CGI script. The process is relatively straightforward, although there are some things to take into consideration. Let me walk you through the process of how we set this up.

The first thing we do is create a proxy user called proxyuser in Active Directory. This is the user name our scripts use to authenticate with LDAP. The proxy user is granted rights to read and write information on user objects within the ou=Domain Users container. That's all that needs to be done within Active Directory. We use Perl for our CGI, so that means using Net::LDAP. Here is how we connect to Active Directory from within a CGI script:

##: Active Directory connection
use Net::LDAP;

my $ldap=Net::LDAP->new('');
my $mesg=$ldap->bind('',
                      password=>'proxyuser'  );

Notice the syntax that Active Directory requires for the user name field. It's one of the unique requirements of Active Directory's LDAP interface. Now that we are connected to the directory, we do a query to find all the user objects in the ou=Domain Users container:

##: Query LDAP to get a list of employees
my $basedn="ou=Domain Users,dc=domain,dc=com";
my $filter="(objectClass=user)";
  base=> $basedn,
  filter=> $filter,
  attrs=> ['givenName','sn','mail',
           'title','sAMAccountName' ]

This returns all of the user objects in that container, along with all of the pertinent attributes you would expect to find in a company directory. We now can refine our search filter to limit our search to only those users whose last name starts with a letter passed to the CGI script in its URL. This allows us to follow an address-book format, so we don't have to display all 70 users at once. We fall back to the letter a if no letter was asked for in the URL:

##: Get letter requested in the URL
my $letter;
$letter=param('letter') || "a";
my $filter="(&(objectClass=user) (sn=$letter*))";

If you aren't familiar with the syntax used by LDAP search filters, I suggest you look over RFC-2254. At this point, we can iterate over our query results and prettify them as needed. Because we also looked up this user's SSC information, we can check each employee's sAMAccountName as we go through the loop. When we find the employee that corresponds to the person SSC says is viewing the page, we add a link by the employee's name that allows him or her to go to an area to edit the directory information. It looks like this:

##: Display the directory
foreach my $entry ($mesg->sorted('sn')) {

  my $san=$entry->get_value('sAMAccountName');
  $empdir.="<div class='empcard'>";
  if(lc($cn) eq lc($san)) {
    ##: This is our man.  Add a button.
    $empdir.="<a href='empedit.cgi'>Edit</a>";
  $empdir.="<span id='name'>";
  $empdir.=$entry->get_value('givenName')." ";
  $empdir.="<span id='title'>";

print STDOUT $empdir;