@@ -32,26 +32,30 @@ public class ActiveDirectory
3232 /// Active Directory Password for Querying
3333 /// </summary>
3434 private static string adPassword = ConfigurationManager . AppSettings [ "API_AD_PASSWORD" ] ;
35+
36+ /// <summary>
37+ /// Active Directory custom properties for Querying
38+ /// </summary>
39+ private static List < string > adCustomProperties = ( ConfigurationManager . AppSettings [ "API_AD_CUSTOM_PROPERTIES" ] ) . Split ( ',' ) . ToList < string > ( ) ;
3540 #endregion
3641
3742 #region Methods
3843 /// <summary>
3944 /// This method returns the entire Active Directory list for the configure Domain
4045 /// </summary>
4146 /// <returns></returns>
42- private static IDictionary < string , dynamic > GetDirectory ( )
47+ private static IDictionary < string , dynamic > GetDirectory < T > ( ) where T : UserPrincipal
4348 {
4449 Log . Instance . Info ( "AD Domain: " + adDomain ) ;
4550 Log . Instance . Info ( "AD Path: " + adPath ) ;
4651 Log . Instance . Info ( "AD Username: " + adUsername ) ;
4752 Log . Instance . Info ( "AD Password: ********" ) ; // Hide adPassword from logs
4853
49- // Initilise a new dynamic object
50- dynamic adUsers = new ExpandoObject ( ) ;
51- // Implement the interface for handling dynamic properties
52- var adUsers_IDictionary = adUsers as IDictionary < string , dynamic > ;
54+ // new ExpandoObject() and implement the interface for handling dynamic properties
55+ var adUsers_IDictionary = new ExpandoObject ( ) as IDictionary < string , dynamic > ;
5356
54- MemCachedD_Value adCache = MemCacheD . Get_BSO < dynamic > ( "API" , "ActiveDirectory" , "GetDirectory" , null ) ;
57+ var inputDTO = Utility . JsonSerialize_IgnoreLoopingReference ( Activator . CreateInstance ( typeof ( T ) , new object [ ] { new PrincipalContext ( ContextType . Domain ) } ) as T ) ;
58+ MemCachedD_Value adCache = MemCacheD . Get_BSO < dynamic > ( "API" , "ActiveDirectory" , "GetDirectory" , inputDTO ) ;
5559 if ( adCache . hasData )
5660 return adCache . data . ToObject < Dictionary < string , dynamic > > ( ) ;
5761
@@ -60,11 +64,20 @@ private static IDictionary<string, dynamic> GetDirectory()
6064 // Get to the Domain
6165 using ( var context = new PrincipalContext ( ContextType . Domain , adDomain , String . IsNullOrEmpty ( adPath ) ? null : adPath , String . IsNullOrEmpty ( adUsername ) ? null : adUsername , String . IsNullOrEmpty ( adPassword ) ? null : adPassword ) )
6266 {
63- // Get to the Search, filtering by Enabled accounts, exclude accounts with blank properties
64- using ( var searcher = new PrincipalSearcher ( new UserPrincipal ( context ) { Enabled = true , SamAccountName = "*" , EmailAddress = "*" , GivenName = "*" , Surname = "*" } ) )
67+ // Crete the query filterusing enabled accounts and excluding those with blank basic properties
68+ var queryFilter = Activator . CreateInstance ( typeof ( T ) , new object [ ] { context } ) as T ;
69+ queryFilter . Enabled = true ;
70+ queryFilter . SamAccountName = "*" ;
71+ queryFilter . EmailAddress = "*" ;
72+ queryFilter . GivenName = "*" ;
73+ queryFilter . Surname = "*" ;
74+
75+ // Run the search
76+ using ( var searcher = new PrincipalSearcher ( queryFilter ) )
6577 {
6678 // Loop trough the results and sort then by SamAccountName
67- foreach ( var result in searcher . FindAll ( ) . Cast < UserPrincipal > ( ) . OrderBy ( x => x . SamAccountName ) )
79+ // Cast to dynamic to get all properties including any custom one
80+ foreach ( var result in searcher . FindAll ( ) . Cast < dynamic > ( ) . OrderBy ( x => x . SamAccountName ) )
6881 {
6982 // Check for duplicate accounts
7083 if ( adUsers_IDictionary . ContainsKey ( result . SamAccountName ) )
@@ -74,23 +87,30 @@ private static IDictionary<string, dynamic> GetDirectory()
7487 }
7588 else
7689 {
77- // Create a shallow copy of the UserPrincipal with the main proprieties for caching/serialising it later on
78- dynamic userPrincipal_ShallowCopy = new ExpandoObject ( ) ;
79- userPrincipal_ShallowCopy . SamAccountName = result . SamAccountName ;
80- userPrincipal_ShallowCopy . UserPrincipalName = result . UserPrincipalName ;
81- userPrincipal_ShallowCopy . DistinguishedName = result . DistinguishedName ;
82- userPrincipal_ShallowCopy . DisplayName = result . DisplayName ;
83- userPrincipal_ShallowCopy . Name = result . Name ;
84- userPrincipal_ShallowCopy . GivenName = result . GivenName ;
85- userPrincipal_ShallowCopy . MiddleName = result . MiddleName ;
86- userPrincipal_ShallowCopy . Surname = result . Surname ;
87- userPrincipal_ShallowCopy . EmailAddress = result . EmailAddress ;
88- userPrincipal_ShallowCopy . EmployeeId = result . EmployeeId ;
89- userPrincipal_ShallowCopy . VoiceTelephoneNumber = result . VoiceTelephoneNumber ;
90- userPrincipal_ShallowCopy . Description = result . Description ;
90+ // Create a shallow copy of AD with the mandatory proprieties for caching/serialising it later on
91+ var userPrincipal_ShallowCopy = new ExpandoObject ( ) as IDictionary < string , Object > ;
92+
93+ userPrincipal_ShallowCopy . Add ( "SamAccountName" , result . SamAccountName ) ;
94+ userPrincipal_ShallowCopy . Add ( "UserPrincipalName" , result . UserPrincipalName ) ;
95+ userPrincipal_ShallowCopy . Add ( "DistinguishedName" , result . DistinguishedName ) ;
96+ userPrincipal_ShallowCopy . Add ( "DisplayName" , result . DisplayName ) ;
97+ userPrincipal_ShallowCopy . Add ( "Name" , result . Name ) ;
98+ userPrincipal_ShallowCopy . Add ( "GivenName" , result . GivenName ) ;
99+ userPrincipal_ShallowCopy . Add ( "MiddleName" , result . MiddleName ) ;
100+ userPrincipal_ShallowCopy . Add ( "Surname" , result . Surname ) ;
101+ userPrincipal_ShallowCopy . Add ( "EmailAddress" , result . EmailAddress ) ;
102+ userPrincipal_ShallowCopy . Add ( "EmployeeId" , result . EmployeeId ) ;
103+ userPrincipal_ShallowCopy . Add ( "VoiceTelephoneNumber" , result . VoiceTelephoneNumber ) ;
104+ userPrincipal_ShallowCopy . Add ( "Description" , result . Description ) ;
105+
106+ // Add the cusotm properties to the shallow copy if any
107+ foreach ( string property in adCustomProperties )
108+ {
109+ userPrincipal_ShallowCopy . Add ( property , result . GetType ( ) . GetProperty ( property ) ? . GetValue ( result , null ) ) ;
110+ }
91111
92112 // Add user to the dictionary, serialise/deserialise to avoid looping references
93- adUsers_IDictionary . Add ( result . SamAccountName , userPrincipal_ShallowCopy ) ;
113+ adUsers_IDictionary . Add ( result . SamAccountName , userPrincipal_ShallowCopy as ExpandoObject ) ;
94114 }
95115 }
96116 }
@@ -103,7 +123,7 @@ private static IDictionary<string, dynamic> GetDirectory()
103123 }
104124
105125 // Set the cache to expire at midnight
106- MemCacheD . Store_BSO < dynamic > ( "API" , "ActiveDirectory" , "GetDirectory" , null , adUsers_IDictionary , DateTime . Today . AddDays ( 1 ) ) ;
126+ MemCacheD . Store_BSO < dynamic > ( "API" , "ActiveDirectory" , "GetDirectory" , inputDTO , adUsers_IDictionary , DateTime . Today . AddDays ( 1 ) ) ;
107127
108128 return adUsers_IDictionary ;
109129 }
@@ -115,7 +135,12 @@ private static IDictionary<string, dynamic> GetDirectory()
115135 public static IDictionary < string , dynamic > List ( )
116136 {
117137 // Get the full directory
118- return GetDirectory ( ) ;
138+ return List < UserPrincipal > ( ) ;
139+ }
140+ public static IDictionary < string , dynamic > List < T > ( ) where T : UserPrincipal
141+ {
142+ // Get the full directory
143+ return GetDirectory < T > ( ) ;
119144 }
120145
121146 /// <summary>
@@ -124,9 +149,13 @@ public static IDictionary<string, dynamic> List()
124149 /// <param name="username"></param>
125150 /// <returns></returns>
126151 public static dynamic Search ( string username )
152+ {
153+ return Search < UserPrincipal > ( username ) ;
154+ }
155+ public static dynamic Search < T > ( string username ) where T : UserPrincipal
127156 {
128157 // Get the full director
129- IDictionary < string , dynamic > adDirectory = GetDirectory ( ) ;
158+ IDictionary < string , dynamic > adDirectory = GetDirectory < T > ( ) ;
130159
131160 if ( adDirectory . ContainsKey ( username ) )
132161 return adDirectory [ username ] ;
@@ -167,4 +196,30 @@ public static bool IsPasswordValid(dynamic userPrincipal, string password)
167196
168197 }
169198
199+ /// <summary>
200+ /// Template to implement a extended UserPrincipal to retrieve custom AD properties (i.e. Sample)
201+ /// </summary>
202+ /*
203+ [DirectoryRdnPrefix("CN")]
204+ [DirectoryObjectClass("Person")]
205+ public partial class UserPrincipalExtended : UserPrincipal
206+ {
207+ public UserPrincipalExtended(PrincipalContext context) : base(context) { }
208+
209+
210+ // Create the "Sample" property.
211+ [DirectoryProperty("sample")]
212+ public string Sample
213+ {
214+ get
215+ {
216+ if (ExtensionGet("sample").Length != 1)
217+ return string.Empty;
218+
219+ return (string)ExtensionGet("sample")[0];
220+ }
221+ set { ExtensionSet("sample", value); }
222+ }
223+ }
224+ */
170225}
0 commit comments