1

I've read plenty of SO questions similar to my issue, but nothing that seems to touch all of it at the same time.

I have an ASP.NET MVC application using Windows Authentication with the application pool identity set to a dedicated service account. This allows us to use the WindowsPrincipal to authenticate the users against our system roles, but have any external systems (i.e., databases) authenticate our application against just the service account.

Everything works fine until we want to push data changes to the user's AD account, as company policy is that we have to do this as the authenticated user, but we obviously don't have users' passwords in order to use the DirectoryEntry overload.

In this case, the following returns a valid DirectoryEntry instance, but CommitChanges throws UnauthorizedAccessException "Access is denied". Even though the current Identity (on Thread.CurrentPrincipal and the request) are the current user; ImpersonationLevel is Impersonation.

using (var de = new DirectoryEntry("LDAP://" + userPath))
{
    de.Properties["telephoneNumber"].Value = phone;
    de.CommitChanges();
}

I've also tried using HostingEnvironment.Impersonate and WindowsIdentity.Impersonate on the WindowsIdentity from the user, but that returns an invalid DirectoryEntry with DirectoryServicesCOMException "An operations error occurred".

e.g. (not actual code),

using (var hei = System.Web.Hosting.HostingEnvironment.Impersonate(wi.Token))
using (var de = new DirectoryEntry("LDAP://" + userPath));

and

WindowsImpersonationContext ctx = wi.Impersonate();
using (var de = new DirectoryEntry("LDAP://" + userPath));

From what I've read, LDAP doesn't support this type of impersonation.

The only way I've been able to make it work (for myself only) is to set the application pool identity to myself, proving that the LDAP code is correct, but getting me no closer to how to authenticate correctly. I've tried <identity impersonate="true"/> (we normally have it false), but it didn't change anything.

Any guidance would be appreciated, as I'm running out of things to tweak.


Edit for some extra context

Almost a TL;DR:

This is a new piece of functionality, so the system is working as expected with regards to authenticating users through IIS. We get the valid WindowPrincipal and WindowsIdentity for the user.

Our users have the ability to modify certain fields within AD, such as "telephoneNumber", so we do not have access to (because we shouldn't need) a privileged account with which to make changes to users.
I'm able to make changes to my own AD data if I set everything to myself, but I'm unable to get impersonation to work while the application is running as the service account (or even as anonymous).

Ian Yates
  • 871
  • 8
  • 15
  • It sounds like you need to give your service account enough permissions to modify user objects within Active Directory? Since normal accounts can't edit other objects. – Steven V Sep 16 '14 at 15:55

1 Answers1

0

As far as I understand, AD will not allow a user to modify Directory Services information, regardless if it's their own account. You'll have to do this with an account that has elevated privileges (I'm not sure about the exact privileges, possibly domain admin).

If you want the users to be able to modify their own directory services properties then you'll have to pass that information along to a service running under elevated privileges.

If this is for authentication then you need to use LogonUser to get a token then use WindowsIdentity with that token. But remember that to impersonate a user you need a token that hasn't been duplicated. In order to get their username/password you'll need to write a custom Authentication Provider that uses basic authentication over HTTPS. (See IHttpModule) and events AuthenticateRequest to authenticate and check the WWW-Authenticate header, EndRequest to issue the challenge if necessary, PostRequestHandlerExecute to modify cookies if necessary.

EDIT: If I haven't addressed your issue please let me know. I'm not sure if you're having trouble authenticating the user or modifying their account properties while impersonating the user account.

Also, is your web.config set to

<identity impersonate="true" />
RyanH
  • 121
  • 1
  • 10
  • Using breaks the app as our database connection is authenticated against a service account, which I do not have the password for; it's set as our ApplicationPool Identity. – Ian Yates Sep 16 '14 at 15:20
  • So your Application Pool identity is set to a custom service account and your website is likely then set to pass-through authentication? – RyanH Sep 16 '14 at 15:34
  • Exactly. I get the authenticated user through as expected, with ImpersonationLevel set to Negotiate. – Ian Yates Sep 16 '14 at 15:54
  • I'm wondering if you are having a problem with the impersonation level. I'd think it would have to be set to Impersonation or Delegation. I see the following URL may be of some help to you: http://stackoverflow.com/questions/11079651/impersonation-in-asp-net-web-application-does-not-work-when-running-on-iis – RyanH Sep 16 '14 at 16:07
  • Just tossing in some additional troubleshooting ideas: 1) Maybe the service account is not allowed to impersonate accounts. See SeImpersonatePrivilege, http://support.microsoft.com/kb/821546 2) If you run this code: 'System.Security.Principal.WindowsIdentity.GetCurrent().Name' it should show you the Name of the Application Pool service account. Really though, we want it to be the account of the impersonated 'WindowsIdentity'. So if it isn't allowing the correct 'ImpersonationLevel' then 'WindowsIdentity'.Impersonate() will fail. – RyanH Sep 16 '14 at 16:15