I'd like check the the login and the password match with the AD info. I tried with this piece of coode but I get an exception on FindOne (bad username or password .. but they are correct). I know there is the PrincipalContext solution but I need to be able to set the server (Production, Dev, ...)
Thanks,
var Ad = new DirectoryEntry("LDAP://server1.domain.com", username, password);
var AdSearcher = new DirectorySearcher(Ad);
AdSearcher.Filter = String.Format("(anr={0})", username);
AdSearcher.PropertiesToLoad.Add("sAMAccountName");
AdSearcher.PropertiesToLoad.Add("displayName");
var AdSearcherResults = AdSearcher.FindOne();
var userFullName = AdSearcherResults.Properties["displayName"][0].ToString();
var userUid = AdSearcherResults.Properties["sAMAccountName"][0].ToString();
if (Membership.ValidateUser(username, userUid))
return true;
return false;
Update1 I tried this too :
using (var context = new PrincipalContext(ContextType.Domain, "server1.domain.com"))
{
var isValid = context.ValidateCredentials(username, password);
}
My computer is not connected on the domain but should be work I think.
My code for ActiveDirectory Auth.
public DirectoryEntry connDirectory(string usr, string pwd)
{
string ip = iniMan.IniRead("LDAP", "adres");
DirectoryEntry oDE;
oDE = new DirectoryEntry(ip, usr, pwd, AuthenticationTypes.Secure);
return oDE;
}
public bool AD_Login(string kullanici_adi, string sifre)
{
try
{
DirectoryEntry entLogin = connDirectory(kullanici_adi, sifre);
object loginObj = entLogin.NativeObject;
return true;
}
catch (Exception ex)
{
return false;
}
}
void TestMetod(){
if(AD_Login("ozan","ozan"){
//ok
}
}
Related
private static bool ValidateUser(string userName, string password, string ldapPath)
{
DirectoryEntry directoryEntry = new DirectoryEntry(ldapPath, userName, password, AuthenticationTypes.ReadonlyServer);
try
{
object obj = directoryEntry.NativeObject;
if (obj.IsNotNullRef())
{
return true;
}
}
catch (Exception ex)
{
//error handling
}
finally
{
directoryEntry.Dispose();
}
return false;
}
I have the sample snippet above that validates an active directory username & password successfully if the domain NETBIOS and DNS match.
However, if the Domain name (NETBIOS) is not matching the DNS entry of the domain, i.e when the NETBIOS & DNS have been registered differently, the code doesn't return true even when you provide a valid UserName and Password.
How can i work around this issue?
EDIT:
The sample input is just standard, a userName, password & a domain URL
Example that returns True:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://abcd1.xyz1.xx1.org", "abcd1\\stacktrace1", "xxxx", AuthenticationTypes.ReadonlyServer);
Example that returns false:
DirectoryEntry directoryEntry = new DirectoryEntry("LDAP://abcd2.xyz2.xx2.org", "abcd2\\stacktrace2", "xxxx", AuthenticationTypes.ReadonlyServer);
The only difference between the 2 examples is that, in example 1, the Domain name (NETBIOS) is matching with the DNS entry while in example 2, NETBIOS & DNS have been registered differently.
Refer following method:
public void AuthenticateUser(string userName, string password)
{
DirectoryUserAuthenticationResponse response = new DirectoryUserAuthenticationResponse();
try
{
// Creating Principal Context.
using (var principalContext = GetPrincipalContext())
{
try
{
// Getting user identity and validating user against active provider.
var aUser = UserPrincipal.FindByIdentity(principalContext, GetIdentitytype(), userName);
if (aUser != null)
{
// To check user account is locked out or not
if (aUser.IsAccountLockedOut())
throw new Exception("UserAccountLockedOut");
// To check user account is disabled or not.
if (aUser.Enabled == false)
throw new Exception("UserAccountDisabled");
// To check user change password on next logon.
if (aUser.LastPasswordSet == null)
throw new Exception("changePassword");
//To check password expiration
if (aUser.LastPasswordSet != null && aUser.PasswordNeverExpires == false)
{
DirectoryEntry rootDSE = new DirectoryEntry("LDAP://" + _directoryServerInfo.IPAddress, userName, password);
try
{
// Bind to the ADsobject to force authentication
object nativeobject = rootDSE.Name;
}
catch (DirectoryServicesCOMException cex)
{
string errorCode = cex.ExtendedErrorMessage.Substring(cex.ExtendedErrorMessage.IndexOf("data", 1));
errorCode = errorCode.Substring(5, 3);
//The commented code below fails to parse properly and throws an exception
// int exErrorCode = int.Parse(errorCode);
int exErrorCode = int.Parse(Regex.Match(errorCode, #"\d+").Value);
if (exErrorCode == (int)PWDFlags.Account_Expired)
throw new Exception("AccountExpired");
if (exErrorCode == (int)PWDFlags.Password_Expiration)
throw new Exception("PasswordExpired");
}
}
// validate the credentials by using principal context method.
var isAuthenticated = principalContext.ValidateCredentials(userName, password);
if (!isAuthenticated)
{
throw new Exception("Invalid your name and passowrd");
}
}
else
throw new Exception("InvalidUsernamePassword");
}
catch (DirectoryServicesCOMException cex)
{
string errorCode = cex.ExtendedErrorMessage.Substring(cex.ExtendedErrorMessage.IndexOf("data", 1));
errorCode = errorCode.Substring(5, 3);
//The commented code below fails to parse properly and throws an exception
// int exErrorCode = int.Parse(errorCode);
int exErrorCode = int.Parse(Regex.Match(errorCode, #"\d+").Value);
if (exErrorCode == (int)PWDFlags.Account_Expired)
throw new Exception("AdminACCExpire");
if (exErrorCode == (int)PWDFlags.Password_Expiration)
throw new Exception("AdminPWDExprire");
else
{
//Else any exception
}
}
}
}
catch (Exception)
{
throw;
}
}
private PrincipalContext GetPrincipalContext()
{
// Creating Principal Context.
PrincipalContext principalContext = null;
string serveraddress = _directoryServerInfo.IPAddress;//+":"+_defdirectoryport ;
if (string.IsNullOrEmpty(_directoryfilterouname))
{
principalContext = new PrincipalContext(ContextType.Domain, serveraddress, _directoryAdminUserId, _directoryAdminPassword);
//principalContext = new PrincipalContext(ContextType.Domain, _directoryServerInfo.IPAddress , _directoryAdminUserId, _directoryAdminPassword);
}
else
{
//string domainComponents = GetDomainComponents();
principalContext = new PrincipalContext(ContextType.Domain, serveraddress, _directoryfilterouname, _directoryAdminUserId, _directoryAdminPassword);
}
//// _directoryServerInfo.HostName = //((System.DirectoryServices.AccountManagement.ADStoreCtx)(principalContext.QueryCtx)).DnsDomainName;
return principalContext;
}
I'm writing some kind of a mini AD tool (with VS-C#) to our organization and got into an issue.
I have a main function that searches the user (when I click on it in a listview) and some functions that manipulate the user's object.
public DirectoryEntry GetUser(string username)
{
try
{
Forest currentForest = Forest.GetCurrentForest();
GlobalCatalog gc = currentForest.FindGlobalCatalog();
using (DirectorySearcher searcher = gc.GetDirectorySearcher())
{
searcher.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + username + "*))";
SearchResult results = searcher.FindOne();
if (!(results == null))
{
DirectoryEntry de = new DirectoryEntry(results.Path, strAdminUser, strAdminPass, AuthenticationTypes.Secure);
de.RefreshCache(new string[] { "canonicalName" });
de.Path = de.Properties["canonicalName"].Value.ToString();
de.CommitChanges();
return de;
}
else
{
return null;
}
}
}
catch (DirectoryServicesCOMException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
}
and here's an example of a function that checks if the user is locked:
public bool IsUserLocked(string username)
{
try
{
DirectoryEntry de = GetUser(username);
string attName = "msDS-User-Account-Control-Computed";
de.RefreshCache(new string[] { attName });
const int UF_LOCKOUT = 0x0010;
int userFlags = /*(int)*/Convert.ToInt32(de.Properties[attName].Value);
if ((userFlags & UF_LOCKOUT) == UF_LOCKOUT)
{
return true;
}
de.Dispose();
return false;
}
catch (DirectoryServicesCOMException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return false;
}
}
The function that checks the locked status of a user always fails with an error: "Unspecified error", but if I'm not changing the Directory Entry's path in the first function I get "The server is unwilling to process the request" error (I'm using proper service username and password with all the permissions needed) but still it happens.
Can someone spot the issue?
How about using System.DirectoryServices.AccountManagement namespace? If you have no issue using the new namespace, there's a simpler way to check if user account is locked and unlock if needed.
public bool IsUserLocked (string username)
{
using(PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "yourdomain.com")
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(ctx, username)
{
if (user != null) return user.IsAccountLockedOut();
}
}
return null;
}
And similarly, you can unlock the user account if needed.
...
if (user != null)
{
user.UnlockAccount();
user.Save();
}
Got it...
This has solved my issue:
de.Path = results.Path.Replace("GC://DCNAME.", "LDAP://");
Since I'm searcing on the Global Catalog, I had to replace a portion in the path to match it to the correct path:
public DirectoryEntry GetUser(string username)
{
try
{
Forest currentForest = Forest.GetCurrentForest();
GlobalCatalog gc = currentForest.FindGlobalCatalog();
using (DirectorySearcher searcher = gc.GetDirectorySearcher())
{
searcher.Filter = "(&((&(objectCategory=Person)(objectClass=User)))(samaccountname=" + username + "*))";
SearchResult results = searcher.FindOne();
if (!(results == null))
{
DirectoryEntry de = new DirectoryEntry(results.Path, strAdminUser, strAdminPass, AuthenticationTypes.Secure);
de = new DirectoryEntry(results.Path);
de.Path = results.Path.Replace("GC://DCNAME.", "LDAP://");
de.CommitChanges();
//System.Windows.Forms.MessageBox.Show(de.Path);
return de;
}
else
{
return null;
}
}
}
catch (DirectoryServicesCOMException e)
{
System.Windows.Forms.MessageBox.Show(e.Message);
return null;
}
}
Now the path returns to the function called GetUser in the correct format :)
I am trying to create a login method and I need to get a password from the corresponding user. This is my database layer code:
public int loginUser(string userName, string pass)
{
int result = 0;
var credentials = MongoCredential.CreateMongoCRCredential("SearchForKnowledge", userName, pass);
var settings = new MongoClientSettings
{
Credentials = new[] { credentials }
};
try
{
var mongoClient = new MongoClient(settings);
var database = mongoClient.GetDatabase("SearchForKnowledge");
var coll = database.GetCollection<BsonDocument>("Users");
var filter = Builders<BsonDocument>.Filter.Eq("userName", userName);
var query = coll.Find(filter);
//??????????
}
catch (Exception ex) {
result = 0;
}
return result;
}
as you can see if the login is success im trying to return 1 and if it fails, 0 (for redirecting purposes). I am struggling to check if the username matches password set to it. At the moment I just made a filter, passed it to the method Find and im dead stuck at this point. How do I return that user's password from mongodb and compare it to the one passed as a parameter?
Try something like this:
public int loginUser(string userName, string pass)
{
int result = 0;
//Here you use credentials for the connection, not the one passed
//to the method:
var credentials = MongoCredential.CreateMongoCRCredential("SearchForKnowledge", connectionUsername, connectionPass);
var settings = new MongoClientSettings
{
Credentials = new[] { credentials }
};
try
{
var mongoClient = new MongoClient(settings);
var database = mongoClient.GetDatabase("SearchForKnowledge");
var coll = database.GetCollection<BsonDocument>("Users");
var filter = Builders<BsonDocument>.Filter.Eq("userName", userName);
var result = await coll.Find(filter).ToListAsync().First();
if(result["Password"] == pass)
{
result = 1;
}
}
catch (Exception ex) {
result = 0;
}
return result;
I have a code that I use to check if the user is member of the AD, worked perfectly,
now I want to add the possibility to check if the user also a member of a group!
what do I need to modify to achieve that, I did some work, but it fails!
so here is my code:
//Authenticate a User Against the Directory
private bool Authenticate(string userName,string password, string domain)
{
if (userName == "" || password == "")
{
return false;
}
bool authentic = false;
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain,userName, password);
object nativeObject = entry.NativeObject;
authentic = true;
}
catch (DirectoryServicesCOMException) { }
return authentic;
}
I want to make it like this:
private bool Authenticate(string userName,string password, string domain, string group)
This is not available on Windows XP or earlier.
Anyway, in order to check for group membership, you can use this code:
bool IsInGroup(string user, string group)
{
using (var identity = new WindowsIdentity(user))
{
var principal = new WindowsPrincipal(identity);
return principal.IsInRole(group);
}
}
In ASP.Net you will use Page.User.IsInRole("RoleName") or in Windows you can use System.Threading.Thread.CurrentPrincipal.IsInRole("RoleName")
I solve it with this code
public bool AuthenticateGroup(string userName, string password, string domain, string group)
{
if (userName == "" || password == "")
{
return false;
}
try
{
DirectoryEntry entry = new DirectoryEntry("LDAP://" + domain, userName, password);
DirectorySearcher mySearcher = new DirectorySearcher(entry);
mySearcher.Filter = "(&(objectClass=user)(|(cn=" + userName + ")(sAMAccountName=" + userName + ")))";
SearchResult result = mySearcher.FindOne();
foreach (string GroupPath in result.Properties["memberOf"])
{
if (GroupPath.Contains(group))
{
return true;
}
}
}
catch (DirectoryServicesCOMException)
{
}
return false;
}
it works fine for me, and it can be use with a machine not part of the Domain Controller / Active Directory
Thank you all for the help
I just want to Add a new method on an existing code below.
Method is a simply check a given User_ID if it is exists on the AD.
It's my 1st time dealing with AD.
public class AD
{
// Fields
private static string ADPassword = ConfigurationManager.AppSettings["ADPassword"].ToString();
private static string ADPath = ConfigurationManager.AppSettings["ADConnection"].ToString();
private static string ADServerName = ConfigurationManager.AppSettings["ADServerName"].ToString();
private static string ADUserName = ConfigurationManager.AppSettings["ADUserName"].ToString();
// Methods
public static string GetLogin(string sUserName, string sPassword)
{
try
{
DirectoryEntry entry = new DirectoryEntry(ADPath, ADServerName + sUserName, sPassword);
object nativeObject = entry.NativeObject;
return string.Empty;
}
catch
{
return "Invalid Username or Password";
}
}
public static string Update(string sUserName, string sOldPassword, string sNewPassword)
{
string message;
try
{
DirectoryEntry searchRoot = new DirectoryEntry();
searchRoot.Path = ADPath;
searchRoot.Username = ADServerName + ADUserName;
searchRoot.Password = ADPassword;
DirectorySearcher searcher = new DirectorySearcher(searchRoot);
searcher.Filter = "(SAMAccountName=" + sUserName + ")";
DirectoryEntry directoryEntry = searcher.FindOne().GetDirectoryEntry();
directoryEntry.Invoke("ChangePassword", new object[] { sOldPassword, sNewPassword });
directoryEntry.CommitChanges();
directoryEntry.Close();
message = string.Empty;
}
catch (Exception exception)
{
try
{
message = exception.InnerException.Message;
}
catch
{
message = exception.Message;
}
}
return message;
}
}
Which version of the .NET Framework are you on??
In .NET before 3.5, you could probably do a DirectorySearch on the whole server (or alternatively a more constrained subtree):
public bool UserExists(string userName)
{
DirectoryEntry searchRoot = new DirectoryEntry("LDAP://dc=yourcompany,dc=com", userName, password);
DirectorySearcher searchForUser = new DirectorySearcher(searchRoot);
searchForUser.SearchScope = SearchScope.SubTree;
searchForUser.Filter = string.Format("(&(objectCategory=Person)(anr={0}))", userName);
if(searchForUser.FindOne() != null)
{
return true;
}
else
{
return false;
}
}
This is just off the top of my head, can't test it right now. This will search in your entire domain - check the LDAP path for the searchRoot - it would have to be something like
LDAP://dc=yourcompany,dc=com
or if you want to search just inside the "Users" container:
LDAP://cn=Users,dc=yourcompany,dc=com
With .NET 3.5 things got a lot easier - see this MSDN Article for a lot of useful info on how to search and find users and groups in .NET 3.5 using the new System.DirectoryServices.AccountManagement namespace. You can basically now do a FindByIdentity call:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "YOURDOMAIN");
UserPrincipal foundUser = UserPrincipal.FindByIdentity(ctx, "your user name");
and that's all there is.
Marc
If it's your first AD experience, it might be worth taking a look at this codeproject article: Howto: (Almost) Everything In Active Directory via C#. It contains lots of examples that might help you.
What do you mean exactly by User_ID? Account name? LDAP distinguished name?