It's logical that the current user is null in GrantResourceOwnerCredentials. That's the point where you'll need to validate the credentials, username / password and set the user in the context.
It seems that you want to impersonate the (child)user. This is what you can do. Please note that this is pseudo code. Read the comments:
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
// assume that context contains username, password and childusername
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
// First validate the credentials of the parent:
var appUser = await userManager.FindAsync(context.UserName, context.Password);
// Check if user is valid AND user is parent of childUserName
// now find the user to impersonate
appUser = await userManager.FindByNameAsync(context.ChildUserName);
// If found, appuser is child user:
// you may add information so you know that the user was impersonated by a parent user.
var propertyDictionary = new Dictionary<string, string> { { "userName", appUser.UserName }, { "parent", context.UserName } };
var properties = new AuthenticationProperties(propertyDictionary);
var oAuthIdentity = await appUser.GenerateUserIdentityAsync(userManager);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
// Token is validated.
context.Validated(ticket);
// parent is now child user.
}
This is just the idea to impersonate the child. You'll need to add the flow for normal login: where child logs in or parent didn't specify a childUserName.
-- update --
Based on your comment I've updated the answer.
The access_token is selfcontained. You cannot change or update it. So you cannot switch the current subset user without having the parent user to login again. Since you cannot get a new or other access_token with the current access_token.
So there are two options: use the flow described above or add claims to the parent user. This will not set the current user, but you can add the current subset user in the url.
You can also add an additional header that contains the subsetUser. In that case you won't need to check the url.
If you want to add claim(s), I suggest you use ApplicationUser like the template:
public class ApplicationUser : IdentityUser
{
public List<string> SubsetUsers { get; set; }
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
{
var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
userIdentity.AddClaim(new Claim("subsetUsers", string.Join(",", SubsetUsers)));
return userIdentity;
}
}
Or something like this. I do not know how and where you persist the subset users.
To get the list of available subset users, assuming the subset user is from the url:
user = (System.Security.Claims.ClaimsIdentity)User.Identity;
var subset = user.FindFirstValue("subsetUsers").Split(',');
if(subset.Contains(UserNameFromUrl))
IsValid = true;
You cannot use the default AuthorizeAttribute to validate this, but you can add your own filter.