Note
Access to this page requires authorization. You can try signing in or changing directories.
Access to this page requires authorization. You can try changing directories.
Here is my repaired version of Jit Ghosh's AD/AM Membership Provider:
using System;
using System.Configuration;
using System.Web.Configuration;
using System.Configuration.Provider;
using System.Web.Security;
using System.DirectoryServices;
using System.Security.Cryptography;
using System.Text;
using System.IO;
namespace CustomProviders
{
/// <summary>
/// Implements a custom provier for the ASP.NET 2.0 Membership Service.
/// This provider uses Microsoft Active Directory Application Mode as the storage system for user information
/// </summary>
public class ADAMMembershipProvider: MembershipProvider
{
private string _Name = null;
private string _ADAMServerUri = "localhost";
private string _ADAMUserName = null;
private string _ADAMPassword = null;
private string _ADAMTopContainer = "CN=ASP.NET Security Provider";
private string _ADAMUserContainer = "CN=Users";
private bool _EnablePasswordRetrieval = false;
private bool _EnablePasswordReset = true;
private string _ApplicationName = null;
private bool _RequiresQuestionAndAnswer = false;
private bool _RequiresUniqueEMail = false;
private byte[] _DecryptionKey = null;
private byte[] _ValidationKey = null;
private MembershipPasswordFormat _PasswordFormat = MembershipPasswordFormat.Hashed;
private const int PAGEINDEX_NOPAGING = 1;
private const int PAGESIZE_NOPAGING = int.MaxValue;
//Filter formats for various LDAP queries
private const string _ADAMCommonName = "CN={0}";
private const string _ADAMGetAllUsersFilterAppSpecific = "(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserApplicationName={0}))";
private const string _ADAMUserSearchByUserNameFilterAppSpecific = "(&(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserApplicationName={0}))(aspnetmembershipuserUserName={1}))";
private const string _ADAMUserSearchByEmailFilterAppSpecific = "(&(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserApplicationName={0}))(aspnetmembershipuserEMail={1}))";
private const string _ADAMUserSearchByNameAndEmailFilterAppSpecific = "(&(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserApplicationName={0}))(&(aspnetmembershipuserUserName={1})(aspnetmembershipuserEMail={2})))";
private const string _ADAMCountUsersOnlineAppSpecific = "(&(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserApplicationName={0}))(aspnetmembershipuserLastActivityTimeStamp>={1:yyMMddHHmmss}Z))";
private const string _ADAMGetAllUsersFilter = "(objectClass=aspnetmembershipuser)";
private const string _ADAMUserSearchByUserNameFilter = "(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserUserName={0}))";
private const string _ADAMUserSearchByEmailFilter = "(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserEMail={0}))";
private const string _ADAMUserSearchByNameAndEmailFilter = "(&(objectClass=aspnetmembershipuser)(&(aspnetmembershipuserUserName={0})(aspnetmembershipuserEMail={1})))";
private const string _ADAMCountUsersOnline = "(&(objectClass=aspnetmembershipuser)(aspnetmembershipuserLastActivityTimeStamp>={0:yyMMddHHmmss}Z))";
private string _ADAMLDAPPathToUserContainer = null;
//Various ADAM Schema class and attribute name literals
private const string _ADAMUserObjectClass = "aspnetmembershipuser";
private const string _ADAMPropApplicationName = "aspnetmembershipuserApplicationName";
private const string _ADAMPropUserName = "aspnetmembershipuserUserName";
private const string _ADAMPropUserId = "aspnetmembershipuserUserId";
private const string _ADAMPropEMail = "aspnetmembershipuserEmail";
private const string _ADAMPropComment = "aspnetmembershipuserComment";
private const string _ADAMPropIsAnonymous = "aspnetmembershipuserIsAnonymous";
private const string _ADAMPropIsApproved = "aspnetmembershipuserIsApproved";
private const string _ADAMPropUserCreationTimestamp = "aspnetmembershipuserUserCreationTimeStamp";
private const string _ADAMPropLastActivityTimestamp = "aspnetmembershipuserLastActivityTimeStamp";
private const string _ADAMPropLastLoginTimestamp = "aspnetmembershipuserLastLoginTimeStamp";
private const string _ADAMPropLastPasswordChangeTimestamp = "aspnetmembershipuserLastPasswordChangeTimestamp";
private const string _ADAMPropPassword = "aspnetmembershipuserPassword";
private const string _ADAMPropPasswordQuestion = "aspnetmembershipuserPasswordQuestion";
private const string _ADAMPropPasswordAnswer = "aspnetmembershipuserPasswordAnswer";
private const string _ADAMPropPasswordFormat = "aspnetmembershipuserPasswordFormat";
private const string _ADAMPropPasswordSaltOrIV = "aspnetmembershipuserPasswordSaltOrIV";
public ADAMMembershipProvider()
{
}
public override string ResetPassword(string name, string answer)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
string RetVal = null;
try
{
//Cannot reset password if not enabled via configuration settings
if (_EnablePasswordReset == false)
throw new NotSupportedException("Current configuration settings do not allow resetting passwords");
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
throw new ApplicationException(string.Format("User {0} does not exist", name));
if (deMembershipUser != null)//user record found!!
{
deMembershipUser.RefreshCache();
//if configuration settings require a security question/answer protocol for passwords
//then the supplied answer parameter needs to match the stored password answer for the user
if (_RequiresQuestionAndAnswer && (deMembershipUser.Properties[_ADAMPropPasswordAnswer].Value == null || (string)deMembershipUser.Properties[_ADAMPropPasswordAnswer].Value != answer))
throw new ApplicationException("Password answer does not match");
//generate a new random password. I have chosen to use a 6 character password.
//It is advisable to make this a configuration setting as well
RetVal = Membership.GeneratePassword(6);
//convert password for storage per password format, and set the user record with the new password
deMembershipUser.Properties[_ADAMPropPassword].Value = this.ConvertPasswordForStorage(RetVal);
//record timestamp
deMembershipUser.Properties[_ADAMPropLastPasswordChangeTimestamp].Value = DateTime.UtcNow;
//save changes
deMembershipUser.CommitChanges();
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error resetting password", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
//return new password
return RetVal; ;
}
public override bool ChangePassword(string name, string oldPwd, string newPwd)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
try
{
//check for existence of user record
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
throw new ApplicationException(string.Format("User {0} does not exist", name));
if (deMembershipUser != null)//user record found!!
{
deMembershipUser.RefreshCache();
//check if the old password matches
if (!ComparePassword(oldPwd, (byte[])deMembershipUser.Properties[_ADAMPropPassword].Value))
throw new ApplicationException("Existing password does not match");
////convert password for storage per password format, and set the user record with the new password
deMembershipUser.Properties[_ADAMPropPassword].Value = ConvertPasswordForStorage(newPwd);
//record timestamp
deMembershipUser.Properties[_ADAMPropLastPasswordChangeTimestamp].Value = DateTime.UtcNow;
//save changes
deMembershipUser.CommitChanges();
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error changing password", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return true;
}
public override void UpdateUser(MembershipUser user)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
try
{
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, user.UserName) : string.Format(_ADAMUserSearchByUserNameFilter, user.UserName), deUserContainer, out deMembershipUser) == false)
throw new ApplicationException(string.Format("User {0} does not exist", user.UserName));
int Count = 0;
if (deMembershipUser != null)//user record found!!
{
deMembershipUser.RefreshCache();
//if requiresUniqueEmail is true, the update cannot specify an email that violates uniqueness
//if the email in the update is different than the original email in the user record, check to see if there
//is another user in the system with the same email
if (_RequiresUniqueEMail && deMembershipUser.Properties[_ADAMPropEMail].Value != user.Email
&& ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByEmailFilterAppSpecific, _ApplicationName, user.Email) : string.Format(_ADAMUserSearchByEmailFilter, user.Email), deUserContainer, out deMembershipUser) == true)
throw new ApplicationException(string.Format("A user with email {0} already exists", user.Email));
//set the user record with the updates
deMembershipUser.Properties[_ADAMPropUserName].Value = user.UserName;
deMembershipUser.Properties[_ADAMPropEMail].Value = user.Email;
//deMembershipUser.Properties[_ADAMPropComment].Value = user.Comment;
//deMembershipUser.Properties[_ADAMPropIsApproved].Value = user.IsApproved.ToString();
deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value = user.PasswordQuestion;
//save changes
deMembershipUser.CommitChanges();
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error updating User", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
}
public override MembershipUser CreateUser(string username, string password, string email, string passwordQuestion, string passwordAnswer, bool isApproved, out MembershipCreateStatus status)
{
MembershipUser NewUser = null;
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
status = MembershipCreateStatus.UserRejected;
try
{
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, username) : string.Format(_ADAMUserSearchByUserNameFilter, username), deUserContainer, out deMembershipUser) == true)
{
//if found, return error
status = MembershipCreateStatus.DuplicateUserName;
return null;
}
//check for duplicate email constraint
if (_RequiresUniqueEMail && ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByEmailFilterAppSpecific, _ApplicationName, email) : string.Format(_ADAMUserSearchByEmailFilter, email), deUserContainer, out deMembershipUser) == true)
{
//if violated return error
status = MembershipCreateStatus.DuplicateEmail;
return null;
}
//create new user id
Guid UserId = Guid.NewGuid();
DateTime TimeNow = DateTime.UtcNow;
//add the object. Set CN to the user id GUID. CN needs to be unique. This avoids conflicts around having same user names
//for multiple applications. Other alternative could be to use a concat to username and appname as CN
deMembershipUser = deUserContainer.Children.Add(string.Format(_ADAMCommonName, UserId.ToString()), _ADAMUserObjectClass);
//set other attributes
deMembershipUser.Properties[_ADAMPropUserId].Value = UserId.ToByteArray();
deMembershipUser.Properties[_ADAMPropUserName].Value = username;
deMembershipUser.Properties[_ADAMPropApplicationName].Value = _ApplicationName;
deMembershipUser.Properties[_ADAMPropPassword].Value = ConvertPasswordForStorage(password);
deMembershipUser.Properties[_ADAMPropEMail].Value = email;
deMembershipUser.Properties[_ADAMPropUserCreationTimestamp].Value = TimeNow;
deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value = passwordQuestion;
deMembershipUser.Properties[_ADAMPropPasswordAnswer].Value = passwordAnswer;
deMembershipUser.Properties[_ADAMPropIsApproved].Value = true;
//save changes
deMembershipUser.CommitChanges();
//create new instance of MembershipUser and return it
NewUser = new MembershipUser(this, username, UserId, email, null, null, true, (DateTime)deMembershipUser.Properties[_ADAMPropUserCreationTimestamp].Value, DateTime.Now, DateTime.Now, DateTime.Now);
status = MembershipCreateStatus.Success;
}
catch (Exception Ex)
{
status = MembershipCreateStatus.ProviderError;
NewUser = null;
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return NewUser;
}
public override bool EnablePasswordReset
{
get
{
return _EnablePasswordReset;
}
}
public override int GetNumberOfUsersOnline()
{
DirectoryEntry deUserContainer = null;
int Count = 0;
try
{
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
//search for all users where LastActivityTimeStamp >= TimeNow - UserIsOnlineTimeWindow
string Filter = (_ApplicationName != null) ? string.Format(_ADAMCountUsersOnlineAppSpecific, _ApplicationName, DateTime.UtcNow.AddMinutes(Convert.ToDouble(-1 * Membership.UserIsOnlineTimeWindow))) : string.Format(_ADAMCountUsersOnline, DateTime.UtcNow.AddMinutes(Convert.ToDouble(-1 * Membership.UserIsOnlineTimeWindow)));
ADAMFindUsers(Filter, deUserContainer, PAGEINDEX_NOPAGING, PAGESIZE_NOPAGING, out Count);
}
catch (Exception Ex)
{
throw;
}
finally
{
try
{
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
//return count
return Count;
}
public override bool ChangePasswordQuestionAndAnswer(string name, string password, string newPwdQuestion, string newPwdAnswer)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
try
{
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
throw new ApplicationException(string.Format("User {0} does not exist", name));
if (deMembershipUser != null)//user record found !!
{
deMembershipUser.RefreshCache();
//check if the old password matches
if (!ComparePassword(password, (byte[])deMembershipUser.Properties[_ADAMPropPassword].Value))
throw new ApplicationException("Existing password does not match");
//set properties and save changes
deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value = newPwdQuestion;
deMembershipUser.Properties[_ADAMPropPasswordAnswer].Value = newPwdAnswer;
deMembershipUser.CommitChanges();
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error changing password", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return true;
}
public override MembershipUser GetUser(string name, bool userIsOnline)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
try
{
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
throw new ApplicationException(string.Format("User {0} does not exist", name));
if (deMembershipUser != null)//user record found!!
{
//refresh the AD cache to load all attributes
deMembershipUser.RefreshCache();
//if the user is indicated to be online
if (userIsOnline)
{
//update the appropriate timestamp and save changes
deMembershipUser.Properties[_ADAMPropLastActivityTimestamp].Value = DateTime.UtcNow;
deMembershipUser.CommitChanges();
}
//return a new instance created from the retrieved user record
return this.ConstructMembershipUserFromDirectoryEntry(deMembershipUser);
/*
return new MembershipUser(this,
(string)deMembershipUser.Properties[_ADAMPropUserName].Value,
deMembershipUser.Properties[_ADAMPropUserId].Value == null ? string.Empty : (string)deMembershipUser.Properties[_ADAMPropUserId].Value,
deMembershipUser.Properties[_ADAMPropEMail].Value == null ? String.Empty : (string)deMembershipUser.Properties[_ADAMPropEMail].Value,
deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value == null ? String.Empty : (string)deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value,
deMembershipUser.Properties[_ADAMPropComment].Value == null ? String.Empty : (string)deMembershipUser.Properties[_ADAMPropComment].Value,
deMembershipUser.Properties[_ADAMPropIsApproved].Value == null ? false : (bool)deMembershipUser.Properties[_ADAMPropIsApproved].Value,
deMembershipUser.Properties[_ADAMPropUserCreationTimestamp].Value == null ? DateTime.Now : (DateTime)deMembershipUser.Properties[_ADAMPropUserCreationTimestamp].Value,
deMembershipUser.Properties[_ADAMPropLastLoginTimestamp].Value == null ? DateTime.Now : (DateTime)deMembershipUser.Properties[_ADAMPropLastLoginTimestamp].Value,
deMembershipUser.Properties[_ADAMPropLastActivityTimestamp].Value == null ? DateTime.Now : (DateTime)deMembershipUser.Properties[_ADAMPropLastActivityTimestamp].Value,
deMembershipUser.Properties[_ADAMPropLastPasswordChangeTimestamp].Value == null ? DateTime.Now : (DateTime)deMembershipUser.Properties[_ADAMPropLastPasswordChangeTimestamp].Value);
*/
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error getting user", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return null;
}
public override bool EnablePasswordRetrieval
{
get
{
return _EnablePasswordRetrieval;
}
}
public override string ApplicationName
{
get
{
return _ApplicationName;
}
set
{
_ApplicationName = value;
}
}
public override string GetUserNameByEmail(string email)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
string RetVal = null;
try
{
//find the user for this application with the specified email address
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByEmailFilterAppSpecific, _ApplicationName, email) : string.Format(_ADAMUserSearchByEmailFilter, email), deUserContainer, out deMembershipUser))
return null;
if (deMembershipUser != null)//user record found!!
{
//refresh the cache with the attribute values
deMembershipUser.RefreshCache();
//return user name
RetVal = (string)deMembershipUser.Properties[_ADAMPropUserName].Value;
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error retrieving user name", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return RetVal;
}
public override bool ValidateUser(string name, string password)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
bool RetVal = false;
try
{
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
RetVal = false;
if (deMembershipUser != null)//user record found!!
{
//refresh cache with attribute values
deMembershipUser.RefreshCache();
//compare supplied password with stored password(or hash of supplied password with the stored hash in case the password format is set to hashed)
RetVal = ComparePassword(password, (byte[])deMembershipUser.Properties[_ADAMPropPassword].Value);
DateTime TimeNow = DateTime.UtcNow;
//set appropriate timestamps
deMembershipUser.Properties[_ADAMPropLastLoginTimestamp].Value = TimeNow;
deMembershipUser.Properties[_ADAMPropLastActivityTimestamp].Value = TimeNow;
deMembershipUser.CommitChanges();
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error validating user", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
//return comparison result
return RetVal;
}
public override string GetPassword(string name, string answer)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
string RetVal = null;
try
{
//if password retrieval is disabled via configuration settings or the password format is set to hashed
//we cannot retriev the password
if (!_EnablePasswordRetrieval || _PasswordFormat == MembershipPasswordFormat.Hashed)
throw new ApplicationException("Current configuration settings do not allow password retrieval");
//check if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
throw new ApplicationException(string.Format("User {0} does not exist", name));
if (deMembershipUser != null)//user record found!!
{
//refresh cache with stored attributes
deMembershipUser.RefreshCache();
//if configuration settings demand a security question/answer protocol, the supplied password answer
//needs to match the stored password answer
if (_RequiresQuestionAndAnswer && (deMembershipUser.Properties[_ADAMPropPasswordAnswer].Value == null || (string)deMembershipUser.Properties[_ADAMPropPasswordAnswer].Value != answer))
throw new ApplicationException("Password answer does not match");
//decode password and return it
RetVal = GetReadablePassword((byte[])deMembershipUser.Properties[_ADAMPropPassword].Value);
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error retrieving password", Ex);
}
finally
{
try
{
deMembershipUser.Close();
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return RetVal;
}
public override bool DeleteUser(string name, bool deleteAllRelatedData)
{
DirectoryEntry deUserContainer = null;
DirectoryEntry deMembershipUser = null;
try
{
//check if user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
if (ADAMFindUser((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, name) : string.Format(_ADAMUserSearchByUserNameFilter, name), deUserContainer, out deMembershipUser) == false)
return false;
if (deMembershipUser != null)//user record found!!
{
//remove the record
deUserContainer.Children.Remove(deMembershipUser);
//save changes
deUserContainer.CommitChanges();
}
}
catch (Exception Ex)
{
throw new ApplicationException("Error deleting user", Ex);
}
finally
{
try
{
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return true;
}
public override bool RequiresQuestionAndAnswer
{
get
{
return _RequiresQuestionAndAnswer;
}
}
public override MembershipUserCollection FindUsersByEmail(string emailToMatch, int pageIndex, int pageSize, out int totalRecords)
{
totalRecords = 0;
DirectoryEntry deUserContainer = null;
MembershipUserCollection RetVal = null;
try
{
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
//get all the users or the nth page of users, and return the collection
RetVal = ADAMFindUsers((_ApplicationName != null) ? string.Format(_ADAMUserSearchByEmailFilterAppSpecific, _ApplicationName, emailToMatch) : string.Format(_ADAMUserSearchByEmailFilter, emailToMatch), deUserContainer, pageIndex, pageSize, out totalRecords);
}
catch (Exception Ex)
{
throw;
}
finally
{
try
{
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return RetVal;
}
public override MembershipUserCollection FindUsersByName(string usernameToMatch, int pageIndex, int pageSize, out int totalRecords)
{
totalRecords = 0;
DirectoryEntry deUserContainer = null;
MembershipUserCollection RetVal = null;
try
{
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
//find the users matching
RetVal = ADAMFindUsers((_ApplicationName != null) ? string.Format(_ADAMUserSearchByUserNameFilterAppSpecific, _ApplicationName, usernameToMatch) : string.Format(_ADAMUserSearchByUserNameFilter, usernameToMatch), deUserContainer, pageIndex, pageSize, out totalRecords);
}
catch (Exception Ex)
{
throw;
}
finally
{
try
{
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return RetVal;
}
public override MembershipUserCollection GetAllUsers(int pageIndex, int pageSize, out int totalRecords)
{
totalRecords = 0;
DirectoryEntry deUserContainer = null;
MembershipUserCollection RetVal = null;
try
{
//let's first see if the user exists
deUserContainer = (_ADAMUserName != null && _ADAMPassword != null) ? new DirectoryEntry(_ADAMLDAPPathToUserContainer, _ADAMUserName, _ADAMPassword) : new DirectoryEntry(_ADAMLDAPPathToUserContainer);
RetVal = ADAMFindUsers((_ApplicationName != null) ? string.Format(_ADAMGetAllUsersFilterAppSpecific, _ApplicationName) : _ADAMGetAllUsersFilter, deUserContainer, pageIndex, pageSize, out totalRecords);
}
catch (Exception Ex)
{
throw;
}
finally
{
try
{
deUserContainer.Close();
}
catch (Exception Ex)
{
}
}
return RetVal;
}
public override string Name
{
get
{
return _Name;
}
}
public override void Initialize(string name, System.Collections.Specialized.NameValueCollection config)
{
_Name = name;
try
{
if (config["server"] != null)
_ADAMServerUri = config["server"];
if (config["userName"] != null)
_ADAMUserName = config["userName"];
if (config["password"] != null)
_ADAMPassword = config["password"];
if (config["topContainer"] != null)
_ADAMTopContainer = config["topContainer"];
if (config["userContainer"] != null)
_ADAMUserContainer = config["userContainer"];
if (config["applicationName"] != null)
_ApplicationName = config["applicationName"];
if (config["enablePasswordRetrieval"] != null)
_EnablePasswordRetrieval = Convert.ToBoolean(config["enablePasswordRetrieval"].ToLower());
if (config["enablePasswordReset"] != null)
_EnablePasswordReset = Convert.ToBoolean(config["enablePasswordReset"].ToLower());
if (config["requiresQuestionAndAnswer"] != null)
_RequiresQuestionAndAnswer = Convert.ToBoolean(config["requiresQuestionAndAnswer"].ToLower());
if (config["requiresUniqueEMail"] != null)
_RequiresUniqueEMail = Convert.ToBoolean(config["requiresUniqueEMail"].ToLower());
if (config["passwordFormat"] != null)
{
switch (config["passwordFormat"].ToLower())
{
case "clear":
_PasswordFormat = MembershipPasswordFormat.Clear;
break;
case "hashed":
_PasswordFormat = MembershipPasswordFormat.Hashed;
break;
case "encrypted":
_PasswordFormat = MembershipPasswordFormat.Encrypted;
break;
default:
throw new ConfigurationException(string.Format("Unknown password format {0}. Supported password formats are Clear,Hashed or Encrypted", config["passwordFormat"]));
}
}
LoadKey(config);
}
catch (Exception Ex)
{
throw new System.Configuration.ConfigurationException("There was an error reading the membership configuration settings", Ex);
}
_ADAMLDAPPathToUserContainer = string.Format("LDAP://{0}/{1},{2}", _ADAMServerUri, _ADAMUserContainer, _ADAMTopContainer);
}
private void LoadKey(System.Collections.Specialized.NameValueCollection config)
{
if (_PasswordFormat != MembershipPasswordFormat.Clear)
{
//object section = ConfigurationSettings.GetConfig("system.web/machineKey");
//MachineKeySection machineKeySection = (MachineKeySection)section;
//MachineKeySection machineKeySection = (MachineKeySection)ConfigurationSettings.GetConfig("system.web/machineKey");
Configuration cfg = Configuration.GetWebConfiguration(System.Web.Hosting.HostingEnvironment.ApplicationVirtualPath);
MachineKeySection machineKeySection = (MachineKeySection)cfg.GetSection("system.web/machineKey");
switch (_PasswordFormat)
{
case MembershipPasswordFormat.Encrypted: //we need a symmetric key
if (!machineKeySection.DecryptionKey.ToLower().Contains("autogenerate"))
_DecryptionKey = HexStringToByteArray(machineKeySection.DecryptionKey);
else if (config["decryptionKey"] != null)
_DecryptionKey = HexStringToByteArray(config["decryptionKey"]);
else
throw new ConfigurationException("Symmetric key required to encrypt passwords. Are you missing a <decryptionKey> in your provider entry ?");
break;
case MembershipPasswordFormat.Hashed:
if (!machineKeySection.ValidationKey.ToLower().Contains("autogenerate"))
_ValidationKey = HexStringToByteArray(machineKeySection.ValidationKey);
else if (config["validationKey"] != null)
_ValidationKey = HexStringToByteArray(config["validationKey"]);
else
throw new ConfigurationException("Symmetric key required to hash passwords. Are you missing a <validationKey> in your provider entry ?");
break;
}
}
}
private MembershipUser ConstructMembershipUserFromDirectoryEntry(DirectoryEntry deMembershipUser)
{
object userName;
object userId;
object eMail;
object passwordQuestion;
string comment;
object isApproved;
object creationDate;
object lastLoginDate;
object lastActivityDate;
object lastPasswordChangedDate;
userName = deMembershipUser.Properties[_ADAMPropUserName].Value;
userId = deMembershipUser.Properties[_ADAMPropUserId].Value;
eMail = deMembershipUser.Properties[_ADAMPropEMail].Value;
passwordQuestion = deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value;
comment = string.Empty;
isApproved = deMembershipUser.Properties[_ADAMPropIsApproved].Value;
creationDate = deMembershipUser.Properties[_ADAMPropUserCreationTimestamp].Value;
lastLoginDate = deMembershipUser.Properties[_ADAMPropLastLoginTimestamp].Value;
lastActivityDate = deMembershipUser.Properties[_ADAMPropLastActivityTimestamp].Value;
lastPasswordChangedDate = deMembershipUser.Properties[_ADAMPropLastPasswordChangeTimestamp].Value;
userName = userName == null ? null : (string)userName;
userId = userId == null ? string.Empty : new Guid((byte[])userId).ToString(); ;
eMail = eMail == null ? null : (string)eMail;
passwordQuestion = passwordQuestion == null ? null : (string)passwordQuestion;
isApproved = isApproved == null ? false : (bool)isApproved;
creationDate = creationDate == null ? DateTime.Now : (DateTime)creationDate;
lastLoginDate = lastLoginDate == null ? DateTime.Now : (DateTime)lastLoginDate;
lastActivityDate = lastActivityDate == null ? DateTime.Now : (DateTime)lastActivityDate;
lastPasswordChangedDate = lastPasswordChangedDate == null ? DateTime.Now : (DateTime)lastPasswordChangedDate;
MembershipUser user = new MembershipUser(this, (string)userName, (string)userId, (string)eMail, (string)passwordQuestion, comment, (bool)isApproved, (DateTime)creationDate, (DateTime)lastLoginDate, (DateTime)lastActivityDate, (DateTime)lastPasswordChangedDate);
return user;
}
private MembershipUserCollection ADAMFindUsers(string Filter, DirectoryEntry SearchRoot, int PageIndex, int PageSize, out int Count)
{
Count = 0;
SearchResultCollection dsUserSearchResult = null;
MembershipUserCollection RetVal = new MembershipUserCollection();
DirectorySearcher dsUser = new DirectorySearcher(SearchRoot, Filter);
dsUser.SearchScope = SearchScope.OneLevel;
try
{
if ((dsUserSearchResult = dsUser.FindAll()) != null)
{
Count = dsUserSearchResult.Count;
if (PageSize == PAGESIZE_NOPAGING) PageSize = Count;
//int StartIndex = (PageIndex - 1) * PageSize;
int StartIndex = PageIndex * PageSize;
int EndIndex = ((PageIndex + 1) * PageSize) - 1;
if (EndIndex > (Count - 1))
{
EndIndex = Count - 1;
}
MembershipUser user;
DirectoryEntry deMembershipUser;
for (int Idx = StartIndex; Idx <= EndIndex; Idx++)
{
deMembershipUser = dsUserSearchResult[Idx].GetDirectoryEntry();
deMembershipUser.RefreshCache();
/*
userName = deMembershipUser.Properties[_ADAMPropUserName].Value;
userId = deMembershipUser.Properties[_ADAMPropUserId].Value;
eMail = deMembershipUser.Properties[_ADAMPropEMail].Value;
passwordQuestion = deMembershipUser.Properties[_ADAMPropPasswordQuestion].Value;
comment = string.Empty;
isApproved = deMembershipUser.Properties[_ADAMPropIsApproved].Value;
creationDate = deMembershipUser.Properties[_ADAMPropUserCreationTimestamp].Value;
lastLoginDate = deMembershipUser.Properties[_ADAMPropLastLoginTimestamp].Value;
lastActivityDate = deMembershipUser.Properties[_ADAMPropLastActivityTimestamp].Value;
lastPasswordChangedDate = deMembershipUser.Properties[_ADAMPropLastPasswordChangeTimestamp].Value;
userName = userName == null?null:(string)userName;
userId = userId == null?string.Empty:new Guid((byte[])userId).ToString();;
eMail = eMail == null?null:(string)eMail;
passwordQuestion = passwordQuestion == null?null:(string)passwordQuestion;
isApproved = isApproved == null?false:(bool)isApproved;
creationDate = creationDate == null?DateTime.Now:(DateTime)creationDate;
lastLoginDate = lastLoginDate == null?DateTime.Now:(DateTime)lastLoginDate;
lastActivityDate = lastActivityDate == null?DateTime.Now:(DateTime)lastActivityDate;
lastPasswordChangedDate = lastPasswordChangedDate == null?DateTime.Now:(DateTime)lastPasswordChangedDate;
user = new MembershipUser(this,(string)userName,(string)userId,(string)eMail,(string)passwordQuestion,comment,(bool)isApproved,(DateTime)creationDate,(DateTime)lastLoginDate,(DateTime)lastActivityDate,(DateTime)lastPasswordChangedDate);
*/
user = this.ConstructMembershipUserFromDirectoryEntry(deMembershipUser);
RetVal.Add(user);
deMembershipUser.Close();
}
}
return RetVal;
}
catch (Exception Ex)
{
throw new ApplicationException("Error retrieving users", Ex);
}
}
private bool ADAMFindUser(string Filter, DirectoryEntry SearchRoot, out DirectoryEntry deUser)
{
SearchResult dsUserSearchResult = null;
deUser = null;
DirectorySearcher dsUser = new DirectorySearcher(SearchRoot, Filter);
dsUser.SearchScope = SearchScope.OneLevel;
if ((dsUserSearchResult = dsUser.FindOne()) != null)
{
deUser = dsUserSearchResult.GetDirectoryEntry();
return true;
}
else
return false;
}
private string GetReadablePassword(byte[] StoredPassword)
{
System.Text.UnicodeEncoding ue = new System.Text.UnicodeEncoding();
string RetVal = null;
switch (_PasswordFormat)
{
case MembershipPasswordFormat.Clear:
RetVal = ue.GetString(StoredPassword);
break;
case MembershipPasswordFormat.Hashed:
throw new ApplicationException("Password cannot be recovered from a hashed format");
case MembershipPasswordFormat.Encrypted:
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
tripleDes.Key = _DecryptionKey;
tripleDes.IV = new byte[8];
CryptoStream cryptoStream = new CryptoStream(new MemoryStream(StoredPassword), tripleDes.CreateDecryptor(), CryptoStreamMode.Read);
MemoryStream msPasswordDec = new MemoryStream();
int BytesRead = 0;
byte[] Buffer = new byte[32];
while ((BytesRead = cryptoStream.Read(Buffer, 0, 32)) > 0)
{
msPasswordDec.Write(Buffer, 0, BytesRead);
}
cryptoStream.Close();
RetVal = ue.GetString(msPasswordDec.ToArray());
msPasswordDec.Close();
break;
}
return RetVal;
}
private byte[] ConvertPasswordForStorage(string Password)
{
System.Text.UnicodeEncoding ue = new System.Text.UnicodeEncoding();
byte[] uePassword = ue.GetBytes(Password);
byte[] RetVal = null;
switch (_PasswordFormat)
{
case MembershipPasswordFormat.Clear:
RetVal = uePassword;
break;
case MembershipPasswordFormat.Hashed:
HMACSHA1 SHA1KeyedHasher = new HMACSHA1();
SHA1KeyedHasher.Key = _ValidationKey;
RetVal = SHA1KeyedHasher.ComputeHash(uePassword);
break;
case MembershipPasswordFormat.Encrypted:
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
tripleDes.Key = _DecryptionKey;
tripleDes.IV = new byte[8];
MemoryStream mStreamEnc = new MemoryStream();
CryptoStream cryptoStream = new CryptoStream(mStreamEnc, tripleDes.CreateEncryptor(), CryptoStreamMode.Write);
cryptoStream.Write(uePassword, 0, uePassword.Length);
cryptoStream.FlushFinalBlock();
RetVal = mStreamEnc.ToArray();
cryptoStream.Close();
break;
}
return RetVal;
}
private bool ComparePassword(string Password, byte[] StoredPassword)
{
UnicodeEncoding ue = new UnicodeEncoding();
bool RetVal = false;
switch (_PasswordFormat)
{
case MembershipPasswordFormat.Clear:
RetVal = (ue.GetString(StoredPassword) == Password);
break;
case MembershipPasswordFormat.Hashed:
byte[] uePassword = ue.GetBytes(Password);
HMACSHA1 SHA1KeyedHasher = new HMACSHA1();
SHA1KeyedHasher.Key = _ValidationKey;
byte[] PasswordHash = SHA1KeyedHasher.ComputeHash(uePassword);
if (PasswordHash.Length != StoredPassword.Length)
RetVal = false;
else
{
int idx = 0;
for (idx = 0; (idx < StoredPassword.Length) && (PasswordHash[idx] == StoredPassword[idx]); idx++) ;
RetVal = (idx == StoredPassword.Length) ? true : false;
}
break;
case MembershipPasswordFormat.Encrypted:
TripleDESCryptoServiceProvider tripleDes = new TripleDESCryptoServiceProvider();
tripleDes.Key = _DecryptionKey;
tripleDes.IV = new byte[8];
CryptoStream cryptoStream = new CryptoStream(new MemoryStream(StoredPassword), tripleDes.CreateDecryptor(), CryptoStreamMode.Read);
MemoryStream msPasswordDec = new MemoryStream();
int BytesRead = 0;
byte[] Buffer = new byte[32];
while ((BytesRead = cryptoStream.Read(Buffer, 0, 32)) > 0)
{
msPasswordDec.Write(Buffer, 0, BytesRead);
}
cryptoStream.Close();
RetVal = (ue.GetString(msPasswordDec.ToArray()) == Password);
msPasswordDec.Close();
break;
}
return RetVal;
}
private byte[] HexStringToByteArray(string HexString)
{
byte[] Result = new byte[HexString.Length / 2];
for (int idx = 0; idx < Result.Length; idx++)
Result[idx] = Convert.ToByte(HexString.Substring(idx * 2, 2), 16);
return Result;
}
}
}
Comments
Anonymous
April 04, 2006
Ramblings by David Crawford [MSFT]
&nbsp;
Here is a quick set of steps to get working fast with ASP.NET...Anonymous
August 22, 2006
I am pleased to say that yes, you can use ADAM as a source for authentication and authorization.
&nbsp;...Anonymous
May 29, 2009
PingBack from http://paidsurveyshub.info/story.php?title=craig-mcmurtry-s-weblog-asp-net-2-0-4-security-i-ad-am-membershipAnonymous
June 08, 2009
PingBack from http://cellulitecreamsite.info/story.php?id=9088Anonymous
June 15, 2009
PingBack from http://einternetmarketingtools.info/story.php?id=19735