Seems like my local machine does not have the required permissions to write data into the Active Directory. I can read data but can not change and update it. Upon calling the .save() command I receive the next message: "Access is denied".
I do not use any login details in order to log into the Active Directory and I wish not to use any as well. I know it has something to do with the application pools and IIS generally, but I can't seem to find a working solution other than trying and changing some minor options and features.
EDIT:
This is the code I'm trying to execute:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, "DOMAINANME"))
{
GroupPrincipal group = new GroupPrincipal.FindByIdentity(pc, "GROUPNAME");
group.Members.Remove(pc, IdentityType.SamAccountName, "USERNAME");
group.Save();
}
Your intuition is correct - you need proper permissions on the application pool account.
A simplest way would be:
Create a new domain user account
Add it to "Domain admins" group
In your iis server, locate the pool your application uses and change the pool identity to the newly created user
This way all requests from users to iis are run in the context of the domain admin and thus all requests from iis to AD will succeed - domain admins can operate the AD.
Although the above solution would work, it is probably not recommended. This is because the application does many things other than just connecting to the AD and if there are places that can be misused, you risk running unwanted requests in the domain admin context.
Usually then, such application would have two layers, a front layer and a back layer. The front layer runs in a restricted context and is responsible for all user requests. This is your application. A back layer is another web application that is not accessible from internet, only from the local intranet. This application runs in the domain admin context and serves as the gateway to the AD. The front application uses the back application to talk to the AD.
In order to execute code that needs specific permissions to your Active Directory, follow these steps:
Require the user to log into the ASP.NET application.
Have your code impersonate the currently-logged in user when executing the the Active Directory portion that needs that access.
There may be slight variations depending on the version of ASP.NET you are using, but basically...
Step 1
For the user login, just use the standard ASP.NET authentication configuration. Because it's the easiest to configure (and just works with AD) I'll document Windows Authentication here. This will prompt the user with a standard Windows login dialog box - where they will need to enter their domain credentials. To configure the application, make the following changes to the Web.config
<configuration>
...
<system.web>
...
<authentication mode="Windows" />
...
</system.web>
...
</configuration>
By default, ASP.NET should already know how to talk to the Active Directory when configured for Windows Authentication, so nothing else should be required, but if you find you need a separate Role Provider, feel free to take the one we use. (We also have instructions.) But again, you shouldn't need it.
Edit: You also need to make sure IIS is configured - using inetmgr.exe - to not allow anonymous access for the application. Otherwise, it will never prompt the user to log in. We typically disable Anonymous access and enable Windows and Basic authentication - because we need to support browsers that don't support NTLM.
Step 2
Now that you have an authenticated user, you can programmatically impersonate them. The following is adapted from Impersonating the authenticating user in code:
System.Security.Principal.WindowsImpersonationContext impersonationContext;
impersonationContext = ((System.Security.Principal.WindowsIdentity)User.Identity).Impersonate();
try
{
// Do your writing to the AD here
}
finally
{
impersonationContext.Undo();
}
I also just discovered (while searching for reference links for this answer) that this is all pretty well documented in the MSDN article How To: Use Windows Authentication in ASP.NET 2.0
Let us know how it goes :-)
Related
I have viewed and tried dozens of "answers" on StackOverflow, but none work.
I have a pretty simple aspx page with C# code behind.
The web site is on a Windows 2008R2 server.
The web site looks like (actual names changed):
MyServer - set for Anonymous Authentication
Application Pools
ASP.NET v4.0 Classic - .Net 4.0, Classic pipeline, App Pool Identity
MySiteAppPool - .Net 2.0, Integrated, runs under a Domain-wide Service identity (call it "mycompany\domservice")
Sites
MyMainSite - Windows Authentication, uses "MySiteAppPool"
"AutoPrint" - my web app, Windows Authentication, uses "ASP.Net v4.0 Classic" app pool, ASP.NET Impersonation enabled
My "AutoPrint" web app has a start page "AutoPrint.aspx" and code behind ("AutoPrint.aspx.cs", plus several classes).
The server and main site are not alterable, as there are several other applications under this site.
The user currently invokes this app with :
http://MyServer/AutoPrint
Everything I have tried is returning the "mycompany\domservice" result:
Request.LogonUserIdentity.Name.ToString() - returns "mycompany\domservice"
System.Environment.UserName.ToString() - returns "domservice"
System.Security.Principal.WindowsIdentity.GetCurrent().Name.ToString() - returns "mycompany\domservice"
What am I missing here? Why is this so hard?
Further clarifications:
"mycompany\domservice" - the "domservice" account is just an ActiveDirectory account in the "mycompany" domain that has permissions to read/write directories needed by the site and other applications. When installing the Site and additional web apps, we use that account as the "connect as" user.
What I am trying to do is to get the ActiveDirectory name of the Windows user account of the person who opened their browser and accessed this app. If user "JJONES" logs into Windows and launches the app with "http://myserver/autoprint", I want to get either "JJONES" or "mycompany\JJONES" as the user name.
If you use anonymous authentication, then the browser does not send any credentials (user id/password) to the server. Therefore if you want the client user id on the server, you have to use non-anonymous authentication, e.g,. Windows or Forms. You can use non-anonymous authentication and then allow or deny access to your web site to specific users or groups of users, or all users.
Thank you for all the helpful comments/suggestions.
The problem turned out to be a combination of factors. The App Pool I was using was using App Pool Identity (which has limited rights), so I had to use a specific account (the domain service account) in the "Connect as..." for the physical path credentials in order to access certain files.
Changing to use an App Pool that used an account with sufficient privileges (the domain service account) allowed me to leave the "Connect as..." using Pass-through authentication when converting to application.
Voila - I now get the user credentials using pretty much any of the proposed methods. After way too many hours of beating my head against the keyboard...
Have you looked at using HttpContext.User property ? This will give the current logged on user. After which point you may need to perform some nifty LDAP queries to get the username from AD.
See https://msdn.microsoft.com/en-us/library/system.web.httpcontext.user(v=vs.110).aspx
You may want to see the below link on how to search AD on the link "How can I search Active Directory by username using C#?"
Hope this helps you.
In my Website, Users who has logged in are able to change their profile pictures, and this process includes saving the uploaded image to a folder in the website's root directory.
When I tested it, I received an Error that I should grant access to this specific folder using permissions.
I do not have control over the Control Panel, the one who does said that he did grant the Images folder a READ and WRITE permissions to Others.
After Testing it again, once again the same error, so I edited web.config and included:
<identity impersonate="true"/>
And now everything seems to work perfectly. BUT, what did I just do here? Is there any security risk? Did I grant anonymous access to my website for everyone?
BUT, what did I just do here?
You are now running your website under the identity of the client user.
Is there any security risk?
That would depend on the permissions that this account has on the server. Usually it is bad practice to run a website with accounts that have lots of privileges. Ideally you should configure your website to run under an account that you explicitly grant privileges to the required folders.
The problem with your approach is that if another user that doesn't have access to the specified folder visits your website, it won't work for him. If on the other hand this is expected behavior then you are probably fine by impersonating user identities.
Did I grant anonymous access to my website for everyone?
No, this has nothing to do with authentication.
What you have done is given user rights to work under logged in user.
And there is a security risk for making impersonate true.
If you are on production, I would recommend you to read this article
http://support.microsoft.com/default.aspx?scid=kb;en-us;329290
"Using impersonation in the web.config allows you to override whatever identity was configured for the Application Pool the app is running under - it's just a more fine grained method to control identity ( on the app level vs. the ApplicationPool level), so you could have two apps run on the same AppPool, but one of them uses impersonation to use another identity."
courtesy: App pool identity versus impersonation identity?
Given that I have a WCF service using windows authentication, and I want to impersonate them and call another WCF service, like so:
using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
// call another WCF service
}
I've set all the config settings and it works fine, as long as on the client side,they include the following line:
client.ClientCredentials.Windows.AllowedImpersonationLevel = TokenImpersonationLevel.Delegation;
But, how do I verify before trying to make the call that the user token has delegation rights? i.e. the client, which I don't control, has set the AllowedPersonationLevel?
If they haven't set it, all sorts of weird exceptions get thrown (like cannot load assembly X etc).
Ideally, I'd like to be able to do the following:
using (ServiceSecurityContext.Current.WindowsIdentity.Impersonate())
{
if (UserDoesntHaveDelegationRights())
throw new SecurityException("No delegation rights");
// call another WCF service
}
Note that WindowsIdentity.GetCurrent().ImpersonationLevel is always equal to TokenImpersonationLevel.Impersonation, so that unfortunately is not an option.
There might be some confusion here in definitions. In terms of impersonation levels a windows identity can be:
Impersonated - the service can impersonate the user locally
Delegated - the service can impersonate the user remotely
The ability to delegate is so powerful that its highly restricted in Active Directory:
The Client has to allow delegation
The service account which is doing the delegation must be marked as "trusted for delegation" in Active Directory.
Here's how to enable an account for delegation. It requires a Active Directory domain admin to the make the change. Every corporate environment that I've ever worked in has a policy that does not allow Delegation.
Back to your question:
So while TokenImpersonationLevel.Delegation exists, its considered a security risk and rarely (if ever) used. TokenImpersonationLevel.Impersonation is the highest level that you will probably ever get.
TokenImpersonationLevel.Impersonation is useful. You can still connect to a database or make a remote service call as the impersonated user. But a remote service (not on the same box) can't impersonate the user a second time. The basic rule of thumb is "impersonation enables two machines hops". If the user's credentials have to "hop" farther, it will fail.
If you need to pass a user's credentials between many servers the best choice is a federated security model such as Windows Identity Foundation (WIF). See Identity Management in Active Directory.
What about
if (WindowsIdentity.GetCurrent().ImpersonationLevel != TokenImpersonationLevel.Delegation) ...
I have a few newbie web service/Windows rights questions since I've typically been a LINUX/embedded dev in the past.
What directories does a web service executing on a server have access to by default?
I ask because I tried to write to C:\ and got an access violation. I kind of assumed I would in this case, but I assume there are some areas of the file system the web service can write to and read from by default, right? Or is it just the current working directory?
*How can I give a web service permissions to look at a new directory it didn't have default access to?*
This is C# - ASMX - .NET 3.5 - IIS
The WebService doesn't really have any associated access controls associated with it (in a sense). It is however tied to the access control of the user account which is being used to run the application. By default this is usually some built in user account with limited permissions.
IIS uses a number of built-in Windows accounts, as well as accounts
that are specific to IIS. For security reasons, you should be aware of
the different accounts and their default user privileges. It can be a
security risk to change the identity of a worker process so that it
runs as an account with a high level of access, such as the
LocalSystem user account.
See a list of possible user accounts here: http://www.microsoft.com/technet/prodtechnol/WindowsServer2003/Library/IIS/3648346f-e4f5-474b-86c7-5a86e85fa1ff.mspx?mfr=true
If you have Anonymous Authentication enabled you can usually check the settings on that to see which account is being used to run the web service. (Depending on which version of IIS you are using, clicking Edit should let you view the default user account)
After finding the account, usually you will have to explicitly grant it the permissions on the folders (read and write) that you want to give it access to. The default user account usually has pretty limited access (and for good reason). You can grant permissions on the Security tab of the properties of any of the folders on a Windows file system (Properties->Security)
If you're using Windows Authentication, then you should have the same access rights as the authenticated user using the application as long as the resources are local to the IIS server.
I have the following scenario where I’m planning in using windows authentication.
1.1) I have a web server which will run within a domain.
1.2) The web site will run under the credentials of a domain user with a set of configured permissions (One which will be allowed access to the file system, SQL server database etc).
1.3) Users visiting the web site will belong to the same domain, so I’m planning in using windows authentication.
So at this point, an authenticated user, would access the site, but I guess that from code, “CurrentUser” would be the one under which the site is running.
I’d like the following.
2.1) To authenticate the user accessing the site with windows authentication. (Domain controller would be responsible for this).
2.2) For the site to run under the configured user from step 1.2. So it would have all of its permissions.
2.3) But I’d like to know the initial user used to authenticate from (step 2.1).
This way I could do the following:
3.1) User “A” decides to access the site, as he belongs to the same domain as the web server, he authenticates successfully.
3.2) From code I detect that “A” authenticated, so I’ll go and fetch his roles. “Role1, Role2, Role3”.
3.3) I then want the code to run under the user configured in step 1.2, but I’ll assign the Principal all of the roles retrieved from 3.2.
I’ve thought that maybe I could use Impersonation for this.
4.1) So user “A” decides to access the site and authenticates.
4.2) The site would initially run with “A” credentials, so the “CurrentUser” would be “A”.
4.3) Switch the user (somehow) back to the one from 1.2
4.4) I could retrieve all of 4.1 configured Roles.
4.5) Assign the Current Principal the roles retrieved from 4.4.
So in the end the web site will use Windows Authentication with Impersonation, but from code I’d switch back to user 1.2.
If you’ve reached this point thanks for reading! I’d like to know if this is possible and if it seems achievable or if I’m overcomplicating things.
Also suggestions in how can I plug into and where to do all the role retrieving and user switching.
Many thanks!
UPDATE 1
# Code Jammr , you're right, no need to do any crazy stuff. But I think I still need to look into HttpModules,..
After doing a few tests, searching etc...
I've started to understand the difference between these IIdentity objects:
HttpContext.Current.User.Identity
Thread.CurrentPrincipal.Identity
WindowsIdentity i2 = WindowsIdentity.GetCurrent();
I posted another question to help me understand them:
Help understanding impersonation
I think this answers my question.
There are several code samples out there for doing Impersonation. Most involve dealing with tokens and Win API calls. But if you really must do it this way, I say this not knowing what your webserver type is. IIS 6 or IIS7, then there are many code samples out there to guide you along.
Here is one link for ya that pretty much gives you a starting point.
http://msdn.microsoft.com/en-us/library/aa331755(v=vs.71).aspx
Here is a link on AD authentication and you may not have to do anything crazy.
http://support.microsoft.com/kb/326340
You may want to look into asp.net impersonation, app pool settings, etc... to see if there is a better way.