I am developing an intranet Web App using windows auth. I am using Claims Transformation using custom ClaimsAuthenticationManager.
public class ClaimsTransformer : ClaimsAuthenticationManager
{
public override ClaimsPrincipal Authenticate(string resourceName, ClaimsPrincipal incomingPrincipal)
{
if (!incomingPrincipal.Identity.IsAuthenticated)
{
return base.Authenticate(resourceName, incomingPrincipal);
}
var newPrinciPal = CreateApplicationPrincipal(incomingPrincipal.Identity.Name);
EstablishSession(newPrinciPal);
return newPrinciPal;
}
private void EstablishSession(ClaimsPrincipal newPrinciPal)
{
var sessionToken = new SessionSecurityToken(newPrinciPal, TimeSpan.FromHours(8))
{
IsPersistent = false,
IsReferenceMode = true
};
FederatedAuthentication.SessionAuthenticationModule.WriteSessionTokenToCookie(sessionToken);
}
private ClaimsPrincipal CreateApplicationPrincipal(string userName)
{
new SecurityManager().LoginUser(userName);
var claims = new List<Claim>();
claims.Add(new Claim(ClaimTypes.Name, userName));
RPSUser originalIdentity = Thread.CurrentPrincipal.Identity as RPSUser;
if (originalIdentity != null)
{
RPSUserInformation userDetails = originalIdentity.UserDetails;
int splitIndex = userDetails.FullName.IndexOf(' ');
claims.Add(new Claim(ClaimTypes.GivenName, userDetails.FullName.Substring(0, splitIndex)));
claims.Add(new Claim(ClaimTypes.Surname, userDetails.FullName.Substring(splitIndex + 1)));
claims.Add(new Claim(ClaimTypes.Email, userDetails.Email));
claims.Add(new Claim(ClaimTypes.WindowsAccountName, userDetails.LanId));
}
RPSUser transformedIdentity = new RPSUser(new ClaimsIdentity(claims, "Custom"));
transformedIdentity.UserDetails = originalIdentity.UserDetails;
return new RPSPrincipal(transformedIdentity, null);
}
}
In Global.ascx I have this code
protected void Application_PostAuthenticateRequest()
{
try
{
var newPrincipal = FederatedAuthentication.FederationConfiguration
.IdentityConfiguration
.ClaimsAuthenticationManager.Authenticate(string.Empty, ClaimsPrincipal.Current);
SecurityManager.SetIdentityToThread(newPrincipal as RPSPrincipal);
}
catch
{
}
}
Also I am able to retrieve/deserialize the Cookie from this piece of code in Global.asax
void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e) { var extendSession = true;
if (Request.UrlReferrer.AbsolutePath.Equals("/"))
{
var principal = e.SessionToken.ClaimsPrincipal as RPSPrincipal;
SecurityManager.SetIdentityToThread(principal);
if (extendSession)
{
e.SessionToken = new SessionSecurityToken(
e.SessionToken.ClaimsPrincipal,
TimeSpan.FromHours(8))
{
IsPersistent = false,
IsReferenceMode = true
};
e.ReissueCookie = extendSession;
}
}
}
But the problem is even though I am able to deserialize the cookie to the custom Principal (RPSPrincipal) in this event and able to set it to thread, subsequently in the Application_PostAuthenticateRequest (for the same request) we are losing the Custom Principal. We are just getting ClaimsPrincipal there.
What am I doing wrong here? How could I ensure that windows authentication does not overwrite principal when there is a custom principal is already set and IsAuthenticated property of Identity is already set to true?
Or is there anyway to access the sessionSecurityToken at Application_PostAuthenticateRequest event?