Search code examples
c#model-view-controllerwindows-authenticationiis-10

Windows Authentication HttpContext.Current.User returns previous website user


.NET Framework : 4.6.1 IIS : 10.0

Hi everyone,

I built an internal WebSite, with Windows Authentication. Every configurations seem to be good :

web.config specifies Windows Authentication mode and denies anonymous users. IIS configuration is also well configured by enabling Win Auth and disabling Anonymous. Providers are "NTML" and "Negotiate".

The very first page of the website is a simple table with data picked from a third Server : SQL.

Everything worked fine as i were testing it with ISS Express until li went to "real world" testing. Let's say i'm userA, and my test user is userB.

userA has advanced rights, meaning he's supposed to get more data from SQL. userB has less rights, and only sees data filtered by the request itself.

The data access is not the issue, everything works fine and are filtered correctly.

The issue is that, when userA visits the website

  1. he has to randomly entire credentials multiple times from 0 up to 10 times (highest counted), and it can even lock the user in the Active Directory for no reasons since the credentials are correct, and
  2. if userB right after, on a second computer visits the websites, sometimes the credentials are asked, sometimes not, but most importantly, the name displayed at the header, and the data he gets are the one of userA, until i refresh the page multiple times (random number here again) and eventually refreshes to his name.

I tried multiple configuration changes without any success (refreshing the AppPool and Site on IIS each modifications).

Using System.Web.HttpContext.Current.User.Identity.Name, or User.Identity.Name alone. Using [Authorize] header for each Controller methods. Disabled caching in web.config and in IIS (system.webServer/caching) Disabled authPersisNonNTLM and authPersistSingleRequest in system.webServer/security/authentication/windowsAuthentication

Basically, to be straight forward, the issue is that User.Identity.Name or more globally HttpContext.Current.User Object returns the last site visitor, instead of the current.

[EDIT]
To give some details, my default page Controller is like so :

    public ActionResult List()
    {
        var username = System.Web.HttpContext.Current.User.Identity.Name;

        string userDisplayName = ADChecks.GetUserDisplayName(username);

        ViewBag.Message = "NewCommers List";
        ViewBag.UserDisplayName = userDisplayName;

        return View();
    }

And the page is :

@model IEnumerable<NewComer.Models.NewComerModel>

@{
    ViewBag.Title = "New Comer - List";
}

<p>
    @if (NewComer.App_Tools.ADChecks.IsRH(System.Web.HttpContext.Current.User.Identity.Name) || NewComer.App_Tools.ADChecks.IsAdmin(HttpContext.Current.User.Identity.Name))
    {
        <div class="col-4">
            <input type="button" value="Create New" class="btn btn-secondary valid w-100 mw-100" onclick="location.href='@Url.Action("Create", "Home")'" />
        </div>
    }
</p>
<table id="ListViewTable" class="table table-responsive table-striped">
    <thead>
        <tr>
            <th></th>
            <th>ID</th>
            <th>First Name</th>
            <th>Last Name</th>
            <th>Contract Type</th>
            <th data-bs-toggle="tooltip" data-bs-placement="top" title="MM/DD/YYYY">Date Start</th>
            <th data-bs-toggle="tooltip" data-bs-placement="top" title="MM/DD/YYYY">Date End</th>
            <th></th>
            <th></th>
            <th></th>
        </tr>
    </thead>
</table>

There are some Javascript in this page that launches the 'LoadTable' function with DataTables in an $.ajax request


Solution

  • I ended up switching to Anonymous, and handle Windows Authentication "manually" with a Login form/page.

    Since i do not know how to convert DirectoryServices.UserPrincipal object to HttpContext.Current.User object, i'm working with Cookies to check the identity on all steps and revert user to login when it expires.