
Defensive programming is a set of techniques/guidance on best practices to ensure your applications are secure, as bug free as possible, and respond gracefully to unexpected events (i.e. software exceptions).
Defensive programming is a set of techniques/guidance on best practices to ensure your applications are secure, as bug free as possible, and respond gracefully to unexpected events (i.e. software exceptions).
Password hashing is a valuable security feature that helps to ensure users’ passwords are encrypted at rest when saved in user data stores, such as databases. Hashing works on the principle of reliable/repeatable one-way encrypting of data.
The SharePoint User Profile service application provides a means to offload the traffic on a domain controller when querying information in an Active Directory schema.
ADAM (Active Directory Application Mode) and AD LDS (Active Directory Lightweight Directory Services) are synonyms for the same product-set. ADAM refers to the technology when hosted on Windows XP / Server 2003 and AD LDS refers to the technology as hosted on Windows 7 / 8 / Server 2008 / Server 2012.
For simplicity, we will refer to the technology as ADAM in this article for brevity, regardless of which operating system we are targeting.
ADAM allows instances of all or part of an Active Directory schema to be hosted separately from the domain controller to off-load tasks such as reading security group memberships or looking information about users (such as email address.) This helps to reduce the load on domain controllers for application-specific operations but ADAM effectively hosts a separate collection of the schema and this can be modified or extended as required for particular programming tasks. For example, additional application-specific security groups can be added to an ADAM schema to control access to an application.
ADAM can be synchronised to the main Active Directory schema to ensure any changes that have been made are captured and updated on the local instance. Although ADAM doesn’t provide scheduled synchronisation out of the box, a simple Windows Service (or scheduled script task) could be developed to call the synchronisation routine on a regular basis.
ADAM also includes a feature where it can still be used for authentication, by proxy. This effectively means that ADAM will service requests for schema information but pass authentication requests on to the domain controller and return the outcomes.
Creating an ADAM Instance
Configuring an ADAM Instance
These instructions assume you are using the default port of 389 and that you have installed your ADAM instance at the default location of %WINDIR%\Adam. If you are using a different port number to host ADAM then please replace 389 with your chosen port number in the commands below and replace the folder.
For Windows Server 2003:
ldifde -i -u -f ms-adamschemaw2k3.ldf -s localhost:389 -c "CN=Configuration,DC=X" #ConfigurationNamingContext
For Windows Server 2008:
ldifde -i -u -f ms-adamschemaw2k8.ldf -s localhost:389 -j . -c "CN=Configuration,DC=X" #ConfigurationNamingContext
Code language: plaintext (plaintext)
ldifde -i -s localhost:389 -c "CN=Configuration,DC=X" #ConfigurationNamingContext -f ms-userproxy.ldf
Code language: plaintext (plaintext)
ldifde -i -s localhost:389 -c "CN=Configuration,DC=X" #ConfigurationNamingContext -f ms-adamsyncmetadata.ldf
Code language: plaintext (plaintext)
source-ad-name domain-controller-hostname
source-ad-partition distinguished-name-of-the-domain (e.g. DC=mycompany,DC=com.)
source-ad-account <leave blank> (unless you want to be prompted for a password!)
account-domain <leave blank> (the domain for the source-ad-account if you specify it.)
target-dn the-distinguished-name-of-ADAM (e.g. DC=myapps,DC=mycompany,DC=com.)
base-dn the-distinguished-name-of-the-domain-controller-root-node.
object-filter (objectCategory=person) (this specifies the scope of data that will be synchronised.)
Code language: plaintext (plaintext)
<include>objectSID</include>
<include>givenName</include>
<include>sn</include>
<include>cn</include>
<include>description</include>
<include>title</include>
<include>company</include>
<include>department</include>
<include>manager</include>
<include>mail</include>
<include>physicalDeliveryOfficeName</include>
<include>telephoneNumber</include>
<include>sAMAcountName</include>
<include>distinguishedName</include>
<include>userPrincipalName</include>
Code language: HTML, XML (xml)
<user-proxy>
<source-object-class>user</source-object-class>
<target-object-class>userProxy</target-object-class>
</user-proxy>
Code language: HTML, XML (xml)
adamsync /install localhost:389 ms-adamsyncconf.xml
Code language: plaintext (plaintext)
regsvr32 schmmgmt.dll
Code language: plaintext (plaintext)
adamsync /sync localhost:389 DC=myapps,DC=mycompany,DC=com
Code language: plaintext (plaintext)
adamsync /force -1 /sync localhost:389 DC=myapps,DC=mycompany,DC=com /log mysync.log
Code language: plaintext (plaintext)
One big problem of using ADAM out of the box is that the feature-rich ‘Active Directory Users and Computers’ MMC snap-in doesn’t work with it. Instead, less user-friendly tools like ADSI Edit must be employed. This section will explain basic use of ADSI Edit but if you are going to be adminstering ADAM on a regular basis I’d recommend developing your own UI or using existing 3rd Party tools such as the excellent Apache Directory Studio.
ADAM instances can be accessed in exactly the same way that you communicate with the main domain controller – via the .NET System.DirectoryServices classes.
using (DirectoryEntry schema = new DirectoryEntry(this.ServerTextBox.Text))
{
using (DirectorySearcher searcher = new DirectorySearcher(schema))
{
if (userToFind.Contains("\\"))
{
// Trim off domain prefix
userToFind = userToFind.Substring(userToFind.IndexOf("\\") + 1);
}
searcher.Filter = string.Format(
"(&(objectClass=userProxy)(anr={0}))", userToFind);
searcher.SearchScope = SearchScope.Subtree;
SearchResultCollection results = searcher.FindAll();
if (results.Count > 0)
{
string sam = null;
foreach (SearchResult result in results)
{
if ((result.Properties.Contains("samaccountname") &&
string.Compare(
result.Properties["samaccountname"][0].ToString(),
userToFind,
true) == 0) ||
(result.Properties.Contains("cn") &&
string.Compare(result.Properties["cn"][0].ToString(),
userToFind,
true) == 0))
{
if (result.Properties.Contains("samaccountname"))
{
sam = result.Properties["samaccountname"][0].ToString();
}
// Get other result properties using well-known
// Active Directory field names
// TODO: do something with the properties you've retrieved.
}
}
}
}
}
Code language: C# (cs)
If you are unable to access your ADAM instance, it might be because the user account you are connecting with doesn’t have the required permissions. You can add/amend permissions via ADSI Edit:
When working programmatically with SharePoint you are likely to need to check membership of SharePoint Groups at some point. This article provides a simple route to retrieving user groups information via SharePoint’s web services.