Principal Extensions
The Account Management API provides three concrete directory object classes: UserPrincipal, GroupPrincipal and ComputerPrincipal. Since the directory schema is modifiable, and not every attribute in the schema is represented by a property on these principal objects, developers may want to create their own custom principal objects. The Principal, AuthenticablePrincipal, UserPrincipal, ComputerPrincipal, and GroupPrincipal classes can all be extended to create custom objects that extend the object model.
Extended classes can add new properties to the object model or remove existing properties from the extended class. The properties that are added to the extended class must be supported in the schema for the directory. Only the application directory and the domain schemas can be extended to support new property types, the Machine SAM directory does not support extensions. The attributes that are shown here are required by the Account Management API to create extension objects:
- DirectoryPropertyAttribute The map of the principal object property to the corresponding object in the directory. This attribute is set on the property in the derived class. The DirectoryPropertyAttribute class contains the SchemaAttributeName property.
- DirectoryRdnPrefixAttribute The RDN Prefix that is used to create the object. This property is set on the derived class. This attribute is optional for the derived class. The default RDN prefix of “CN” is supplied by the Account Management API when no RDN prefix is set on the derived class. The DirectoryRdnPrefixAttribute class contains the RdnPrefix property.
- DirectoryObjectClassAttribute The object class in the schema that the store inserts into a new object in the directory. The DirectoryObjectClassAttribute class contains the ObjectClass property.
The following example code example shows how to extend the user principal class. The RDN prefix is set to the default value CN, and the InetOrgPerson object class is added to the directory. The directory property mobile is also added through this class.
The ExtensionGet and ExtensionSet methods are used to create and populate the properties of the extension class, and they are used extensively in the example extension class that is shown here:
[DirectoryRdnPrefix("CN")]
[DirectoryObjectClass("inetOrgPerson")]
public class InetOrgPerson : UserPrincipal
{
// Inplement the constructor using the base class constructor.
public InetOrgPerson(PrincipalContext context) : base(context)
{
}
// Implement the constructor with initialization parameters.
public InetOrgPerson(PrincipalContext context,
string samAccountName,
string password,
bool enabled)
: base(context,
samAccountName,
password,
enabled)
{
}
InetOrgPersonSearchFilter searchFilter;
new public InetOrgPersonSearchFilter AdvancedSearchFilter
{
get
{
if ( null == searchFilter )
searchFilter = new InetOrgPersonSearchFilter(this);
return searchFilter;
}
}
// Create the mobile phone property.
[DirectoryProperty("mobile")]
public string MobilePhone
{
get
{
if (ExtensionGet("mobile").Length != 1)
return null;
return (string)ExtensionGet("mobile")[0];
}
set
{
ExtensionSet( "mobile", value );
}
}
// Create the other home phone property.
[DirectoryProperty("otherHomePhone")]
public string[] HomePhoneOther
{
get
{
int len = ExtensionGet("otherHomePhone").Length;
string[] otherHomePhone = new string[len];
object[] otherHomePhoneRaw = ExtensionGet("otherHomePhone");
for( int i = 0; i < len; i++ )
{
otherHomePhone[i] = (string)otherHomePhoneRaw[i];
}
return otherHomePhone;
}
set
{
ExtensionSet( "otherHomePhone", value );
}
}
// Create the logoncount property.
[DirectoryProperty("LogonCount")]
public Nullable<int> LogonCount
{
get
{
if (ExtensionGet("LogonCount").Length != 1)
return null;
return ((Nullable<int>)ExtensionGet("LogonCount")[0]);
}
}
// Implement the overloaded search method FindByIdentity.
public static new InetOrgPerson FindByIdentity(PrincipalContext context,
string identityValue)
{
return (InetOrgPerson)FindByIdentityWithType(context,
typeof(InetOrgPerson),
identityValue);
}
// Implement the overloaded search method FindByIdentity.
public static new InetOrgPerson FindByIdentity(PrincipalContext context,
IdentityType identityType,
string identityValue)
{
return (InetOrgPerson)FindByIdentityWithType(context,
typeof(InetOrgPerson),
identityType,
identityValue);
}
}
public class InetOrgPersonSearchFilter : AdvancedFilters
{
public InetOrgPersonSearchFilter(Principal p) : base(p) { }
public void LogonCount(int value, MatchType mt)
{
this.AdvancedFilterSet("LogonCount", value, typeof(int), mt);
}
}
Using the Extended Class
The following code example shows how to create a new InetOrgPerson object and insert it into the store. The example also shows how to use the search feature to find InetOrgPerson objects.
// Create the context for the InetOrgPerson.
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "fabrikam", "DC=fabrikam,DC=com"))
{
// Create the InetOrgPerson object and set some properties on it.
InetOrgPerson newInetPerson = new InetOrgPerson(ctx);
newInetPerson.DisplayName = "Jim Daly";
newInetPerson.SamAccountName = "Jim Daly";
newInetPerson.MobilePhone = "2155550189";
string[] phone = new string[1];
phone[0] = "1234567";
newInetPerson.HomePhoneOther = phone;
newInetPerson.Save();
// Search the directory for the new object.
InetOrgPerson inetPerson = InetOrgPerson.FindByIdentity(ctx,
IdentityType.SamAccountName,
"Jim Daly");
// Search for all Inetorgperson objects that have logged on more than 5 times.
InetOrgPerson filter = new InetOrgPerson(ctx);
filter.AdvancedSearchFilter.LogonCount(5, MatchType.GreaterThan);
PrincipalSearcher ps = new PrincipalSearcher(filter);
foreach (InetOrgPerson p in ps.FindAll())
{
}
}
Group Objects
When group objects are expanded by the GetMembers method, there may be extended object types in the expanded group. Since the group object does not have knowledge of the extended object types, the Account Management API creates an AuthenticablePrincipal object to represent group members that are extended types. The interfaces on the AuthenticablePrincipal object can be used to manage extended object types that are contained in the group. Applications can also use the StructuralObjectClass property to determine the object type and then perform more object specific editing.
See Also
Reference
System.DirectoryServices.AccountManagement
Concepts
About System.DirectoryServices.AccountManagement
Using System.DirectoryServices.AccountManagement
Send comments about this topic to Microsoft.
Copyright © 2008 by Microsoft Corporation. All rights reserved.