I set the current user to a ClaimsIdentity in a WebAPI Messagehandler derived from DelegateHandler, and retrieve the username and user id from the controller.
It used to work quite fine. Now something has changed (In RC, and probably the last Preview version too) and instead of getting my ClaimsIdentity in the ApiController I suddenly get a WindowsIdentity (unauthenticated, though). I thought maybe some window authentication was kicking in, but I've never used that, and it is disabled under the properties window for the project (also the WIndowsIdentify I receive is not actually authenticated).
It's practically impossible to find examples with the new RC. Did something break, or am I doing something wrong? While I'm at it, some info on the new AuthenticationFilters would be awesome, thanks!
I can set breakpoints and trace the Identity being set correctly to Thread.Principal AND to HttpContext.Current.User in the messagehandler, and suddenly it's gone in the controller. I can send a demo project if required, but since its more than 4mb I can't attach it.
Key elements:
public class AuthHandler : DelegatingHandler
{
protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
string apiKey = request.GetQueryNameValuePairs().FirstOrDefault(k => k.Key == "apiKey").Value;
if (!string.IsNullOrWhiteSpace(apiKey))
{
string[] token = apiKey.Split('*');
var claims = new List<Claim>{
new Claim(ClaimTypes.Name, token[1]),
new Claim(ClaimTypes.NameIdentifier, token[0])
};
var principal = new ClaimsPrincipal(new[] { new ClaimsIdentity(claims, "Digest") });
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
HttpContext.Current.User = principal;
}
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
response = request.CreateResponse(HttpStatusCode.Unauthorized);
}
return response;
}
}
}
Test Controller:
public IEnumerable<string> Get()
{
var id = (System.Security.Claims.ClaimsIdentity)User.Identity;
if (id.Claims.FirstOrDefault(i => i.Type == System.Security.Claims.ClaimTypes.NameIdentifier) != null)
{
var userId = id.Claims.FirstOrDefault(i => i.Type == System.Security.Claims.ClaimTypes.NameIdentifier).Value;
return new string[] { id.Name, userId };
}
return new string[] { "No", "User", "Returned" };
}
Test call:
http://localhost:1646/api/test?apiKey=12345667*myusername
Comments: Hi Daniel, Well, it's certainly possible I failed to use the authentication filter correctly, since the only examples of it's use are using the old non-async versions. I hacked something together using the code from the HostAuthenticationFilter Source as inspriration, and yet the identity I retrieved on my controller seemed to still contain values from the WindowsIdentity. I also failed in my quest to short circuit the pipeline and return an errormessage with a 401 statuscode when authentication failed, and a bunch of other stuff that would have been nice. I would be happy to try again, and report back, if you would be kind enough to provide me with an example implementation of the authentication filter with async methods. Best regards, Martin
It used to work quite fine. Now something has changed (In RC, and probably the last Preview version too) and instead of getting my ClaimsIdentity in the ApiController I suddenly get a WindowsIdentity (unauthenticated, though). I thought maybe some window authentication was kicking in, but I've never used that, and it is disabled under the properties window for the project (also the WIndowsIdentify I receive is not actually authenticated).
It's practically impossible to find examples with the new RC. Did something break, or am I doing something wrong? While I'm at it, some info on the new AuthenticationFilters would be awesome, thanks!
I can set breakpoints and trace the Identity being set correctly to Thread.Principal AND to HttpContext.Current.User in the messagehandler, and suddenly it's gone in the controller. I can send a demo project if required, but since its more than 4mb I can't attach it.
Key elements:
public class AuthHandler : DelegatingHandler
{
protected async override System.Threading.Tasks.Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
{
string apiKey = request.GetQueryNameValuePairs().FirstOrDefault(k => k.Key == "apiKey").Value;
if (!string.IsNullOrWhiteSpace(apiKey))
{
string[] token = apiKey.Split('*');
var claims = new List<Claim>{
new Claim(ClaimTypes.Name, token[1]),
new Claim(ClaimTypes.NameIdentifier, token[0])
};
var principal = new ClaimsPrincipal(new[] { new ClaimsIdentity(claims, "Digest") });
Thread.CurrentPrincipal = principal;
if (HttpContext.Current != null)
HttpContext.Current.User = principal;
}
HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
response = request.CreateResponse(HttpStatusCode.Unauthorized);
}
return response;
}
}
}
Test Controller:
public IEnumerable<string> Get()
{
var id = (System.Security.Claims.ClaimsIdentity)User.Identity;
if (id.Claims.FirstOrDefault(i => i.Type == System.Security.Claims.ClaimTypes.NameIdentifier) != null)
{
var userId = id.Claims.FirstOrDefault(i => i.Type == System.Security.Claims.ClaimTypes.NameIdentifier).Value;
return new string[] { id.Name, userId };
}
return new string[] { "No", "User", "Returned" };
}
Test call:
http://localhost:1646/api/test?apiKey=12345667*myusername
Comments: Hi Daniel, Well, it's certainly possible I failed to use the authentication filter correctly, since the only examples of it's use are using the old non-async versions. I hacked something together using the code from the HostAuthenticationFilter Source as inspriration, and yet the identity I retrieved on my controller seemed to still contain values from the WindowsIdentity. I also failed in my quest to short circuit the pipeline and return an errormessage with a 401 statuscode when authentication failed, and a bunch of other stuff that would have been nice. I would be happy to try again, and report back, if you would be kind enough to provide me with an example implementation of the authentication filter with async methods. Best regards, Martin