MVC4 web getting the user details from wrong Active directory. - c#

I have MVC 4 web app deployed on 'Alpha' domain and web app is getting the Windows User details using the following code. We have trusted relationship between 3 different domains (Alpha, Beta and Gamma). When a user called Beta\bloggs login opens the web app following code returns the details of alpha\bloggs. Is there a way to get the right user from active directory.
Thanks in advance.
using (PrincipalContext context = new PrincipalContext(ContextType.Domain))
{
using (UserPrincipal user = UserPrincipal.FindByIdentity(context, username))
{
if (user != null)
{
HttpContext.Current.Session["FullUserName"] = fullName;
HttpContext.Current.Session["EmailAddress"] = user.EmailAddress;
}
}
}

As far as I understand, you should test against a global catalog.
Can you try to change you context like this :
PrincipalContext context = new PrincipalContext(ContextType.Domain, "DNSName.Of.GlobalCatalog.com:3268", "DC=yourcompany,DC=com");

Context.domain identifies the credential store to use. A connection to the correct domain would still be required to lookup information in another domain. Domain trust just specifies credential mapping, who in domain x maps to credential y in domain z.
I don't think that FindByIdentity can handle implicit domain trust lookups.

Related

Getting "Access is denied." when trying to update UserPrincipal object

I have a SharePoint solution with a custom application where a user should be able to change some properties in his own Active Directory object.
I am doing the following:
PrincipalContext ctx = ActiveDirectory.GetPrincipalContext("lab");
UserPrincipal user = ActiveDirectory.GetUserPrincipal(ctx, "Administrator");
user.DisplayName = user.DisplayName + DateTime.Now.ToString("ddMMyyyyHHmmss");
user.Save();
I am logged in to SharePoint as the domain administrator and i am trying to change my own DisplayName.
What is wrong with my code?
Update 20.04.2016
I have built a small Console Application with the following code:
static void Main(string[] args)
{
try
{
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "lab");
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, "administrator");
DirectoryEntry de = (user.GetUnderlyingObject() as DirectoryEntry);
user.DisplayName = user.DisplayName + DateTime.Now.ToString("ddMMyyyyHHmmss");
user.Save();
Console.WriteLine("OK");
Console.ReadKey();
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
}
This works fine! That means normally, that the Authentication goes wrong or the user which is logged into SharePoint is not getting used to connect to AD and do the changes. If this could be the case, how could i find out with which user i am doing the operation?
Update 20.04.2016 - 2
I have now tried to put the username and password in the PrincipalContext contructor as below:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "lab", "administrator", "pass");
This works, too! That means now definitely, that the user which is logged in to SharePoint is not used to create the PrincipalContext. But why? Normally code is always executed in the context of the current user!?
How can i find out which user is used to create the PrincipalContext and how can i change it that the logged in user is getting used?
I had the same problem, I resolved it like this:
In IIS, in the advanced settings of my app -> In Identity I add my service account (example: domain\service-account)
In my active directory, I give to this service account full control on folder and sub-folder where I want to create/update user (you need to modify view to see security tab -> right click -> view -> advanced features)
If you already have that, check if your service account is not disabled
And now everything is working :)

Using PrincipalContext & PrincipalSearcher to access Active Directory users from separate server

I have the following code to retrieve the current active directory users:
public List<DomainContext> GetADUsers(string term=null)
{
List<DomainContext> results = new List<DomainContext>();
string ADServerName = System.Web.Configuration.WebConfigurationManager.AppSettings["ADServerName"];
using (var context = new PrincipalContext(ContextType.Domain, ADServerName))
using (var searcher = new PrincipalSearcher(new UserPrincipal(context)))
{
var searchResults = searcher.FindAll();
foreach (Principal p in searchResults)
{
if (term == null || p.SamAccountName.ToString().ToUpper().StartsWith(term.ToUpper()))
{
DomainContext dc = new DomainContext();
dc.DisplayName = p.DisplayName;
dc.UserPrincipalName = p.UserPrincipalName;
dc.Name = p.Name;
dc.SamAccountName = p.SamAccountName;
results.Add(dc);
}
}
}
return results;
}
My current situation is as follows:
I am working on the development machine, where both the ASP.NET MVC web application and the Active Directory are on the same machine.
I am not passing usernames and password to get the AD users.
So I have the following concerns when I move my ASP.NET MVC web application which contains the above code to my UAT server:
On the UAT server the ASP.NET MVC web application and AD will be on two different machines.
To access the AD from certain machine I might need to send a username and password to the AD server.
So will my original code works if:
The AD and the ASP.NET MVC web application are on different machines?
And if the AD server required passing a user name and password along with?
There are two possibilities.
Either you pass the username/password to the PricipalContext or the identity of the application pool has enough priviledges to query the AD and you don't have to provide username/password then.
If the application server is in the AD, the latter is very convenient as there is no username/password in code and/or configuration files. If on the other hand the application server is not in AD, passing username/password in an explicit way is the only possibility for this to work.

Unable to extract information

I'm trying to query a domain to determine if:
User is a valid user (and has the correct password)
User is enabled
User belongs to group x
My development machine does not belong to this domain.
I want to specify the username and password via my application
I'm using the System.DirectoryServices.AccountManagement namespace as this seems to be the most efficient way doing this, however I've struggling to get even the most basic of information out of my domain controller.
I can explore LDAP via another tool.
First test is to collect user information, the code below returns null on user.
The user however is valid.
What am I doing wrong?
// set up domain context
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "server","CN=Users,DC=doom,DC=home", "ldapuser","password");
// get user contect
UserPrincipal user = UserPrincipal.FindByIdentity(ctx, IdentityType.Name, username);
//is user locked?
var locked = user.Enabled;
Update:
Having defined the bind method as below, I now receive error
"Information about the domain could not be retrieved (1355)."
var ctx = new PrincipalContext(ContextType.Domain, "server", "DC=doom,DC=home", ContextOptions.SimpleBind, "ldapuser", "password");
Sorted.
This answer resolves the two issues I came across when attempting to connect to a domain controller that I am not a member of.
This article get me the final answer:
http://elegantcode.com/2009/03/21/one-scenario-where-the-systemdirectoryservices-accountmanagement-api-falls-down/
you need to define the Bind in the context (i.e. ContextOptions.SimpleBind)
You must set up the domain server in your Network adaptors DNS settings as the first DNS server to use.
I can now connect to my AD and collect data.

Logon failure error when attempting UserPrincipal.FindByIdentity

I've been searching for solutions on this for a while now, but each thread a dead-end unfortunately.
I'm working on a C#/ASP.net web app that will only be used internally by our company. Anonymous access has been switched off both in IIS and my web.config file forcing IIS to use the windows authenticated user (Active Dir user).
My problem is that the following code works perfectly to get the required (or any) AD user:
using System.DirectoryServices.AccountManagement;
... other code ...
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "mydomain", "someADuser", "someADuserpassword");
UserPrincipal winuser = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "samaccountname");
"someADuser" used in the PrincipalContext above is the current logged in user through windows, thus authenticated and a valid AD user. Using the following code (with the exact same user still logged in) gives me a "Logon failure: unknown user name or bad password" error:
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, "mydomain");
UserPrincipal winuser = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "samaccountname");
It seems UserPrincipal.FindByIdentity doesn't use the logged in user's validated credentials for some reason if it's not specified in the PrincipalContext object - something I don't want to do.
Is it possible that the ctx aren't picking up the logged in Windows users for some reason, even if the necessary settings (i hope) is added to web.config :
<authentication mode="Windows"/>
<authorization>
<deny users="?"/>
</authorization>
And Anonymous access is completely disabled in IIS?
It seems UserPrincipal.FindByIdentity doesn't use the logged in user's validated credentials for some reason if it's not specified in the PrincipalContext object - something I don't want to do.
UserPrincipal.FindByIdentity doesn't care about the user's credentials at all. You're just performing a look up to see if the account exists. The reason you're getting an error is because the default user credentials (i.e. the identity that your web application is running as) doesn't have access to the directory, so it can't perform the look up. When you pass in the client's credentials to the PrincipalContext then the problem goes away because your client has a valid AD account with access to the directory.
You should investigate which identity is being used to run the application pool and make sure it has access to the directory.
Quite annoying as I though if anonymous access was turned off, the current principal would default to the user logged in to windows. It turns out it's not as indicated by #RogerN.
Using the following statement as mentioned by #TheKingDave, it basically impersonates the user logged in to windows and makes the current thread run on it's principal rather than the "ASP" (in my case) account.
Because all the users on our domain has query/read access to Active Directory, this shouldn't be a problem to get more detail on them, which is what I wanted in the first place.
The end code (was testing):
System.Web.HttpContext.Current.Request.LogonUserIdentity.Impersonate();
ctx = new PrincipalContext(ContextType.Domain, System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties().DomainName);
UserPrincipal winuser = UserPrincipal.FindByIdentity(ctx, IdentityType.SamAccountName, "whicheveraccount");
Hope it helps some1 in future! thx! ;-)
I did a lot of search/research to resolve the issue, but nothing worked, at last, all what I did was to add # to the servername, container, username & password like below:
app.CreatePerOwinContext(() => new PrincipalContext(ContextType.Domain, #"abc.net", #"OU=Customers,DC=abc,DC=net", ContextOptions.SimpleBind, #"abcnet\authuser", #"!$%MyPassword"));
And it worked. doh!
So I found out how to pass the impersonated identity. I had a situation where, as an admin, I wanted to unlock a user account automatically. I had to get the user names into variables and pass them in to the function like this:
string accountname = #"domain\username";
string admin = "adminusername";
string domain = Environment.UserDomainName;
string password = "password";
string dc = "WIN2K8DC1"; // example host name of domain controller, could use IP
// This determines the domain automatically, no need to specify
// Use the constructor that takes the domain controller name or IP,
// admin user name, and password
PrincipalContext ctx = new PrincipalContext(ContextType.Domain, dc, admin, password);
UserPrincipal winuser = UserPrincipal.FindByIdentity(ctx, accountname)
if (winuser != null)
{
WindowsImpersonationContext wic = Impersonation.doImpersonation(admin, domain, password); //class/function that does the logon of the user and returns the WIC
if (wic != null)
{
winuser.UnlockAccount();
}
}
Impersonation class functionality that can be used to return a WIC can be found on MSDN:
https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx

Create PrincipalContext using windows authentication

I'm creating a PrincipalContext object for retrieving a user's groups from our AD database (we use these then for authentication to various parts of the site).
This used to be done using forms authentication, so the code looked something like this
PrincipalContext pc =
new PrincipalContext(ContextType.Domain, "domain.com", username, password);
UserPrincipal usp =
UserPrincipal.FindByIdentity(pc, IdentityType.Guid, user.Guid.ToString());
foreach (var group in usp.GetGroups())
{
// Add group to collection
}
However, we recently switched to windows authentication, and I no longer have access to the user's password.
How can I search the AD database using the current user's credentials? I've tried using impersonation, but it throws an An operations error occurred error on the FindByIdentity line. If I forget about authentication all together I'm limited in the number of groups that are returned.
Here is a method I use, You could change it to return a collection:
public static List<string> getGrps(string userName)
{
List<string> grps = new List<string>();
try
{
var currentUser = UserPrincipal.Current;
RevertToSelf();
PrincipalSearchResult<Principal> groups = currentUser.GetGroups();
IEnumerable<string> groupNames = groups.Select(x => x.SamAccountName);
foreach (var name in groupNames)
{
grps.Add(name.ToString());
}
return grps;
}
catch (Exception ex)
{
// Logging
}
}
I assume you want the results IEnumerable, which is what I did here.
Anon's answer works for what I asked, but I also wanted to be able to search for other user's groups. The best way I've found to do this is to run the asp.net program's app pool under a service account, and then use my original code.
To do this in IIS Manager 7.5, go to the Application Pools, right click on the one your app is running under -> Advanced Settings, and change the identity from "ApplicationPoolIdentity" to a custom domain account.

Categories

Resources