I am trying to do something a bit hacky - but feels like it might be doable.
Essentially I have an ASP.Next application that uses Windows authentication.
In some scenarios, I want privileged (admin) users to be able to "spoof" different users (use different names, and assign themselves fewer application roles). The info about the user and roles to spoof are passed in HTTP headers on the request.
What I wanted was for the application to first use Windows to authenticate that the original user is an admin (and thus is allowed to spoof other users). And then set the HTTP context's user property to a generic principal (built from info from the request), so that following code would be essentially oblivious to the spoofing.
I have put the code that changes the User in a System.Web.IHttpModule
(see code below).
When using other authentication modes (e.g. Forms) the following code works; but with windows authentication, although everything looks good in the debugger (I see the code being executed and the request has been authenticated) by the time EndRequest is invoked, the request response always ends up as 401. (If I comment out the line that sets the user, then everything is fine).
What I would like to know is; where is the code that is setting the response code to 401? And can it be avoided / disabled? Is what I am attempting just not possible?
Many thanks
using System;
using System.Security.Principal;
using System.Web;
using System.Net;
namespace ACME
{
public sealed class SpoofModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest += ScrapeFlowedUser;
context.EndRequest += HandleEndRequest;
context.AuthorizeRequest += ScrapeFlowedUser;
}
public void HandleEndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Response.StatusCode == (int)HttpStatusCode.Unauthorized)
{
// Always end up here if I set HttpContext.Current.User to any other user.
}
}
private void ScrapeFlowedUser(object sender, EventArgs e)
{
var userIdentity = HttpContext.Current.User?.Identity;
if (userIdentity.IsAuthenticated && userIdentity.Name == "ACME\\Admin")
{
HttpContext.Current.User = CreateUserFromDataOnRequest();
}
}
private GenericPrincipal CreateUserFromDataOnRequest()
{
string userName = "JoeBlogs"; // the name and roles will be passed in the request headers.
string[] roles = new[] { "Role1", "Role2" };
var id = new GenericIdentity(userName);
return new GenericPrincipal(id, roles); // The generic principal has IsAuthenticated == true.
}
public void Dispose()
{
}
}
}
Web config
<modules>
<add name="Spoof" type="ACME.SpoofModule, ACME.App" />
</modules>