1

we are using Identity 2 with MVC 5 for our web project. Requirement is to be able configure impersonated user for web application in web.config like so

<system.web>
  <identity impersonate="true" userName="domain\impersonated" password="password" />
</system.web>

We implemented custom UserManager and configured authentication like this:

public partial class Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        app.CreatePerOwinContext(MyIdentityContext.Create);
        app.CreatePerOwinContext<MyUserManager>(MyUserManager.Create);
        app.CreatePerOwinContext<MySignInManager>(MySignInManager.Create);

        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider
            {
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<MyUserManager, MyUser, Guid>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentityCallback: (manager, user) => user.GenerateUserIdentityAsync(manager),
                    getUserIdCallback: (claimsIdentity) => (Guid.Parse(claimsIdentity.GetUserId()))),
            },
            ExpireTimeSpan = TimeSpan.FromMinutes(settingsFacade.GetSessionTimeout())
        });
    }
}

We implemented custom UserStore as well, interacting with database using EF. Connection string is configured to use Integrated Security=True to use our impersonated user to access database.

We implemented AccountController with ChangePassword Action

[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult ChangePassword(ChangePasswordViewModel model)
{
    if (!ModelState.IsValid)
    {
       return View(model);
    }

    var userGuid = User.Identity.GetUserGuid();
    var result = UserManager.ChangePassword(userGuid, model.OldPassword, model.NewPassword);

    if (result.Succeeded)
    {
        var user = UserManager.FindById(User.Identity.GetUserGuid());
        if (user != null)
        {
            SignInManager.SignIn(user, isPersistent: false, rememberBrowser: false);
        }
        return RedirectToAction("Index", new { Message = AccountMessageId.ChangePasswordSuccess });
    }

    AddErrors(result);

    return View(model);
}

When ChangePassword action is called it runs under impersonated user as expected. When I stop on break point inside ChangePassword

System.Security.Principal.WindowsIdentity.GetCurrent().Name = "domain\impersonated"

When I step into UserManager.ChangePassword and stop debugger inside our UserStore public Task FindByIdAsync(Guid userId), WindowsIdentity changed to user running application pool instead of impersonated user. Application user does not have access to database. We want only impersonated user to have access to database.

System.Security.Principal.WindowsIdentity.GetCurrent().Name = "domain\appPoolUser"

I've noticed when I replace synch extention method call

UserManager.ChangePassword(userGuid, model.OldPassword, model.NewPassword);

with asych method call

UserManager.ChangePasswordAsync(userGuid, model.OldPassword, model.NewPassword).Result;

WindowsIdentity does not change and FindByIdAsync is running in impersonated user context.

What are we doing wrong? Why synch and asynch methods behave differently. Is there any configuration of OWIN we are missing, to work correctly with impersonation? Thank you.

0 Answers0