I am trying to port code from IdentityServer3 which used PreAuthenticate to provide a temporary impersonation of a user into a client application for our admins.
Following with the thread in here, I am overriding ProcessInteractionAsync in a custom IAuthorizeInteractionResponseGenerator. This works great and I have everything working, BUT, I can't add an extra claim to be sent back to the client application so that it knows this is an impersonated id_token. In replacing the Subject on ValidatedAuthorizeRequest in my override, I add an additional claim that specifies the user who started the impersonation but this claim does not follow through in the id_token or the access token. Here is my override:
public override async Task<InteractionResponse> ProcessInteractionAsync(ValidatedAuthorizeRequest request, ConsentResponse consent = null)
{
string impersonatedUserName = request.GetPrefixedAcrValue("Impersonate:");
if (!string.IsNullOrWhiteSpace(impersonatedUserName))
{
if (request.Client.AllowedScopes.Contains(Constants.ClaimTypes.Impersonation))
{
var currentUser;
var impersonatedUser;
//Omited code to verify eligibility to impersonate user
if (impersonatedUser != null)
{
IEnumerable<string> requestedClaimTypes = request.Client.AllowedScopes;
IdentityServerUser idSrvUser = new IdentityServerUser(impersonatedUser.Id.ToString())
{
AuthenticationTime = Clock.UtcNow.UtcDateTime,
DisplayName = impersonatedUser.UserName,
IdentityProvider = !string.IsNullOrEmpty(impersonatedUser.PasswordHash) ? IdentityServerConstants.LocalIdentityProvider : "external"
};
ProfileDataRequestContext context = new ProfileDataRequestContext(
idSrvUser.CreatePrincipal(),
request.Client,
nameof(AuthorizeInteractionResponseGenerator),
requestedClaimTypes);
await Profile.GetProfileDataAsync(context);
//Need this claim to flow through to client
context.IssuedClaims.Add(new Claim(Constants.ClaimTypes.Impersonation, currentUser.UserName));
foreach (Claim claim in context.IssuedClaims)
{
idSrvUser.AdditionalClaims.Add(claim);
}
ClaimsPrincipal newSubject = idSrvUser.CreatePrincipal();
request.Subject = newSubject;
Logger.LogInformation("Impersonation set, returning response");
return new InteractionResponse();
}
else
{
Logger.LogWarning("Invalid attempt to impersonate user");
return new InteractionResponse { Error = "Invalid attempt to impersonate user" };
}
}
else
{
Logger.LogWarning("Client does not support impersonation!");
return new InteractionResponse { Error = "Client does not support impersonation" };
}
}
return await base.ProcessInteractionAsync(request, consent);
}
I added a scope for this special claim that the client requests, but it still is not being included. I feel like there is something obvious I am missing here, how do I add an extra claim to one of the tokens? Or is there a better way to signal the client who started the impersonation?