how to check the username in Active Directory in WPF - wpf

I want to check whether username exists in Active Directory?
And depending on that I need to execute the code.
I have domain and username.How to check whether username exists in Active Directory without password using DirectorySearcher.

Your process has to be run under active directory user otherwise you should provide also active directory user credentials when creating PrincipalContext.
This is simple code to find user by userName:
var context = new PrincipalContext(ContextType.Domain, "yourDomainHost");
var userInfo = UserPrincipal.FindByIdentity(context, userName);
EDIT:
if you need to use directory searcher you can try this method:
bool ContainsUser(string domain, string userName)
{
string ldapBase = string.Format("LDAP://{0}", domain);
// in case if process is not running under AD user use: new DirectoryEntry(ldapBase, "userName", "password")
using (var entry = new DirectoryEntry(ldapBase))
{
using (var searcher = new DirectorySearcher(entry))
{
searcher.Filter = string.Format("(sAMAccountName={0})", userName);
return searcher.FindOne() != null;
}
}
}

You could try this approach:
DirectoryEntry entry = new DirectoryEntry("LDAP://DomainName");
DirectorySearcher dsearcher = new DirectorySearcher(entry);
dsearcher.Filter = "samaccountname=" + username;
SearchResult result = dsearcher.FindOne();
if(null!=result) //User Exists
{
//Do your stuff here
}
else //User Not Exists
{
//Do your stuff here
}
The above code assumes your AD Server is allowing anonymous access.

Related

EF Core migrations on a new SQL Server

I'm trying to build a Migration console app, that is able to start from scratch, i.e. on a freshly installed SQL Server, including a dedicated user with credentials, which should be the db_owner.
I have it working on PostgreSQL, but need to get a similar solution for SQL Server.
Before I call context.Database.Migrate() , I'm calling CheckDatabaseCreated(context.Database, configuration) which basically does this:
Tries to connect with given connectionstring
If it fails it replaces user, and password with SA and SA password
and connects to master.
Creates the login, if it does not exist.
Creates the database, if it does not exist.
Connects to the newly created database - still as SA.
Creates the user with the login, and adds db_owner role.
Finally it tries again to connect using the original connectionstring - this is where it fails.
Using HeidiSQL, I can see that the database is created, but I can only connect using SA credentials.
private static void CheckDatabaseCreated(DatabaseFacade contextDatabase, IConfiguration configuration)
{
bool canConnect;
try
{
canConnect = contextDatabase.CanConnect();
Console.WriteLine("Database connected succesfully.");
}
catch (Exception e)
{
Console.WriteLine($"Unable to connect to database: {e.Message}");
canConnect = false;
}
if (!canConnect)
{
var builder = new SqlConnectionStringBuilder(configuration["ConnectionString"]);
var originalUser = builder.UserID;
var originalPassword = builder.Password;
var originalDatabase = builder.InitialCatalog;
builder.UserID = _masterUsername;
builder.Password = _masterPassword;
builder.InitialCatalog = "master";
var login = $"{originalUser}Login";
SqlConnection conn = new SqlConnection(builder.ConnectionString);
try
{
conn.Open();
// Check if login exists
SqlCommand command = new SqlCommand($"SELECT COUNT(*) FROM master.sys.server_principals WHERE name = '{login}'", conn);
object result = command.ExecuteScalar();
result = (result == DBNull.Value) ? null : result;
if (Convert.ToInt32(result) < 1)
{
Console.WriteLine("Login does not exist - creating.");
command = new SqlCommand($"CREATE LOGIN [{login}] WITH PASSWORD = N'{originalPassword}', CHECK_POLICY = OFF, CHECK_EXPIRATION = OFF", conn);
command.ExecuteNonQuery();
}
// Check if database exists
command = new SqlCommand($"SELECT COUNT(*) FROM master.sys.databases WHERE name = '{originalDatabase}'", conn);
result = command.ExecuteScalar();
result = (result == DBNull.Value) ? null : result;
if (Convert.ToInt32(result) < 1)
{
Console.WriteLine("Database does not exist - creating.");
command = new SqlCommand($"CREATE DATABASE \"{originalDatabase}\" ", conn);
command.ExecuteNonQuery();
}
conn.Close();
// Now connect to the (newly created) database - still as sa.
builder.InitialCatalog = originalDatabase;
conn = new SqlConnection(builder.ConnectionString);
try
{
conn.Open();
command = new SqlCommand($"CREATE USER [{originalUser}] FOR LOGIN [{login}]", conn);
command.ExecuteNonQuery();
command = new SqlCommand($"EXEC sp_addrolemember 'db_owner', '{originalUser}'", conn);
command.ExecuteNonQuery();
conn.Close();
}
catch (Exception e)
{
Console.WriteLine($"Unable to connect to {originalDatabase} database: {e.Message}");
}
// Finally try to connect as the user created above.
builder = new SqlConnectionStringBuilder(configuration["ConnectionString"]);
conn = new SqlConnection(builder.ConnectionString);
try
{
conn.Open();
}
catch (Exception e)
{
// This is where it fails.
Console.WriteLine($"Unable to connect to database: {e.Message}");
}
}
catch (Exception e)
{
Console.WriteLine($"Unable to connect to database: {e.Message}");
}
}
}
The User ID in a SQL Server connection string refers to a Login, or a Contained Database User.
So your problem is here:
var login = $"{originalUser}Login";
This login is not the one referenced in your connection string. There's no reason the Login and Database User need different names. So jut make them the same:
var login = originalUser;

Spring ldap unlocking an account

I am trying to unlock user account using spring ldap and getting the error message
""Malformed 'LockoutTime' attribute value" exception.
My code looks like below
public boolean unlockAccount(Name dn) {
ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("lockoutTime", 0));
ldapTemplate.modifyAttributes(dn, new ModificationItem[] {item});
return true;
}
I am using Windows server 2016 and Spring ldap 2.3.2.
Is 'lockoutTime' the correct attribute to unlock an account ?
Is there anything else I am missing ?
In LDAP if you type the wrong password for more than 5 times, the account gets locked. If you want to unlock the user you have to delete an operational attribute name as pwdAccountLockedTime.
public String unlockUser(Users pvo) {
System.out.println("this is pvo" + pvo);
Name dn = buildDn(pvo);
DirContextOperations context = ldapTemplate.lookupContext(dn);
ModificationItem[] modificationItems;
modificationItems = new ModificationItem[1];
modificationItems[0] = new ModificationItem(DirContext.REMOVE_ATTRIBUTE,
new BasicAttribute("pwdAccountLockedTime"));
ldapTemplate.modifyAttributes(dn, modificationItems);
return "Account Unlocked";
}
build Dn for your LDAP and use the above code then the user gets unlocked.
String[] attrIDs = new String[] { "lockoutTime", "sAMAccountName",
"distinguishedName","pwdLastSet", "accountExpires", "userAccountControl",
"IsAccountLocked" };
ctls.setReturningAttributes(attrIDs);
ctls.setSearchScope(2);
String filter = "(&(objectClass=user)(objectCategory=Person)(sAMAccountName=" +
samaccountname+ "))";
NamingEnumeration<SearchResult> answer = ctx.search(adManagedOU, filter,ctls);
while (answer.hasMore()) {
SearchResult rs = answer.next();
Attributes attrs = rs.getAttributes();
distinguishedName = rs.getNameInNamespace();
String[] lockouttime = null;
String lockOutValue=attrs.get("lockoutTime");
if (lockOutValue != null)
{
lockouttime = attrs.get("lockoutTime").toString().split(":");
if (Long.valueOf(lockouttime[1].trim()) > 0) {
ModificationItem[] mods1 = new ModificationItem[] {
new ModificationItem(2, new BasicAttribute("lockoutTime", "0") )
};
((DirContext) ctls).modifyAttributes(distinguishedName, mods1);
}
else
{
LOGGER.info(username + " Account Not Locked");
}
The only values that may be set on lockouttime is to set the value to "0" which will effectively un-lock the account.
To learn more on Microsoft Active Directory Lockouts.
Setting the value to a String instead of an int makes this work, at least with AWS Simple AD.
ModificationItem item = new ModificationItem(DirContext.REPLACE_ATTRIBUTE, new BasicAttribute("lockoutTime", "0"));
ldapTemplate.modifyAttributes(dn, new ModificationItem[] {item});

Check if List of Users are valid against adfs in C#

I have a requirement to check if the users in my application are active users in active directory.
I need to send a notification when one of the user alias becomes invalid.
In most of the examples I see validating only one user at a time against ADFS using LDAP which is going to take a very long time large number of users.
Is there any way by which I can validate by sending a list of users and validate, so that it will be faster?
Thanks.
Out the box in ADFS, no.
This sounds like something you should call from your app. using the AD C# API's.
Refer Howto: (Almost) Everything In Active Directory via C#.
Or (in some cases) Everything in Active Directory via C#.NET 3.5 (Using System.DirectoryServices.AccountManagement)
Starting with .Net 3.5 there's System.DirectoryServices.AccountManagement
I'd code something like
public List<string> InvalidUsernames (List<string> usernames)
{
var result = new List<string>();
var domainName = "OkieDokie";
var ldapContext = new PrincipalContext(ContextType.Domain, domainName);
foreach (var username in usernames)
{
var user = UserPrincipal.FindByIdentity(ldapContext, username);
if (user == null) //null means it couldn't be found
{
result.Add(username);
}
}
return result;
}
But it all depends on what you consider active/invalid. In the if you could check for the user.AccountExpirationDate (?date) or user.Enabled (?bool).
Or if you do have a common group for all of them, you could replace the previous foreach and use:
var usersGroup = UsernamesInGroup("theONEgroup");
foreach (var username in usernames)
{
var user = UserPrincipal.FindByIdentity(ldapContext, username);
if (user == null) //null means it couldn't be found
{
result.Add(username);
}
}
public List<string> UsernamesInGroup(string groupName)
{
GroupPrincipal grupo = GroupPrincipal.FindByIdentity(MainOU, groupName);
return UsernamesInGroup(group);
}
public List<string> UsernamesInGroup(GroupPrincipal gp)
{
List<string> userNames = new List<string>();
var principalsInGroup = gp.GetMembers(true);
foreach (Principal principal in principalsInGroup)
{
if (principal.StructuralObjectClass == "user")
{
userNames.Add(principal.SamAccountName);
}
}
return userNames;
}

Is my LDAP syntax wrong in search filter

This is my first attempt in trying to query our LDAP server for AD info. When I am trying to query the LDAP server here is what I'm trying to retrieve:
I am trying to retrieve all active employees with a countlimit of 500 records whose displayname starts with "sav", has an email address and has a userAccountControl attribute of 512. The problem I'm encountering is that I'm only getting back 8 records total. I should literally be getting back at least 10 records.
I did a separate search on the 2 records that were NOT retrieved in my search and each had an email address and a userAccountControl value of 512. So I'm not sure why those 2 records were missing.
I'm sure I've done something wrong in my syntax but I cannot find what it is. Any HELP/DIRECTION would be appreciated. Thank you.
After googling I've defined the SEARCH FILTER as:
String searchFilter = "(&(objectClass=user)(displayname="+displayname+"*"+")(mail=*)(userAccountControl=512))";
Please see my complete method below:
public List<String> getAutocompleteEmpRecordsList(String displayname, LdapContext ctx) {
List<String> activeEmpAttributes = new ArrayList<String>();
Attributes attrs = null;
int count = 0;
int empEmailAddrLen = 0;
try {
SearchControls constraints = new SearchControls();
constraints.setCountLimit(500);
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {"displayname", "mail", "userAccountControl"};
constraints.setReturningAttributes(attrIDs);
String searchFilter = "(&(objectClass=user)(displayname="+displayname+"*"+")(mail=*)(userAccountControl=512))";
NamingEnumeration answer = ctx.search("OU=Standard,OU=Users,DC=xxx,DC=org", searchFilter, constraints);
if (answer != null) {
while (answer.hasMore()) {
attrs = ((SearchResult) answer.next()).getAttributes();
if (attrs.get("displayname") != null) {
int empNameLen = attrs.get("displayname").toString().length();
activeEmpAttributes.add(attrs.get("displayname").toString().substring(13, empNameLen));
}
count++;
ctx.close();
}
}
else {
throw new Exception("Invalid User");
}
System.out.println("activeEmpAttributes: " + activeEmpAttributes);
System.out.println("count: " + activeEmpAttributes.size());
} catch (Exception ex) {
ex.printStackTrace();
}
return activeEmpAttributes;
}
You may be confusing displayname attribute and cn attribute.
On Windows server you've got a command line tool called LDIDIFDE.EXE which can allow you to test your filter.
ldifde -f datas.ldf -d "OU=Standard,OU=THR Users,DC=txhealth,DC=org" -r "(&(objectClass=user)(displayname=sav*)(mail=*)(userAccountControl=512))"
ldifde -f datas.ldf -d "OU=Standard,OU=THR Users,DC=txhealth,DC=org" -r "(&(objectClass=user)(cn=sav*)(mail=*)(userAccountControl=512))"
In the User and computer MMC you can also test your filter.
Start User and computer Active-Directory :
Right buton on registered request :
Choose personalize search, you've got an helper tab for common attributes :
You can choose personalized tab for technical attributes
You can test en copy the resulting LDAP filter (you don't need the double (& one is enough):
Can you post your userAccountControl, displayName, and mail values for the two excluded users?
FWIW the medial search on displayName would run alot faster if you add a tuple index to it.
I downloaded a free AD tool to view all in AD that I needed and it showed me that the data was not the problem but I was just not hitting all the OU's that I needed because there is NOT just 1 OU where all our users are stored.
Consequently, after googling some more I found a page on the Oracle site regarding LDAP and I changed my LDAPContext to DirContext for my connection to do searches within the directory as well as using this context's REFERRAL and set the value to "follow" to avoid the PartialSearchException.
I thought I'd post my findings just in case some other newbie ran into the same issue.
If you see a downside to the changes I made please let me know. Regards.
Here is my corrected code:
public List<String> getAutocompleteEmpRecordsList(String displayname, DirContext ctx) {
List<String> activeEmpAttributes = new ArrayList<String>();
Attributes attrs = null;
int count = 0;
int empEmailAddrLen = 0;
try {
SearchControls constraints = new SearchControls();
constraints.setCountLimit(500);
constraints.setSearchScope(SearchControls.SUBTREE_SCOPE);
String[] attrIDs = {"displayname", "mail", "userAccountControl"};
constraints.setReturningAttributes(attrIDs);
String searchFilter = "(&(objectClass=user)(displayname="+displayname.trim()+"*"+")(mail=*)(userAccountControl=512))";
NamingEnumeration answer = ctx.search("DC=xxx,DC=org", searchFilter, constraints);
if (answer != null) {
while (answer.hasMore()) {
attrs = ((SearchResult) answer.next()).getAttributes();
if (attrs.get("displayname") != null) {
int empNameLen = attrs.get("displayname").toString().length();
activeEmpAttributes.add(attrs.get("displayname").toString().substring(13, empNameLen));
}
count++;
ctx.close();
}
}
else {
throw new Exception("Invalid User");
}
System.out.println("activeEmpAttributes: " + activeEmpAttributes);
System.out.println("count: " + activeEmpAttributes.size());
} catch (Exception ex) {
ex.printStackTrace();
}
return activeEmpAttributes;
}
Thanks anyway.

Odd result by using DirectorySearcher

I am using DirectorySearcher to get all AD users' display name from company AD server, we have around 100k records and most of results are correct.
But we got near 100 users' display name are "$CimsUserVersion2", it's really a odd result, I checked in outlook which also sync display name from AD, the name is correct
Have u facing same issue?
Thanks a lot
using (var de = new DirectoryEntry("LDAP://" + domain))
{
using (var search = new DirectorySearcher(de))
{
search.Filter = "CN=" + userName;
var results = search.FindAll();
string temp = results[0].Properties["displayname"][0].ToString();
if (string.IsNullOrEmpty(temp))
{
return string.Empty;
}
else
{
return temp;
}
}
}
Not sure if that's the problem - but I think you'd need to tell your searcher that you want the displayName attribute to be loaded:
using (var de = new DirectoryEntry("LDAP://" + domain))
{
using (var search = new DirectorySearcher(de))
{
search.Filter = "CN=" + userName;
search.PropertiesToLoad.Add("displayName"); // specify "displayname" to be returned from search
var results = search.FindAll();
string temp = results[0].Properties["displayname"][0].ToString();
if (string.IsNullOrEmpty(temp))
{
return string.Empty;
}
else
{
return temp;
}
}
}
Don't you automate the provisioning of UNIX users and groups into Microsoft Active Directory with "Centrify DirectControl".
This tool uses a simple object model to manage the UNIX-specific properties for users, groups, computers, and zones, as well as UNIX NIS services.
As far as I understand it uses Active-Directory attributes to register some special informations.
UserVersion is map to displayName :
UserVersion determines compatibility between a user profile object and the Centrify DirectControl Administrator Console. The only valid value for this attribute is $CimsUserVersion2.
For example:
displayName: $CimsUserVersion2

Resources