Reputation: 1738
I have a WebAPI 2 project that uses a token issued by an IdentityServer3 token provider. In my Startup.cs file I have the IdentityServerBearerTokenAuthorization middleware implemented and it, along with a global AuthorizateAttribute filter, is requiring that a valid token be present in the request. However, I have also added ClaimsTransformation so I can extract "roles" from the claims in either a token issued using the implicit flow or a token issued for the client credential flow. I can't use a scope here because, I have 1 scope that gives you access to use my API, but all clients are not allowed to use all api endpoints.
Startup.cs
JwtSecurityTokenHandler.InboundClaimTypeMap.Clear();
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions()
{
Authority = ConfigurationManager.AppSettings["IdentityServer"],
RequiredScopes = new[] { "my.api" },
});
httpConfig.MapHttpAttributeRoutes();
httpConfig.Filters.Add(new AuthorizeAttribute());
//SwaggerConfig.Register(httpConfig);
app.UseAutofacMiddleware(container);
app.UseAutofacWebApi(httpConfig);
app.UseWebApi(httpConfig);
app.UseClaimsTransformation(identity =>
{
var principal = new ClaimsPrincipal(identity);
if (!identity.HasClaim(c => c.Type == "name") && identity.HasClaim(c => c.Type == "client_name"))
{
identity.Identities.First().AddClaim(new Claim("name", identity.Claims.First(c => c.Type == "client_name").Value));
}
//we want to remove the client_ from the claims so we can evaluate clients like they are users
if (identity.Claims.Any(c => c.Type.Contains("client_")))
{
foreach (var claim in identity.Claims.Where(c => c.Type.Contains("client_")))
{
var newClaimType = claim.Type.Replace("client_", "");
identity.Identities.First().AddClaim(new Claim(newClaimType, claim.Value));
}
}
//set the scopes as roles also
if (identity.Claims.Any(c => c.Type == "scope"))
{
identity.Identities.First().AddClaims(identity.Claims.Where(c => c.Type == "scope").Select(c => new Claim("role", c.Value)));
}
return Task.FromResult(principal);
});
On my APIController operation, I have an Authorize attribute with a Roles property defined. The global Authorize attribute is working but the check for roles never happens. Am I missing something? \ API Controller
[HttpDelete]
[Authorize(Roles = "item.deleter")]
[Route("{itemId:guid}")]
public async Task<HttpResponseMessage> DeleteAsync([ValidGuid] Guid itemId)
{
_log.Audit.Info($"Received Delete request for item {itemId} from user {User.Identity?.Name}.");
if (!ModelState.IsValid)
....
Upvotes: 4
Views: 785
Reputation: 5480
Your authroize attribute is most likely firing before your claims transform fires.
In your owin pipeline, you've added webAPI before the claims transform. As your request travels along the pipeline, web api will get the request & run the authorize against it before the claims transform can do its bit.
Try moving the UseClaimsTransformation
before the UseWebApi
Upvotes: 2