System.DirectoryServices.AccountManagement.UserPrincipal Serialization

Español

You can’t serialize this Type, the first reason is simple: Doesn’t have [Serialize] attribute on the base classes, but more important it has a lot of dependencies on non-managed resources that has to be connected to this class. If you could serialize making some tricks the class would expect to connect to Active Directory on the client consumer side, and assuming that the class could connect then it will be non sense to send the class in the first place. It will be more easy that the final client create and connect to the class directly.

So if you need to serialize just “data” of this class like some info on the attributes of an user. The recommended way will be to implement a memento pattern.

When you had a lot of properties and you are not worried of a coupled internal constructor (for example when the class will be serialized for a .Net Web Service and that constructor will not be used on the client consumer side) you could use a internal constructor that get as an argument the original class like:

[Serialize]
public class UserInfo
{
  private string displayName;
  ...

  public UserInfo()
  {
  }

  internal UserInfo(UserPrincipal user)
  {
      this.displayName = user.DisplayName;
      ...
  }
}

This way you can use it in your return methods like this:

return new UserInfo(user);

Authentication with Active Directory from Forms Authentication

Español

There are two ways that .Net can use to do Active Directory Authentication and this are:

To make a “bind” to Active Directory using LDAP.
To use the Win32 Logon API.

If .Net 3.5 is available you can authenticate with this method:

private bool ValidateExternalUser(string username, string password)
{
    using(PrincipalContext context = new PrincipalContext(ContextType.Domain, _defaultDomain))
    {
          return context.ValidateCredentials(username, password, ContextOptions.Negociate);
    }
}

Before .Net 3.5 you can just bind with your own object:

public bool AuthenticateActiveDirectory(string Domain, string UserName, string Password)
{
    try
    {
          DirectoryEntry entry = new DirectoryEntry(”LDAP://” + Domain, UserName, Password);
          object nativeObject = entry.NativeObject;
        return true;
    }
    catch (DirectoryServicesCOMException) { return false; }
}

Using Win32 Logon API:

It’s very large and fortunately already documented here:
http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html

Another method that we can use when the authentication has to consider Active Directory or SAM local accounts is the following:

[SecurityCritical, DirectoryServicesPermission(SecurityAction.Assert, Unrestricted=true)]
public bool Validate(string userName, string password, ContextOptions connectionMethod)
{
    if ((userName != null) && (userName.Length == 0))
    {
        return false;
    }
    if ((this.contextType == ContextType.Domain) || (this.contextType == ContextType.ApplicationDirectory))
    {
        try
        {
            NetworkCredential creds = new NetworkCredential(userName, password);
            this.BindLdap(creds, connectionMethod);
            return true;
        }
        catch (LdapException exception)
        {
            if (exception.ErrorCode != ExceptionHelper.ERROR_LOGON_FAILURE)
            {
                throw;
            }
            return false;
        }
    }
    return this.BindSam(this.serverName, userName, password);
}

Final Conclusions:

The Win32 Logon API method may be is more verbose of all but has more capabilities like inform the reason behind a failed authentication like account expiration, or if the password has not been set, etc. If you don’t need this advanced behavior it’s recommended the 3.5 or just bind approach.

References:

http://stackoverflow.com/questions/290548/c-validate-a-username-and-password-against-active-directory
http://stackoverflow.com/questions/30861/authenticating-domain-users-with-system-directoryservices
http://archive.devx.com/security/articles/ps0602/ps0602-4.asp
http://support.microsoft.com/kb/316748/en-us
http://msdn.microsoft.com/en-us/library/ms180890(VS.80).aspx
http://www.adventuresindevelopment.com/2009/06/02/how-to-authenticate-a-user-in-active-directory-using-aspnet/
http://support.microsoft.com/kb/180548/en-us
http://www.pinvoke.net/default.aspx/advapi32/LogonUser.html