Active Directory Tip #5 – Set Large Integer (e.g. Account expires date)

by Tobias Hertkorn on May 10th, 2010

Setting a large integer property is just as easy.

C#:
  1. /// <summary>
  2. /// You still have to call CommitChanges() after using this method.
  3. /// </summary>
  4. private void SetAccountExpiresDate(DirectoryEntry directoryEntry, DateTime expiresOn)
  5. {
  6.   long accountExpires = expiresOn.ToFileTimeUtc();
  7.    
  8.   var accountExpiresOriginalValue = directoryEntry.Properties["accountExpires"].Value;
  9.  
  10.   Type type = accountExpiresOriginalValue.GetType();
  11.  
  12.   int highPart = (int)(accountExpires>> 32);
  13.   int lowPart = (int)(0xFFFFFFFF & accountExpires);
  14.  
  15.   type.InvokeMember("HighPart", BindingFlags.SetProperty, null, accountExpiresOriginalValue, new object[] { highPart });
  16.   type.InvokeMember("LowPart", BindingFlags.SetProperty, null, accountExpiresOriginalValue, new object[] { lowPart });
  17.  
  18.   SetAdObjectAttribute(directoryEntry, "accountExpires", accountExpiresOriginalValue);
  19. }

May 10th, 2010 2:00 pm | Comments (0)

Active Directory Tip #4 – Get Large Integer (e.g. Account expires date)

by Tobias Hertkorn on May 4th, 2010

Certain properties, like usnChanged or accountExpires, are in an IADsLargeInteger format. One way to read out the long representation of the value of such a property is by reflection.

C#:
  1. private static long ConvertLargeIntegerToLong(object largeInteger)
  2. {
  3.   Type type = largeInteger.GetType();
  4.  
  5.   int highPart = (int)type.InvokeMember("HighPart", BindingFlags.GetProperty, null, largeInteger, null);
  6.   int lowPart = (int)type.InvokeMember("LowPart", BindingFlags.GetProperty | BindingFlags.Public, null, largeInteger, null);
  7.  
  8.   return (long)highPart <<32 | (uint)lowPart;
  9. }

That value may be converted to a DateTime value using the static DateTime.FromFileTimeUtc method.

C#:
  1. object accountExpires = DirectoryEntryHelper.GetAdObjectProperty(directoryEntry, "accountExpires");
  2. var asLong = ConvertLargeIntegerToLong(accountExpires);
  3.  
  4. if (asLong == long.MaxValue || asLong <= 0 || DateTime.MaxValue.ToFileTime() <= asLong)
  5. {
  6.   return DateTime.MaxValue;
  7. }
  8. else
  9. {
  10.   return DateTime.FromFileTimeUtc(asLong);
  11. }

May 4th, 2010 10:58 pm | Comments (1)

Active Directory Tip #3 – Get DirectoryEntry Property with range fetch

by Tobias Hertkorn on May 2nd, 2010

Tip #2 already dealt with one of the problems while using multi-value properties.But there is another pitfall that got me once - and usually only happens in production environments and is very hard to debug. I am talking about property range fetch a mechanism introduced to allow the active directory server to use certain optimizations. Unfortunatelly the optimization means a harder to understand API and more work for us programmer.

When dealing with multi-value properties with a huge number of values the active directory server will only return a certain amount of values on the first access (usually 1500 items). On some properties these values don't have an order so that there is a certain randomness to which values are returned - and therefore a certain randomness if your code works as expected or not. Which makes spotting the problem so hard.

So instead of relying on the fact that directoryEntry.Properties["member"] will return all values one must use the range fetch method using DirectorySearcher in order to get all values for said property. In the code sample below I used a cutoff value to determine if simple access should be trusted or if range fetch (slower) must be used.

C#:
  1. public static readonly int ATTRIBUTE_RANGE_FETCH_CUTOFF = 500;
  2.  
  3. public static List<object> GetAdObjectProperties(DirectoryEntry entry, string propertyName)
  4. {
  5.   if (entry == null) { throw new ArgumentNullException("entry"); }
  6.   if (string.IsNullOrEmpty(propertyName)) { throw new ArgumentException("propertyName"); }
  7.  
  8.   List<object> result = new List<object>();
  9.  
  10.   if (entry.Properties.Contains(propertyName))
  11.   {
  12.     int count = entry.Properties[propertyName].Count;
  13.  
  14.     if (count == 0)
  15.     {
  16.       // Nothing to do.
  17.     }
  18.     if (count == 1)
  19.     {
  20.       result.Add(entry.Properties[propertyName].Value.ToString());
  21.     }
  22.     else if (count <ATTRIBUTE_RANGE_FETCH_CUTOFF)
  23.     {
  24.       foreach (object value in entry.Properties[propertyName])
  25.       {
  26.         result.Add(value.ToString());
  27.       }
  28.     }
  29.     else
  30.     {
  31.       return GetAdObjectPropertiesWithRangeFetch(entry, propertyName);
  32.     }
  33.   }
  34.  
  35.   return result;
  36. }
  37.  
  38. private static List<object> GetAdObjectPropertiesWithRangeFetch(DirectoryEntry entry, string propertyName)
  39. {
  40.   List<object> result = new List<object>();
  41.   int index = 0;
  42.  
  43.   int step = entry.Properties[propertyName].Count - 1;
  44.   string rangeFormatString = propertyName + ";range={0}-{1}";
  45.  
  46.   string currentRange = string.Format(rangeFormatString, 0, step);
  47.  
  48.   using (DirectorySearcher searcher = new DirectorySearcher(entry, string.Format("({0}=*)", propertyName), new string[] { currentRange }, SearchScope.Base))
  49.   {
  50.     SearchResult searchResult = FindCurrentRange(searcher, currentRange);
  51.  
  52.     while ((searchResult != null) && searchResult.Properties.Contains(currentRange))
  53.     {
  54.       foreach (object item in searchResult.Properties[currentRange])
  55.       {
  56.         if (item != null)
  57.         {
  58.           result.Add(item);
  59.         }
  60.         index++;
  61.       }
  62.  
  63.       currentRange = string.Format(rangeFormatString, index, (index + step));
  64.  
  65.       searchResult = FindCurrentRange(searcher, currentRange);
  66.     }
  67.  
  68.     if (searchResult != null)
  69.     {
  70.       // final search with '*' as upper limit
  71.       string finalRange = string.Format(rangeFormatString, index, "*");
  72.       searchResult = FindCurrentRange(searcher, finalRange);
  73.  
  74.       foreach (object item in searchResult.Properties[finalRange])
  75.       {
  76.         if (item != null)
  77.         {
  78.           result.Add(item);
  79.         }                 
  80.       }
  81.     }
  82.  
  83.     return result;
  84.   }
  85. }
  86.  
  87. private static SearchResult FindCurrentRange(DirectorySearcher searcher, string currentRange)
  88. {
  89.   searcher.PropertiesToLoad.Clear();
  90.   searcher.PropertiesToLoad.Add(currentRange);
  91.  
  92.   SearchResult searchResult = searcher.FindOne();
  93.   return searchResult;
  94. }

May 2nd, 2010 10:55 pm | Comments (1)

Active Directory Tip #2 – Get DirectoryEntry Property as object list

by Tobias Hertkorn on April 30th, 2010

Even when you have a directory entry, it's not very easy to interact with it. Especially using the Properties property of the DirectoryEntry class is not as intuitive as I wish it would be. It either acts as a List, when there are more than one value to return, or it acts as a single value property when there is only one value currently set. That means accessing multi value ad properties like the url property through directoryEntry.Properties will act differently depending on how many values are actually set on the active directory entry.

To be save from these kinds of edge-cases it is best to not directly use the Properties property, but instead use a helper function. That way it always behaves like a list.

C#:
  1. public static List<object> GetAdObjectProperties(DirectoryEntry entry, string propertyName)
  2. {
  3.   if (entry == null) { throw new ArgumentNullException("entry"); }
  4.   if (string.IsNullOrEmpty(propertyName)) { throw new ArgumentException("propertyName"); }
  5.  
  6.   List<object> result = new List<object>();
  7.  
  8.   if (entry.Properties.Contains(propertyName))
  9.   {
  10.     int count = entry.Properties[propertyName].Count;
  11.  
  12.     if (count == 0)
  13.     {
  14.       // nothing to do
  15.     }
  16.     else if (count == 1)
  17.     {
  18.       result.Add(entry.Properties[propertyName].Value);
  19.     }
  20.     else
  21.     {
  22.       foreach (object value in entry.Properties[propertyName])
  23.       {
  24.         result.Add(value);
  25.       }
  26.     }
  27.   }
  28.  
  29.   return result;
  30. }

Unfortunatelly this is not all that needs to be observed while reading properties. Make sure to check out Tip #3 to find out more.

April 30th, 2010 10:54 pm | Comments (0)

Active Directory Tip #1 – DirectoryEntry.Exists with authentication

by Tobias Hertkorn on April 28th, 2010

When checking, if an entry in the Active Directory exists, usually I would use the static DirectoryEntry.Exists method. Unfortunatelly it does not provide an overload that lets me specify an username and password. But that's easily fixed. Just check for the error code "no such object" in the COMException that is thrown in case of a Ldap path that points to no existing object.

C#:
  1. public static bool Exists(string ldapPath, string username, string password)
  2. {
  3.   return GetDirectoryEntry(ldapPath, username, password) != null;
  4. }
  5.  
  6. private static readonly int ERROR_DS_NO_SUCH_OBJECT =  -2147016656;
  7.  
  8. public static DirectoryEntry GetDirectoryEntry(string ldapPath, string username, string password)
  9. {
  10.   DirectoryEntry de = new DirectoryEntry();
  11.   de.Path = ldapPath;
  12.   de.Username = username;
  13.   de.Password = password;
  14.   de.AuthenticationType = AuthenticationTypes.Secure;
  15.  
  16.   try
  17.   {
  18.     if (de.NativeObject == null)
  19.     {
  20.       // No AD object found!
  21.       de.Close();
  22.       de = null;
  23.     }
  24.   }
  25.   catch (COMException exception)
  26.   {
  27.     // 0x80072030 ERROR_DS_NO_SUCH_OBJECT
  28.     // http://msdn.microsoft.com/en-us/library/aa746386.aspx
  29.     if (exception.ErrorCode != ERROR_DS_NO_SUCH_OBJECT)
  30.     {
  31.       throw;
  32.     }
  33.     de.Close();
  34.     de = null;
  35.   }
  36.  
  37.   return de;
  38. }

April 28th, 2010 10:59 pm | Comments (2)

Active Directory Tips – The series

by Tobias Hertkorn on April 28th, 2010

I am currently digging into old automation code for active directory object CRUD. Unfortunatelly there are certain pitfalls and weird edge-cases surrounding the use of DirectoryEntry. So in order to save me the research in future projects and maybe help you I am starting a small series focusing on those pitfalls and edge-cases. I call them "tips" because it will be mostly code and less explanation of the code. Feel free to use the comments if you have further questions concerning the code. Just remember: If you have a question chances are somebody wants the answer as well.

April 28th, 2010 10:51 pm | Comments (0)

Part 3: Adding a dynamic decorator to an object – the “Why not”

by Tobias Hertkorn on December 21st, 2009

Krzysztof pointed me to his post Castle Dynamic Proxy FAQ: why there’s no "class proxy with target" why the dynamic decorator is not part of Castles's DynamicProxy implementation yet.

Looking at the code one realizes that the real problem is, that IsAdult() is not virtual. That's why the decorator is not able to intercept and redirect that call to the target. There is no way around it - that is a real bug and it does show why a class proxy with a target is indeed dangerous. Thanks for pointing it out to me, Krzysztof!

The question we have to ask now is: If we refuse to generate the proxy, if any member more visible than protected is non-virtual, would that get rid of the bug? I would argue that it will, since the proxy will now be able to redirect the call to the target and everything works out fine. Or am I again missing something?

December 21st, 2009 6:44 pm | Comments (0)

Part 2: Adding a dynamic decorator to an object – the “Why”

by Tobias Hertkorn on December 20th, 2009

I got the question "Why would we do that, we can't guarantee that nobody would use the original reference to manipulate stuff."

Well, this question is answered best by an example.

Imagine an object with a complicated creation and/hydration path. We are in a multithreaded environment and the object is passed between theads often, etc. There are two approaches to ensure that on has no data corruption because of multi threading. Either locking or immutability. Immutability is a strong feature but usually it is quite clumsy to use. Especially since with purely immutable objects there can be a lot of memory pressure with all the copying and creating of objects. Think "creating a complex immutable tree".

A solution to circumvent the memory pressure is to have a mutable object during creation and marking it as immutable after it is fully hydrated. This usually leads in C# to code similar to this:

C#:
  1. public class MyImmutable
  2. {
  3.     private string m_property;
  4.     public string Property
  5.     {
  6.         get { return m_property; }
  7.         set
  8.         {
  9.             if (m_immutable) { throw new MemberAccessException("Type is marked as immutable"); }
  10.             m_property = value;
  11.         }
  12.     }
  13.  
  14.     private bool m_immutable = false;
  15.     public void MarkAsImmutable()
  16.     {
  17.         m_immutable = true;
  18.     }
  19. }
  20.  
  21. public class MyImmutableFactory
  22. {
  23.     public MyImmutable CreateMyImmutable()
  24.     {
  25.         MyImmutable myImmutable = new MyImmutable();
  26.         myImmutable.Property = "Test";
  27.  
  28.         myImmutable.MarkAsImmutable();
  29.  
  30.         return myImmutable;
  31.     }
  32. }
  33.  
  34. public static class ImmutableOldStyleTest
  35. {
  36.     public static void Test()
  37.     {
  38.         MyImmutableFactory myImmutableFactory = new MyImmutableFactory();
  39.         MyImmutable myImmutable = myImmutableFactory.CreateMyImmutable();
  40.  
  41.         bool caughtException = false;
  42.         try
  43.         {
  44.             myImmutable.Property = "Test2";
  45.         }
  46.         catch (MemberAccessException)
  47.         {
  48.             caughtException = true;
  49.         }
  50.  
  51.         Debug.Assert(caughtException);
  52.         Debug.Assert(myImmutable.Property == "Test");
  53.     }
  54. }

For each set it is the programmer's resposibility to check within the setter, if it may or may not proceed with the setting of the value. Which can be quite tiring for multiple properties (DRY for the check!) and multiple immutable types (DRY for the MarkAsImmutable() method).

An alterative approach would be to use a decorator:

C#:
  1. public class ImmutableInterceptor : IInterceptor<MyType>
  2. {
  3.     public void InterceptGetter(IProxy proxy, MyType @object, string propertyName, out object value)
  4.     {
  5.         proxy.ProceedGetter(propertyName, out value);
  6.     }
  7.  
  8.     public void InterceptSetter(IProxy proxy, MyType @object, string propertyName, object value)
  9.     {
  10.         throw new MemberAccessException("Type is marked as immutable");
  11.     }
  12. }
  13.  
  14. public class MyTypeFactory
  15. {
  16.     public MyType CreateMyType()
  17.     {
  18.         MyType myType = new MyType();
  19.         myType.Property = "Test";
  20.  
  21.         return MarkAsImmutable(myType);
  22.     }
  23.  
  24.     private MyType MarkAsImmutable(MyType myType)
  25.     {
  26.         ImmutableInterceptor immutableInterceptor = new ImmutableInterceptor();
  27.  
  28.         return GenerateProxy(myType, immutableInterceptor);
  29.     }
  30.  
  31.     // This method belongs in a proxy generator
  32.     private static MyType GenerateProxy(MyType myType, IInterceptor<MyType> interceptor)
  33.     {
  34.         return new MyTypeProxy(myType, interceptor);
  35.     }
  36. }
  37.  
  38. public static class ImmutableTest
  39. {
  40.     public static void Test()
  41.     {
  42.         MyTypeFactory myTypeFactory = new MyTypeFactory();
  43.         MyType myType = myTypeFactory.CreateMyType();
  44.  
  45.         bool caughtException = false;
  46.         try
  47.         {
  48.             myType.Property = "Test2";
  49.         }
  50.         catch (MemberAccessException)
  51.         {
  52.             caughtException = true;
  53.         }
  54.  
  55.         Debug.Assert(caughtException);
  56.         Debug.Assert(myType.Property == "Test");
  57.     }
  58. }

Way more straight forward, isn't it?

Another application could be the old INotifyPropertyChanged problem, read-only collections, ...

December 20th, 2009 6:03 pm | Comments (0)

Adding a dynamic decorator to an object

by Tobias Hertkorn on December 19th, 2009

I am really confused that non of the dynamic proxy frameworks out there allow me to add dynamic behavior after the fact - I have an instantiated object and need to add behavior when a property is accessed. Like this:

C#:
  1. var myType = new MyType();
  2. myType.Property = "Test";
  3.  
  4. var interceptor = new MyInterceptor();
  5. MyType wrappedMyType = proxyGenerator.GenerateProxy(myType, interceptor);
  6. wrappedMyType.Property = "Test2";
  7.  
  8. Debug.Assert(myType.Property == "Test2");
  9. Debug.Assert(interceptor.SetterWasCalled);

All current frameworks need me to instantiate the object using the proxy generator. Which is unfortunate, because, unlike in the example, I plan to introduce the decorator in a part of my application that is conceptionally in a completely different region of the application's source code. It would just not make sense to introduce the knowledge about the additional behavior at the point of object creation.

It should be fairly easy to pull off, since I am already able to do it by hand:

C#:
  1. public class MyInterceptor : IInterceptor<MyType>
  2. {
  3.     public void InterceptGetter(IProxy proxy, MyType @object, string propertyName, out object value)
  4.     {
  5.         // do something before get
  6.         proxy.ProceedGetter(propertyName, out value);
  7.         // do something after get
  8.     }
  9.  
  10.     public void InterceptSetter(IProxy proxy, MyType @object, string propertyName, object value)
  11.     {
  12.         // do something before set
  13.         proxy.ProceedSetter(propertyName, value);
  14.         // do something after set
  15.         m_setterCalled = true;
  16.     }
  17.  
  18.     private bool m_setterCalled = false;
  19.     public bool SetterWasCalled
  20.     {
  21.         get { return m_setterCalled; }
  22.     }
  23. }
  24.  
  25. public class MyType
  26. {
  27.     public virtual string Property { get; set; }
  28. }
  29.  
  30. /////// AUTOGENERATED PROXY ///////
  31.  
  32. public class MyTypeProxy : MyType, IProxy
  33. {
  34.     private MyType m_object;
  35.     private IInterceptor<MyType> m_interceptor;
  36.  
  37.     public MyTypeProxy(MyType @object, IInterceptor<MyType> interceptor)
  38.     {
  39.         m_object = @object;
  40.         m_interceptor = interceptor;
  41.     }
  42.  
  43.     public override string Property
  44.     {
  45.         get
  46.         {
  47.             object value;
  48.             m_interceptor.InterceptGetter(this, m_object, "Property", out value);
  49.             return (string)value;
  50.         }
  51.         set { m_interceptor.InterceptSetter(this, m_object, "Property", value); }
  52.     }
  53.  
  54.     public void ProceedGetter(string propertyName, out object value)
  55.     {
  56.         if (propertyName == "Property")
  57.         {
  58.             value = m_object.Property;
  59.         }
  60.         else
  61.         {
  62.             throw new MissingMemberException();
  63.         }
  64.     }
  65.  
  66.     public void ProceedSetter(string propertyName, object value)
  67.     {
  68.         if (propertyName == "Property")
  69.         {
  70.             m_object.Property = (string)value;
  71.         }
  72.         else
  73.         {
  74.             throw new MissingMemberException();
  75.         }
  76.     }
  77. }
  78.  
  79. /////// SUPPORTING CODE ///////
  80.  
  81. public interface IProxy
  82. {
  83.     void ProceedGetter(string propertyName, out object value);
  84.     void ProceedSetter(string propertyName, object value);
  85. }
  86.  
  87. public interface IInterceptor<T>
  88. {
  89.     void InterceptGetter(IProxy proxy, T @object, string propertyName, out object value);
  90.     void InterceptSetter(IProxy proxy, T @object, string propertyName, object value);
  91. }
  92.  
  93. /////// TEST ///////
  94.  
  95. public static class Test
  96. {
  97.     public static void ProxyTest()
  98.     {
  99.         var myType = new MyType();
  100.         myType.Property = "Test";
  101.  
  102.         var interceptor = new MyInterceptor();
  103.         MyType wrappedMyType = GenerateProxy(myType, interceptor);
  104.         wrappedMyType.Property = "Test2";
  105.  
  106.         Debug.Assert(myType.Property == "Test2");
  107.         Debug.Assert(interceptor.SetterWasCalled);
  108.     }
  109.  
  110.     // This method belongs in a proxy generator
  111.     private static MyType GenerateProxy(MyType myType, IInterceptor<MyType> interceptor)
  112.     {
  113.         return new MyTypeProxy(myType, interceptor);
  114.     }
  115. }

Who will help me to adapt the API to the Castle DynamicProxy API and to write the actual proxy/decorator generation? :)

December 19th, 2009 6:01 pm | Comments (3)

Silverlight 4 Beta released

by Tobias Hertkorn on November 18th, 2009

AWESOME. This just made my day:

Silverlight 4 beta

This sounds like a great release that smoothes the edges around ADO, out of browser and code reuse between WPF and Silverlight. That's HUGE!

Plus PRINTING! Finally. And the mic and webcam features are nothing to sneeze at either. The list goes on and on. Seriously, they really packed a lot of stuff in. And it seems to be all community feedback driven. They really listened to us over at uservoice. 8 out of the top 10 features actually made it into that release. Great work!

Enjoy!

November 18th, 2009 9:35 pm | Comments (0)
Tobi + C# = T# - Blogged blogoscoop