I have created a AD forest that search for a user across all domains in the forest using its global catalog connection string.
I am trying to get thumbnailPhoto of AD user using c# code. But I did not get thumbnailPhoto property in result object even though it exist in AD.
I had verified the thumbnailPhoto prop in AD using powershell. Also I have verified it by getting using LDAP connection string. It both case I got the byte array.
Below is the code to get user and its properties and _configuration.GlobalCatalog returns the Global catalog connections string which is in format (GC://domain-name).
public Task<ProfileImage> GetProfileImageByEmail(string email)
{
var filterQuery = ("mail=" + email);
return Task.FromResult(GetProfileImageFromAD(filterQuery));
}
private ProfileImage GetProfileImageFromAD(string filterQuery)
{
var result = GetADUserDetails(filterQuery);
if (result == null)
return null;
if (result.Properties.Contains("thumbnailPhoto"))
{
var imageBytes = result.Properties["thumbnailPhoto"][0] as byte[];
if (imageBytes != null)
{
return new ProfileImage
{
Content = new MemoryStream(imageBytes),
ContentType = "image/jpeg"
};
}
}
return null;
}
private SearchResult GetADUserDetails(string filterQuery)
{
using (var userBinding = new DirectoryEntry(_configuration.GlobalCatalog))
{
using (DirectorySearcher adSearch = new DirectorySearcher(userBinding))
{
adSearch.ReferralChasing = ReferralChasingOption.All;
adSearch.Filter = filterQuery;
adSearch.PropertiesToLoad.Add("mail");
adSearch.PropertiesToLoad.Add("sn");
adSearch.PropertiesToLoad.Add("givenName");
adSearch.PropertiesToLoad.Add("thumbnailPhoto");
return adSearch.FindOne();
}
}
}
Any help is appreciated.
Update:
On a domain controller open ADSIEdit, connect to Schema Naming Context, find attribute CN=Picture,CN=Schema,CN=Configuration... and go to it's properties. Verify that isMemberOfPartialAttributeSet is set to TRUE
Related
The following C# code accepts two parameter username and password from API using ajax
public Login[] checkLogin(models.Login log)
{
Boolean flag = false;
connection obj = new connection();
IMongoDatabase server = obj.getConnection();
var collection = server.GetCollection<models.Login>("login");
string param = "{'username':'" + log.username + "','password':'"+ log.password +"'}";
List<Login> result = new List<Login>();
var check = collection.Find(param);
foreach(var emp in check.ToList())
{
result.Add(emp);
}
if(result == null)
flag = false;
else
flag = true;
return result.ToArray();
}
I want to check the username and password from my MongoDB database. I am trying to find method but don't know how to check the value if it is available or not.
In order to test whether provided credentials are valid, your method should simply return a boolean value.
You might do something like this.
public IMongoCollection<models.Login> GetLoginCollection()
{
var client = new MongoClient();
var database = client.GetDatabase("dbName");
var collection = database.GetCollection<models.Login>("login");
return collection;
}
public bool CheckLogin(models.Login log)
{
var collection = this.GetLoginCollection();
var authSuccessful = collection
.Count(login =>
login.username == log.username &&
login.password == log.password) > 0;
return authSuccessful;
}
As an alternative, CheckLogin() method might be implemented using explictly-defined filters.
public bool CheckLogin(models.Login log)
{
var collection = GetLoginCollection();
var filter = Builders<models.Login>.Filter
.And(
Builders<models.Login>.Filter.Eq(login => login.username, log.username),
Builders<models.Login>.Filter.Eq(login => login.password, log.password));
var authSuccessful = collection.Count(filter) > 0;
return authSuccessful;
}
Note that storing clear text password within the database is a bad practice. Nobody but the user should know the actual password. One solution is storing the hashed password in the database. On authentication you can compare the hash of the provided password with your stored value. One of the most common hash functions is md5.
I am using active directory and want a list of all users, basically in dotnet core. But I am receiving an exception:
Search result reference received, and referral following is off
Below is my code.
LdapSearchResults lsc = lc.Search("DC = xyz, DC = local", LdapConnection.SCOPE_ONE , "(|(objectClass = person)(objectClass = user))", null, false);
Necromancing - just in case the links go dark.
To fix it in your application, set ReferralFollowing to true.
if you get the message
Search result reference received, and referral following is off
, add
Novell.Directory.Ldap.LdapSearchConstraints cons = lc.SearchConstraints;
cons.ReferralFollowing = true;
lc.Constraints = cons;
to your code.
Example:
public static void GetUsers()
{
System.Collections.Generic.List<ARSoft.Tools.Net.Dns.SrvRecord> lsLdap = GetLdap();
ARSoft.Tools.Net.Dns.SrvRecord ldap = lsLdap[0];
string[] attrs = new string[] { "cn", "distinguishedName", "sAMAccountName", "userPrincipalName", "displayName", "givenName", "sn", "mail", "mailNickname", "memberOf", "homeDirectory", "msExchUserCulture" };
// CN = Common Name
// OU = Organizational Unit
// DC = Domain Component
string searchBase = "DC=cor,DC=local";
string searchFilter = "(&(objectClass=user)(objectCategory=person))";
string ldapHost = MySamples.TestSettings.ldapHost;
int ldapPort = MySamples.TestSettings.ldapPort;//System.Convert.ToInt32(args[1]);
string loginDN = MySamples.TestSettings.loginDN; // args[2];
string password = MySamples.TestSettings.password; // args[3];
Novell.Directory.Ldap.LdapConnection lc = new Novell.Directory.Ldap.LdapConnection();
int ldapVersion = Novell.Directory.Ldap.LdapConnection.Ldap_V3;
try
{
// connect to the server
lc.Connect(ldap.Target.ToString(), ldap.Port);
// bind to the server
lc.Bind(ldapVersion, loginDN, password);
Novell.Directory.Ldap.LdapSearchConstraints cons = lc.SearchConstraints;
cons.ReferralFollowing = true;
lc.Constraints = cons;
// To enable referral following, use LDAPConstraints.setReferralFollowing passing TRUE to enable referrals, or FALSE(default) to disable referrals.
Novell.Directory.Ldap.LdapSearchResults lsc = lc.Search(searchBase,
Novell.Directory.Ldap.LdapConnection.SCOPE_SUB,
searchFilter,
attrs,
false,
(Novell.Directory.Ldap.LdapSearchConstraints)null);
while (lsc.HasMore())
{
Novell.Directory.Ldap.LdapEntry nextEntry = null;
try
{
nextEntry = lsc.Next();
}
catch (Novell.Directory.Ldap.LdapReferralException eR)
{
// https://stackoverflow.com/questions/46052873/ldap-referal-error
// The response you received means that the directory you are requesting does not contain the data you look for,
// but they are in another directory, and in the response there is the information about the "referral" directory
// on which you need to rebind to "redo" the search.This principle in LDAP are the referral.
// https://www.novell.com/documentation/developer/ldapcsharp/?page=/documentation/developer/ldapcsharp/cnet/data/bp31k5d.html
// To enable referral following, use LDAPConstraints.setReferralFollowing passing TRUE to enable referrals, or FALSE (default) to disable referrals.
// are you sure your bind user meaning
// auth.impl.ldap.userid=CN=DotCMSUser,OU=Service Accounts,DC=mycompany,DC=intranet
// auth.impl.ldap.password = mypassword123
// has permissions to the user that is logging in and its groups?
System.Diagnostics.Debug.WriteLine(eR.LdapErrorMessage);
}
catch (Novell.Directory.Ldap.LdapException e)
{
// WARNING: Here catches only LDAP-Exception, no other types...
System.Console.WriteLine("Error: " + e.LdapErrorMessage);
// Exception is thrown, go for next entry
continue;
}
var atCN = nextEntry.getAttribute("cn");
var atUN = nextEntry.getAttribute("sAMAccountName");
var atDN = nextEntry.getAttribute("distinguishedName");
var atDIN = nextEntry.getAttribute("displayName");
if (atCN != null)
System.Console.WriteLine(atCN.StringValue);
if (atUN != null)
System.Console.WriteLine(atUN.StringValue);
if (atDN != null)
System.Console.WriteLine(atDN.StringValue);
if (atDIN != null)
System.Console.WriteLine(atDIN.StringValue);
System.Console.WriteLine("\n" + nextEntry.DN);
Novell.Directory.Ldap.LdapAttributeSet attributeSet = nextEntry.getAttributeSet();
System.Collections.IEnumerator ienum = attributeSet.GetEnumerator();
while (ienum.MoveNext())
{
Novell.Directory.Ldap.LdapAttribute attribute = (Novell.Directory.Ldap.LdapAttribute)ienum.Current;
string attributeName = attribute.Name;
string attributeVal = attribute.StringValue;
System.Console.WriteLine(attributeName + "value:" + attributeVal);
}
}
}
catch (System.Exception ex)
{
System.Console.WriteLine(ex.Message);
}
finally
{
// disconnect with the server
lc.Disconnect();
}
}
You have to activate the behaviour which will follow the referral returned by the directory.
The response you received means that the directory you are requesting does not contain the data you look for, but they are in another directory, and in the response there is the information about the "referral" directory on which you need to rebind to "redo" the search. This principle in LDAP are the referral.
I don't know how to do it in C#, but maybe have a look at :
https://www.novell.com/documentation/developer/ldapcsharp/?page=/documentation/developer/ldapcsharp/cnet/data/bp31k5d.html
I am trying to get all users name from Active Directory using PricipalContext. I can able to get the results on the IEnumurable variable as principalSearchResult using following code. But I am not able to read the results under principalSearchResult.
While trying to read the results from principalSearchResult , it will populate error message like PrincipalOperation Exception was unhandled by users code: Information about the domain could not be retrieved (1355).
I don't know about this error and I am unable to read the values in the search result.
Here is my code:
PrincipalContext ouContext = new PrincipalContext(ContextType.Domain, AD.ServerDomain, AD.LDAPUser, AD.LDAPPasswoprd);
UserPrincipalEx userpricipalex = new UserPrincipalEx(ouContext);
PrincipalSearcher mySearch = new PrincipalSearcher(userpricipalex);
mySearch.QueryFilter = userpricipalex;
IEnumerable<UserPrincipalEx> principalSearchResult = mySearch.FindAll().Cast <UserPrincipalEx>();
var s = (from user in oPrincipalSearchResult //Here I am getting the exception
select new User
{
DisplayName=user.DisplayName,
EmailAddress=user.EmailAddress
.
.
.
});
How can I resolve this error and read the values in that IEnumurable collection without exception.
The Domain Users built-in group will have all the ad users, so you can query all ad users details like shown below. Here i am storing the details in a DataTable. You can also store them as list of custom business objects. Hope this helps!!
string groupName="Domain Users";
using (GroupPrincipal objGroupPrincipal = GetGroupPrincipal(FQDN, AOuserName, AOpassword, groupName))
{
if (objGroupPrincipal != null)
using (PrincipalSearchResult<Principal> objPrincipalSearchResult = objGroupPrincipal.GetMembers(false))
{
objPrincipalSearchResult.ToList<Principal>().FindAll(p => p != null).Cast<UserPrincipal>().ToList<UserPrincipal>()
.ForEach(delegate(UserPrincipal objUserPrincipal)
{
DataRow drUser = dtUsers.NewRow();
drUser["displayname"] = objUserPrincipal.DisplayName;
drUser["UserName"] = objUserPrincipal.SamAccountName;
drUser["Domain"] = FQDN;
drUser["AccountActive"] = objUserPrincipal.IsAccountLockedOut();
drUser["FirstName"] = "";
drUser["initials"] = objUserPrincipal.MiddleName;
drUser["LastName"] = objUserPrincipal.Surname;
drUser["mail"] = objUserPrincipal.EmailAddress;
drUser["telephoneNumber"] = objUserPrincipal.VoiceTelephoneNumber;
drUser["LastLogOn"] = Convert.ToString(objUserPrincipal.LastLogon);
drUser["ADUserPath"] = Convert.ToString(objUserPrincipal.DistinguishedName);
drUser["AccExpiryDate"] = Convert.ToString(objUserPrincipal.AccountExpirationDate);
drUser["PwdExpiryDate"] = "";
dtUsers.Rows.Add(drUser);
});
}
}
And the sub methods are
public static GroupPrincipal GetGroupPrincipal(string FQDN, string AOuserName, string AOpassword, string groupName)
{
GroupPrincipal objGroupPrincipal = null;
objGroupPrincipal = GroupPrincipal.FindByIdentity(GetPrincipalContext(FQDN, AOuserName, AOpassword), IdentityType.SamAccountName, groupName);
return objGroupPrincipal;
}
public static PrincipalContext GetPrincipalContext(string FQDN, string AOuserName, string AOpassword)
{
PrincipalContext objPrincipalContext = null;
objPrincipalContext = new PrincipalContext(ContextType.Domain, FQDN, AOuserName, AOpassword);
return objPrincipalContext;
}
First of all, please forgive me if I'm not using the correct terminologies. Correct me wherever I'm using the wrong terminology.
The objective is to programmatically retrieve the lastLogon date of a given username.
We have what I believe is a forest; two AD servers like - adserver01.aa.mycompany.com and adserver02.aa.mycompany.com
I connected to these servers from a third machine using Microsoft's ADExplorer to inspect the objects. There I see some users having lastLogon date available in adserver01, but not in adserver02. For example, the value for lastLogon is 0x0 in adserver02 whereas it is a valid date in adserver01 for some users.
The code I've developed so far as a Windows Forms application, works fine if only one AD Server is involved. How do I check both servers and return the non-zero value if available, in either for lastLogon date attribute?
private static string GetLastActivityDate(string UserName)
{
string domainAndUserName = String.Format(#"LDAP://aa.mycompany.com/CN={0},OU=CLIENT_PROD,OU=clients.mycompany.com,DC=aa,DC=mycompany,DC=com", UserName);
string OUAdminUserName = "abc";
string OUAdminPassword = "xyz";
AuthenticationTypes at = AuthenticationTypes.Secure;
DateTime lastActivityDate;
string returnvalue;
long lastLogonDateAsLong;
using (DirectoryEntry entryUser = new DirectoryEntry(domainAndUserName, OUAdminUserName, OUAdminPassword, at))
using (DirectorySearcher mysearcher = new DirectorySearcher(entryUser))
try
{
using (SearchResultCollection results = mysearcher.FindAll())
{
if (results.Count >= 1)
{
DirectoryEntry de = results[0].GetDirectoryEntry();
lastLogonDateAsLong = GetInt64(de, "lastLogon");
try
{
if (lastLogonDateAsLong != -1)
{
lastActivityDate = DateTime.FromFileTime(lastLogonDateAsLong);
returnvalue = lastActivityDate.ToString();
}
else
{
returnvalue = "-Not available-";
}
}
catch (System.ArgumentOutOfRangeException aore)
{
returnvalue = "Not available";
}
}
else
{
returnvalue = string.Empty;
}
}
}
catch (System.DirectoryServices.DirectoryServicesCOMException dsce)
{
returnvalue = "- Not available -";
}
return returnvalue;
}
Thank you.
EDIT:
private static Int64 GetInt64(DirectoryEntry entry, string attr)
{
DirectorySearcher ds = new DirectorySearcher(
entry,
String.Format("({0}=*)", attr),
new string[] { attr },
SearchScope.Base
);
SearchResult sr = ds.FindOne();
if (sr != null)
{
if (sr.Properties.Contains(attr))
{
return (Int64)sr.Properties[attr][0];
}
}
return -1;
}
Forgot to mention, the AD schema, structure etc, looks exactly alike in the two servers.
Check this post
http://www.codeproject.com/Articles/19181/Find-LastLogon-Across-All-Windows-Domain-Controlle
I had the same issue but but only for one domain,
I solved it by using the following code however i'm checking the lastLogin of all users
public static Dictionary<string, DateTime> UsersLastLogOnDate()
{
var lastLogins = new Dictionary<string, DateTime>();
DomainControllerCollection domains = Domain.GetCurrentDomain().DomainControllers;
foreach (DomainController controller in domains)
{
try
{
using (var directoryEntry = new DirectoryEntry(string.Format("LDAP://{0}", controller.Name)))
{
using (var searcher = new DirectorySearcher(directoryEntry))
{
searcher.PageSize = 1000;
searcher.Filter = "(&(objectClass=user)(!objectClass=computer))";
searcher.PropertiesToLoad.AddRange(new[] { "distinguishedName", "lastLogon" });
foreach (SearchResult searchResult in searcher.FindAll())
{
if (searchResult.Properties.Contains("lastLogon"))
{
var lastLogOn = DateTime.FromFileTime((long)searchResult.Properties["lastLogon"][0]);
var username = Parser.ParseLdapAttrValue(searchResult.Properties["distinguishedName"][0].ToString());
if (lastLogins.ContainsKey(username))
{
if (DateTime.Compare(lastLogOn, lastLogins[username]) > 0)
{
lastLogins[username] = lastLogOn;
}
}
else
{
lastLogins.Add(username, lastLogOn);
}
}
}
}
}
}
catch (System.Runtime.InteropServices.COMException comException)
{
// Domain controller is down or not responding
Log.DebugFormat("Domain controller {0} is not responding.",controller.Name);
Log.Error("Error in one of the domain controllers.", comException);
continue;
}
}
return lastLogins;
}
On top of the code you can use the following to get all domains in a forest.
Forest currentForest = Forest.GetCurrentForest();
DomainCollection domains = currentForest.Domains;
foreach(Domain domain in domains)
{
// check code above
}
There may be a simpler approach? There is actually another attribute lastLogonTimestamp, added with 2003 domain level I think, that tries to keep a single, consistent value across the domain for the last login. Alas, it has a bizarre replication time pattern, and could be up to two weeks out of date.
How can I get the distinguished name from Active Directory of the currently logged in user in C#?
Check following snippet. You have pass to Identity.Name from IPrincipal. I assume that the user is already authenticated in Active Directory (ie. using standard IIS authorization methods).
private string GetUserName(string identity)
{
if (identity.Contains("\\"))
{
string[] identityList = identity.Split('\\');
return identityList[1];
}
else
{
return identity;
}
}
public string GetUserDn(string identity)
{
var userName = GetUserName(identity);
using (var rootEntry = new DirectoryEntry("LDAP://" + adConfiguration.ServerAddress, null, null, AuthenticationTypes.Secure))
{
using (var directorySearcher = new DirectorySearcher(rootEntry, String.Format("(sAMAccountName={0})", userName)))
{
var searchResult = directorySearcher.FindOne();
if (searchResult != null)
{
using (var userEntry = searchResult.GetDirectoryEntry())
{
return (string)userEntry.Properties["distinguishedName"].Value;
}
}
}
}
return null;
}
Why wouldn't you just use: System.DirectoryServices.AccountManagement.UserPrincipal.Current.DistinguishedName