.NET 中获取 AD 上帐号密码过期时间

using System;
using System.DirectoryServices;
using System.Runtime.InteropServices;

namespace AdDemo
{
public enum LoginResult
{
OK,
NotExist,
Inactive,
Incorrect
}

public abstract class AdEntry : MarshalByRefObject, IDisposable
{
private readonly DirectoryEntry _entry;

private bool _autoCommit = false;

protected AdEntry(DirectoryEntry entry)
{
_entry = entry;
}

public DirectoryEntry CurrentEntry
{
get
{
return _entry;
}
}

public bool AutoCommit
{
get
{
return _autoCommit;
}
set
{
_autoCommit = value;
}
}

public PropertyCollection Properties
{
get
{
return _entry.Properties;
}
}

public Uri URI
{
get
{
return new Uri(_entry.Path);
}
}

public String Path
{
get
{
return _entry.Path;
}
}

// 在 .NET 中访问 INTEGER8 类型必须通过 IADsLargeInteger 接口
// http://www.dotnet247.com/247reference/msgs/31/159934.aspx
[ComImport]
[Guid("9068270B-0939-11D1-8BE1-00C04FD8D503")]
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
internal interface IADsLargeInteger
{
[DispId(0x00000002)] int HighPart{get; set;}
[DispId(0x00000003)] int LowPart{get; set;}
}

internal long GetLongValue(IADsLargeInteger value)
{
// 将 IADsLargeInteger 内容转换为 long 之前必须小心溢出
// http://www.rlmueller.net/Integer8Discussion.htm
return (long)(((ulong)value.HighPart << 32) + (ulong)value.LowPart);
}


public void Commit()
{
_entry.CommitChanges();
}

public void Refresh()
{
if(_autoCommit) Commit();

_entry.RefreshCache();
}

public object Invoke(string methodName, params object[] args)
{
return _entry.Invoke(methodName, args);
}

#region IDisposable Members

public void Dispose()
{
if(_autoCommit) Commit();

_entry.Close();
}

#endregion
}

public abstract class AdItem : AdEntry
{
private readonly AdServer _srv;

internal AdItem(AdServer srv, DirectoryEntry entry) : base(entry)
{
_srv = srv;
}

public AdServer Server
{
get
{
return _srv;
}
}
}

public class AdUser : AdItem
{
///
/// 用户属性定义标志
///
public enum ADS_USER_FLAG_ENUM
{
///
/// 登录脚本标志。如果通过 ADSI LDAP 进行读或写操作时,该标志失效。如果通过 ADSI WINNT,该标志为只读。
///
ADS_UF_SCRIPT = 0X0001,

///
/// 用户帐号禁用标志
///
ADS_UF_ACCOUNTDISABLE = 0X0002,

///
/// 主文件夹标志
///
ADS_UF_HOMEDIR_REQUIRED = 0X0008,

///
/// 过期标志
///
ADS_UF_LOCKOUT = 0X0010,

///
/// 用户密码不是必须的
///
ADS_UF_PASSWD_NOTREQD = 0X0020,

///
/// 密码不能更改标志
///
ADS_UF_PASSWD_CANT_CHANGE = 0X0040,

///
/// 使用可逆的加密保存密码
///
ADS_UF_ENCRYPTED_TEXT_PASSWORD_ALLOWED = 0X0080,

///
/// 本地帐号标志
///
ADS_UF_TEMP_DUPLICATE_ACCOUNT = 0X0100,

///
/// 普通用户的默认帐号类型
///
ADS_UF_NORMAL_ACCOUNT = 0X0200,

///
/// 跨域的信任帐号标志
///
ADS_UF_INTERDOMAIN_TRUST_ACCOUNT = 0X0800,

///
/// 工作站信任帐号标志
///
ADS_UF_WORKSTATION_TRUST_ACCOUNT = 0x1000,

///
/// 服务器信任帐号标志
///
ADS_UF_SERVER_TRUST_ACCOUNT = 0X2000,

///
/// 密码永不过期标志
///
ADS_UF_DONT_EXPIRE_PASSWD = 0X10000,

///
/// MNS 帐号标志
///
ADS_UF_MNS_LOGON_ACCOUNT = 0X20000,

///
/// 交互式登录必须使用智能卡
///
ADS_UF_SMARTCARD_REQUIRED = 0X40000,

///
/// 当设置该标志时,服务帐号(用户或计算机帐号)将通过 Kerberos 委托信任
///
ADS_UF_TRUSTED_FOR_DELEGATION = 0X80000,

///
/// 当设置该标志时,即使服务帐号是通过 Kerberos 委托信任的,敏感帐号不能被委托
///
ADS_UF_NOT_DELEGATED = 0X100000,

///
/// 此帐号需要 DES 加密类型
///
ADS_UF_USE_DES_KEY_ONLY = 0X200000,

///
/// 不要进行 Kerberos 预身份验证
///
ADS_UF_DONT_REQUIRE_PREAUTH = 0X4000000,

///
/// 用户密码过期标志
///
ADS_UF_PASSWORD_EXPIRED = 0X800000,

///
/// 用户帐号可委托标志
///
ADS_UF_TRUSTED_TO_AUTHENTICATE_FOR_DELEGATION = 0X1000000

}


internal AdUser(AdServer srv, DirectoryEntry entry) : base(srv, entry)
{
}

public int UserAccountControl
{
get
{
return Convert.ToInt32(Properties["userAccountControl"][0]);
}
}

public bool Enabled
{
get
{
return (UserAccountControl & (int)ADS_USER_FLAG_ENUM.ADS_UF_ACCOUNTDISABLE) == 0;
}
}

public bool IsPasswordNotExpire
{
get
{
return (UserAccountControl & (int)ADS_USER_FLAG_ENUM.ADS_UF_DONT_EXPIRE_PASSWD) != 0;
}
}

public string DistinguishedName
{
get
{
return (string)Properties["distinguishedName"].Value;
}
}

public DateTime PasswordLastChanged
{
get
{
return DateTime.FromFileTime(GetLongValue((IADsLargeInteger)Properties["pwdLastSet"][0]));
}
}

// http://msdn.microsoft.com/library/en-us/dnclinic/html/scripting09102002.asp
public DateTime PasswordExpirationDate
{
get
{
if(IsPasswordNotExpire)
{
return DateTime.MaxValue; // 帐号被设置为密码永不过期
}
else
{
long lastChanged;

try
{
lastChanged = GetLongValue((IADsLargeInteger)Properties["pwdLastSet"][0]);
}
catch(Exception)
{
return DateTime.MinValue; // 密码没有被设置过
}

IADsLargeInteger maxAge = (IADsLargeInteger)Server.Properties["maxPwdAge"][0];

if(maxAge.LowPart == 0)
return DateTime.MaxValue; // 域中密码没有设置最大有效期限
else
return PasswordLastChanged.AddDays(Server.MaxPasswordDays);
}
}
}

public void ChangePassword(string oldPassword, string newPassword)
{
CurrentEntry.Invoke("ChangePassword", new Object[] {oldPassword, newPassword});

if(AutoCommit) Commit();
}

public void Attach(AdGroup group)
{
group.Add(this);
}

public void Detach(AdGroup group)
{
group.Remove(this);
}

public AdGroup[] Groups
{
get
{
PropertyValueCollection memberOfs = Properties["memberOf"];

AdGroup[] groups = new AdGroup[memberOfs.Count];

for(int i=0; i<groups.Length; i++)
{
groups[i] = new AdGroup(Server, Server.GetDirectoryEntry(memberOfs[i].ToString()));
}
return groups;
}
}
}

public class AdGroup : AdItem
{
internal AdGroup(AdServer srv, DirectoryEntry entry) : base(srv, entry)
{
}

public void Add(AdUser user)
{
Properties["member"].Add(user.DistinguishedName);

if(AutoCommit) Commit();
if(user.AutoCommit) user.Commit();
}

public void Remove(AdUser user)
{
Properties["member"].Remove(user.DistinguishedName);

if(AutoCommit) Commit();
if(user.AutoCommit) user.Commit();
}

public bool Contain(AdUser user)
{
return (bool)Invoke("IsMember", new Object[] { user.Path });
}
}

public class AdServer : AdEntry
{
public AdServer(string path, string username, string password, AuthenticationTypes authenticationType)
: base(new DirectoryEntry(path, username, password, authenticationType))
{
}

public AdServer(string path, string username, string password)
: base(new DirectoryEntry(path, username, password))
{
}

public AdServer(string path)
: base(new DirectoryEntry(path))
{
}

public String Username
{
get
{
return CurrentEntry.Username;
}
}

public String Password
{
get
{
return CurrentEntry.Password;
}
}

public AuthenticationTypes AuthenticationType
{
get
{
return CurrentEntry.AuthenticationType;
}
}

private static readonly int ONE_HUNDRED_NANOSECOND = 10000000;
private static readonly int SECONDS_IN_DAY = 86400;

public int MaxPasswordDays
{
get
{
long maxAge = GetLongValue((IADsLargeInteger)Properties["maxPwdAge"][0]);

return -(int)(maxAge / ONE_HUNDRED_NANOSECOND / SECONDS_IN_DAY);
}
}

public LoginResult LoginByAccountName(string accountName, string password)
{
AdUser user = FindUserByAccountName(accountName);

if(user == null)
return LoginResult.NotExist;
else if(!user.Enabled)
return LoginResult.Inactive;
else if(GetDirectoryEntry(user.Path, accountName, password) == null)
return LoginResult.Incorrect;
else
return LoginResult.OK;
}

public LoginResult Login()
{
return LoginByAccountName(Username, Password);
}

public DirectoryEntry GetDirectoryEntry(string path, string username, string password)
{
Uri uri = URI;

if(path.StartsWith(uri.Scheme.ToUpper()))
return new DirectoryEntry(path, username, password, AuthenticationType);
else
return new DirectoryEntry(uri.Scheme.ToUpper() + Uri.SchemeDelimiter +
uri.Host + "/" + path, username, password, AuthenticationType);
}

public DirectoryEntry GetDirectoryEntry(string path)
{
return GetDirectoryEntry(path, Username, Password);
}

public AdGroup FindGroup(string groupName, SearchScope scope)
{
DirectorySearcher searcher = new DirectorySearcher(CurrentEntry);

searcher.Filter = string.Format("(&(objectClass=group)(cn={0}))", groupName);
searcher.SearchScope = scope;

SearchResult ret = searcher.FindOne();

return ret == null ? null : new AdGroup(this, GetDirectoryEntry(ret.Path));
}

public AdGroup FindGroup(string groupName)
{
return FindGroup(groupName, SearchScope.Subtree);
}

public AdUser FindUserByCommonName(string commonName, SearchScope scope)
{
DirectorySearcher searcher = new DirectorySearcher(CurrentEntry);

searcher.Filter = string.Format("(&(&(objectCategory=person)(objectClass=user))(cn={0}))", commonName);
searcher.SearchScope = scope;

SearchResult ret = searcher.FindOne();

return ret == null ? null : new AdUser(this, GetDirectoryEntry(ret.Path));
}

public AdUser FindUserByCommonName(string commonName)
{
return FindUserByCommonName(commonName, SearchScope.Subtree);
}

public AdUser FindUserByAccountName(string accountName, SearchScope scope)
{
DirectorySearcher searcher = new DirectorySearcher(CurrentEntry);

searcher.Filter = string.Format("(&(&(objectCategory=person)(objectClass=user))(sAMAccountName={0}))", accountName);
searcher.SearchScope = scope;

SearchResult ret = searcher.FindOne();

return ret == null ? null : new AdUser(this, GetDirectoryEntry(ret.Path));
}

public AdUser FindUserByAccountName(string accountName)
{
return FindUserByAccountName(accountName, SearchScope.Subtree);
}

public bool IsUserExists(string commonName)
{
return FindUserByCommonName(commonName) != null;
}

public bool IsAccountExists(string accountName)
{
return FindUserByAccountName(accountName) != null;
}
}
}

posted on 2006-08-11 00:13  hades  阅读(741)  评论(0)    收藏  举报

导航