I am trying to connect to Active Directory using service account credentials that have full access to connect to Active Directory, but unable to load property details of users.
This happens when I am logged in using 'miminstall' account which does not have access to fetch user details from AD, but in my app I have passed credentials of account that has access in AD.
When I run Visual Studio with different user (adma) that has full connection access to Active directory, I am able to connect and fetch user details without any issue.
I don't know why it is happening even though adma account credentials are passed in the code.
public string getADattributes(string DN, string operation)
{
string path = "LDAP://xyz.com";
DirectoryEntry directoryEntry = new DirectoryEntry(path, "xyz\\adma", "abc", AuthenticationTypes.Secure);
using (directoryEntry)
{
DirectorySearcher objDSearcher = new DirectorySearcher();
objDSearcher.Filter = "(distinguishedName=" + DN + ")";//search user in AD using DN
objDSearcher.PropertiesToLoad.Add("whenCreated");
objDSearcher.PropertiesToLoad.Add("whenChanged");
objDSearcher.PropertiesToLoad.Add("EmployeeID");
objDSearcher.SearchScope = SearchScope.Subtree;
SearchResult result = objDSearcher.FindOne();
if (result != null)//if count!=0 that means user exist in ad
{
string createdDate = "";
string modifiedDate = "";
string employeeID = "";
if (result.Properties["whenCreated"].Count >0)
{
//able to come inside if statement when running visual studio using adma account but not when runnning with login account i.e., miminstall
createdDate = result.Properties["whenCreated"][0].ToString();
}
if(result.Properties["whenChanged"].Count>0)
{
modifiedDate = result.Properties["whenChanged"][0].ToString();
}
if(result.Properties["EmployeeID"].Count > 0)
{
employeeID = result.Properties["EmployeeID"][0].ToString();
}
}
return null;
}
}
Unless this is a one time task, one would typically create a task in task scheduler or a webapp under IIS.
If this is a console application, add a new Task under Task Scheduler, set the action to run your app (give it path to your app's exe), and set the task user as 'adma'
If it's part of a webapp, create a new application pool in IIS. Then right click the newly created app pool, go to Advanced Settings > Identity and provide the credentials for 'adma'. Then assign this application pool to your webapp.
If this is not going to be a scheduled task or a webapp, and occasional on-demand run, I believe adding Impersonation would be your best option. See this SO
Related
I am very new to the LDAP and Active Directory integration portion. Although I successfully configured my local machine to access Active Directory domain controller, when I deployed it on one of our server neither through IP address of the domain nor through domain name it was accessible.
My website is in ASP.NET C#.
It was getting this error:
The specified domain either does not exist or could not be contacted.
My method written to access AD is here:
private SearchResultCollection sResults { get; set; }
sResults = null;
public void SearchByUsername(string username)
{
try
{
// initiate a directory entry
private const string ldapPath = "LDAP://192.168.0.190/OU=Domain Users,DC=mydomain,DC=net"
dEntry = new DirectoryEntry(ldapPath);
dSearcher = new DirectorySearcher(dEntry);
dSearcher.Filter = "(&(objectClass=user)(sAMAccountname= " + username + "))";
performSearch();
getValues();
}
catch (Exception)
{
throw;
}
}
private void performSearch()
{
// perform search in Active Directory
sResults = dSearcher.FindAll();
}
private void getValues()
{
// loop through results of search
foreach (SearchResult sResult in sResults)
{
Employee emp = new Employee();
emp.CN = getProperty(sResult, "cn");
emp.FirstName = getProperty(sResult, "givenName");
emp.LastName = getProperty(sResult, "sn");
emp.Username = getProperty(sResult, "sAMAccountname");
emp.Email = getProperty(sResult, "mail");
Employees.Add(emp);
}
}
Above method works very well on my local machine both with IP address and domain name. Server where I am trying this to work is Windows Server 2012 R2.
I ran command nltest /dclist:mydomain.net and made sure that the server is within the domain as it returned me details. i.e. DC name, IP address, domain name.
Is there any syntactical issue I have run into? OR is it related to configuration issue like DNS ?
Also, like to mention as I tried searching about this on www.serverfault.com but couldn't gather much details.
Please suggest me direction.
Finally things seemed working out.
Earlier I mentioned that I made sure that the machine I am working on is in the domain but things were slightly different there. The machine I am trying to make things work is not actually in the domain but in the workgroup.
Below two Netdom commands helped me identifying this situation.
netdom verify - with this command it is found that machine hasn't joined domain.
netdom join - with this command, was able to join machine to network domain.
Reference: https://technet.microsoft.com/en-us/library/cc772217.aspx
Once it is in domain, Active Directory became immediately accessible.
I've been searching a lot on the web for Active Directories and windows authentications. I've succeded on getting the User information from the Domain AD but I had to pass the User name AND PASSWORD. So to put you into my context :
I have a Domain where I've set my users. Each Users will be connecting to the domain with their given credentials. So they will log into their PC and when they open a VS 2013 C# application it will check if the users Exists on the Domain if he does then return the AD information if the users doesn't exist then show a Login Page to enter the Credentials. Since I can have external users connecting to my Domain etc ...
right now I cannot access the AD with the user's windows authentication it gives me a Unkown error on the Search.FindOne();
public static void GetActiveDirectoryUser(string UserName)
{
try
{
// Create LDAP connetion object
DirectoryEntry ldapConnection = CreateDirectoryEntry();
// Create Search object which operates on LDAP connection object
// and set search object to only find the user specified
DirectorySearcher search = new DirectorySearcher(ldapConnection);
// Create results objects from search object
SearchResult result = search.FindOne();
if (result != null)
{
// User exists, cycle through LDAP fields (cn, telephonenumber, etc.)
ResultPropertyCollection fields = result.Properties;
foreach (string ldapField in fields.PropertyNames)
{
// Cycle through objects in each field e.g group membership
foreach (Object objCollection in fields[ldapField])
{
Console.WriteLine(String.Format("{0, -20} : {1}", ldapField, objCollection.ToString()));
}
}
}
}
catch (Exception e)
{
Console.WriteLine("Exception Caught:\n\n" + e.ToString());
}
}
static DirectoryEntry CreateDirectoryEntry()
{
string pathDomainName = "WinNT://MyDomain/Fred,Person";
DirectoryEntry ldapConnection = new DirectoryEntry(pathDomainName);
return ldapConnection;
}
This is the error I'm getting
System.Runtime.InteropServices.COMException (0x80005000): Unknown error (0x80005000)
at System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail)
at System.DirectoryServices.DirectoryEntry.Bind()
at System.DirectoryServices.DirectoryEntry.get_AdsObject()
at System.DirectoryServices.DirectorySearcher.FindAll(Boolean findMoreThanOne)
at System.DirectoryServices.DirectorySearcher.FindOne()
but when I use this string
string pathDomainName = "LDAP://MyDomain";
DirectoryEntry directoryEntry = new DirectoryEntry(pathDomainName, "Fred", "f12345!");
it works, it returns me all the AD for the user, but I've already logged in with the windows authentication, why would I pass the credentials again ? I just need to know that if the user exists on the domain that's it
Thanks
If you're on .NET 3.5 and up, you should check out the System.DirectoryServices.AccountManagement (S.DS.AM) namespace. Read all about it here:
Managing Directory Security Principals in the .NET Framework 3.5
MSDN docs on System.DirectoryServices.AccountManagement
Basically, you can define a domain context and easily find users and/or groups in AD:
// set up domain context
using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain))
{
// find a user
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "SomeUserName");
if(user != null)
{
// do something here....
}
// or alternatively: get the currently logged in user
UserPrincipal current = UserPrincipal.Current;
.....
}
The new S.DS.AM makes it really easy to play around with users and groups in AD!
I have a fairly odd requirement to be able to impersonate a user, when I'm already impersonating another, using C#.
I'm writing an app to allow the management of Active Directory users. This app will provide the ability for anyone in the company to view and maintain certain details about themselves (some of which will not actually be saved to Active Directory, but some of which will), for managers to be able to view and maintain details about their team, and for HR to be able to view and maintain details about anyone.
For obvious reasons I don't want to develop or test this against the live domain. We have recently ported all users over to this domain from another domain, which means I can actually test against the old domain without affecting anything. However, to enable me to do this I have to impersonate my old account on the old domain, which I do on loading the application.
Although for me everything will work fine as I'm setup as a domain admin, going forward obviously not all users will be domain admins, and won't be able to write to AD under their own account, and therefore we have another domain admin user setup specifically for this application, whenever data needs to be saved to AD that user is impersonated. This was working great before when I was testing against an Active Directory I'd setup on a virtual machine because I was logging onto the local domain, however that didn't allow me to step through the code in Visual Studio so debugging was slow, and hence I've stopped using that virtual machine and am using this old domain. Now I'm already impersonating another user (i.e. my old domain account), when it then tries to impersonate the domain admin user it fails with an "System.Security.SecurityException: Access is denied." exception. The line this fails on is just writing out some debugging information using "WindowsIdentity.GetCurrent().Name".
If I change my code so I'm actually logging in using the new domain admin rather than my old account, the first time it goes through it logs in successfully (so the credentials are correct), however when it then goes through and tries to do the same again to write to AD it fails with the above exception. Therefore I think it must be a problem with trying to do a nested impersonate.
Is it possible to do a nested impersonate?
Below is the code I'm using:
private static WindowsImpersonationContext ImpersonateUser(out string result, string sUsername,
string sDomain, string sPassword)
{
// initialize tokens
var pExistingTokenHandle = new IntPtr(0);
var pDuplicateTokenHandle = new IntPtr(0);
// if domain name was blank, assume local machine
if (sDomain == "")
{
sDomain = Environment.MachineName;
}
try
{
result = null;
const int logon32ProviderDefault = 0;
// create token
const int logon32LogonInteractive = 2;
// get handle to token
var bImpersonated = LogonUser(sUsername, sDomain, sPassword,
logon32LogonInteractive,
logon32ProviderDefault,
ref pExistingTokenHandle);
// did impersonation fail?
if (!bImpersonated)
{
var nErrorCode = Marshal.GetLastWin32Error();
result = "LogonUser() failed with error code: " + nErrorCode + "\r\n";
}
// Get identity before impersonation
result += string.Format("Before impersonation: {0}\r\n", WindowsIdentity.GetCurrent().Name);
var bRetVal = DuplicateToken(pExistingTokenHandle, (int)SecurityImpersonationLevel.SecurityImpersonation,
ref pDuplicateTokenHandle);
// did DuplicateToken fail?
if (bRetVal)
{
// create new identity using new primary token
var newId = new WindowsIdentity(pDuplicateTokenHandle);
var impersonatedUser = newId.Impersonate();
// check the identity after impersonation
result += "After impersonation: " + WindowsIdentity.GetCurrent().Name + "\r\n";
return impersonatedUser;
}
else
{
var nErrorCode = Marshal.GetLastWin32Error();
CloseHandle(pExistingTokenHandle); // close existing handle
result += "DuplicateToken() failed with error code: " + nErrorCode + "\r\n";
return null;
}
}
finally
{
// close handle(s)
if (pExistingTokenHandle != IntPtr.Zero)
{
CloseHandle(pExistingTokenHandle);
}
if (pDuplicateTokenHandle != IntPtr.Zero)
{
CloseHandle(pDuplicateTokenHandle);
}
}
}
When this is called for the nested impersonation which fails, "bImpersonated" is actually "true", as is bRetVal, which suggests its worked, however when it gets to "WindowsIdentity.GetCurrent().Name" it fails with the exception above.
I hope this makes sense, and would appreciate any assistance.
I access the AD properties thru the below method. It works fine in my Local VHD (where I'm the domain/local/enterprise Admin) - but the same doesn't work when I access from a Domain user(who has only local admin access).
But the same Domain user(only with local admin access) access all the AD property details using the ADExplorer(SysInternal) tools.
Is it because that is unmanaged code and have Windows APIs to access and in .Net I need domain admin or some privilege ?
Or is there another way - which I'm missing in .Net to access the AD Properties without having an extra domain-level-privilege ??
public void getCurrentUserADDetails(string UserName)
{
string ladpQueryStr = "LDAP://sp.com";
DirectoryEntry dirEntry = new DirectoryEntry(ladpQueryStr);
DirectorySearcher srch = new DirectorySearcher(dirEntry);
srch.Filter = "(cn=" + UserName.ToLowerInvariant().Trim() + ")";
srch.PropertiesToLoad.Add("name");
srch.PropertiesToLoad.Add("memberOf");
srch.PropertiesToLoad.Add("prop123");
SearchResult searcResult = srch.FindOne();
if (searcResult != null)
{
ResultPropertyCollection propertiesCollection = searcResult.Properties;
List<DisplayClass> grdDataList = new List<DisplayClass>();
foreach (string strKey in propertiesCollection.PropertyNames)
{
DisplayClass dispC = new DisplayClass();
dispC.pName = strKey;
dispC.pValue = Convert.ToString(propertiesCollection[strKey][0]);
grdDataList.Add(dispC);
}
dataGridView1.DataSource = grdDataList;
}
}
This is going to run in ASP.Net
thanks in advance :)
I assume you're using integrated authentification - in order for this to work you have to setup account delegation, unless you're running your application on a domain controller. This is a pretty tricky process, but there are a ton of info in Google.
By using Explicit authentication and changing the Search filter, i got the results.
DirectoryEntry dirEntry = new DirectoryEntry(path, username, password, AuthenticationType);
I search for a long time how I can define permitted logon hours on group like it is possible to do with user from the account tab in Active Directory.
I already have a class in c# that can make queries to returns a list of all permitted hours of a user with the help 'logonhours' properties.
public byte[] GetLogonHours(string userName, string password, string path)
{
DirectoryEntry entry = this.GetUserAccount(userName, path);
return (byte[])entry.Properties["logonHours"].Value;
}
public DirectoryEntry GetUserAccount(string username, string path)
{
using (DirectoryEntry objRootEntry = new DirectoryEntry(path))
{
using (DirectorySearcher objAdSearcher = new DirectorySearcher(objRootEntry))
{
objAdSearcher.Filter = "(&(objectClass=user)(samAccountName=" + username + "))";
SearchResult objResult = objAdSearcher.FindOne();
if (objResult != null)
{
return objResult.GetDirectoryEntry();
}
}
}
return null;
}
I used this post to help me understanding how I can query the logon hours:
http://anlai.wordpress.com/2010/09/07/active-directory-permitted-logon-times-with-c-net-3-5-using-system-directoryservices-accountmanagement/
It is important to understand that I don't want a feature to know when the last time a user has been logged. What I have is a feature that prevent a user logging at some moments.
What I want is a feature that can apply logon hours for a group of users and I can query the Active Directory with c# to get these logon hours information.
Thank you very much.
In my understanding logon hours information is a user information. As discribed in HOW TO: Limit User Logon Time in a Domain in Windows Server 2003 pointed by #Knite you can change it :
User by user, whatever if you loop on a list of user
Applying a GPO to an organizationalUnit users belongs to
In your case you can loop for all the members of a group and change their logon hours.
According to http://support.microsoft.com/kb/816666 , you should generate the list of users in a group and write their logon hours to a CSV file.