How to log authentication failure reasons when using OWIN and JWT? - c#

I am using a c# self hosted OWIN server and have configured my application to use authorise with JWT as below. This works properly, and invalid tokens are rejected with a 401 Unauthorized and valid tokens are accepted.
My question is how can I write a log of why requests are rejected. Was it expired? Was it the wrong audience? Was no token present? I want all failed requests to be logged, but I can't seem to find any example of how.
public class Startup
{
public void Configuration(IAppBuilder appBuilder)
{
// Configure Web API for self-host.
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
// Enable
config.Filters.Add(new AuthorizeAttribute());
appBuilder.UseJwtBearerAuthentication(new JwtOptions());
appBuilder.UseWebApi(config);
}
}
JwtOptions.cs
public class JwtOptions : JwtBearerAuthenticationOptions
{
public JwtOptions()
{
var issuer = WebConfigurationManager.AppSettings["CertificateIssuer"];
var audience = WebConfigurationManager.AppSettings["CertificateAudience"];
var x590Certificate = Ap21X509Certificate.Get(WebConfigurationManager.AppSettings["CertificateThumbprint"]);
AllowedAudiences = new[] { audience };
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new X509CertificateSecurityTokenProvider(issuer, new X509Certificate2(x590Certificate.RawData))
};
}
}
I am guessing I will need to implement my own validation to do this, but not sure how to implement that either.

I know that it is quite late, but can be useful for one how is struggling to find an answer.
Basically AuthenticationMiddleware has embedded logging. You just need to redirect OWIN logs to logger you are using.
NLog.Owin.Logging works well for me. There is similar solution for log4net.
There is alternative solution. Extend JwtSecurityTokenHandler and log the reason manually.
public class LoggingJwtSecurityTokenHandler : JwtSecurityTokenHandler
{
public override ClaimsPrincipal ValidateToken(string securityToken, TokenValidationParameters validationParameters, out SecurityToken validatedToken)
{
try
{
return base.ValidateToken(securityToken, validationParameters, out validatedToken);
}
catch (Exception ex)
{
//log the error
throw;
}
}
}
And use it like this:
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
TokenHandler = new LoggingJwtSecurityTokenHandler()
});

Related

Consume OAuth Tokens in ASP.Net Web Api 2.0

I have created a brand new WebService using ASP.Net Web Api 2.0 and am trying to use authorization based on an OAuth JWT token. I have all of the basic wiring done with OWIN, but when I use the [Authorize] attribute, it fails, even for a valid token. Can you help.
Edit: I narrowed down the issue. It seems that the key is RS256 and SymmetricKeyIssuerSecurityKeyProvider doesn't handle that... Either that or I am passing the Key Provider the wrong information. Any ideas how to fix that?
Here is the code of my startup.cs
using System.Configuration;
using System.Web.Http;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Jwt;
using Owin;
using Microsoft.AspNet.Identity;
namespace SecuredApi
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
ConfigureOAuth(app);
var config = ConfigureWebApi();
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(config);
}
private HttpConfiguration ConfigureWebApi()
{
var config = new HttpConfiguration();
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter("Bearer"));
config.MapHttpAttributeRoutes();
return config;
}
private void ConfigureOAuth(IAppBuilder app)
{
var issuer = ConfigurationManager.AppSettings.Get("Issuer");
var audience = ConfigurationManager.AppSettings.Get("Audience");
var secret = ConfigurationManager.AppSettings.Get("Secret");
// Api controllers with an [Authorize] attribute will be validated with JWT
var jwtBearerAuthenticationOptions = new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AuthenticationType = DefaultAuthenticationTypes.ExternalBearer,
AllowedAudiences = new[] { audience },
IssuerSecurityKeyProviders = new IIssuerSecurityKeyProvider[]
{
new SymmetricKeyIssuerSecurityKeyProvider(issuer, secret)
}
};
app.UseJwtBearerAuthentication(
jwtBearerAuthenticationOptions);
}
}
}

OAuth Bearer Token Not Working for WebApi

I have gone through a lot of docs but it seems my problem is strange.
I have configured Oauth but I am not able to get the bearer token back. whenever I hit api to get the token, I get 200 but nothing back in response(I am expecting bearer token). Below is the config:
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions oAuthOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
Provider = new ApplicationOAuthProvider()
};
app.UseOAuthAuthorizationServer(oAuthOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new OAuthBearerAuthenticationProvider()
});
HttpConfiguration config = new HttpConfiguration();
//config.Filters.Add(new );
//config.MapHttpAttributeRoutes();
// There can be multiple exception loggers. (By default, no exception loggers are registered.)
//config.Services.Replace(typeof(IExceptionHandler), new GlobalExceptionHandler());
WebApiConfig.Register(config);
//enable cors origin requests
app.UseCors(CorsOptions.AllowAll);
app.UseWebApi(config);
}
}
public static class WebApiConfig
{
/// <summary>
///
/// </summary>
/// <param name="config"></param>
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
// Web API routes
config.MapHttpAttributeRoutes();
config.Filters.Add(new HostAuthenticationAttribute("bearer")); //added this
config.Filters.Add(new AuthorizeAttribute());
config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{id}", new { id = RouteParameter.Optional }
);
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
public override async Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
context.Validated();
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var form = await context.Request.ReadFormAsync();
if (myvalidationexpression)
{
var identity = new ClaimsIdentity(context.Options.AuthenticationType);
identity.AddClaim(new Claim(ClaimTypes.Role, "AuthorizedUser"));
context.Validated(identity);
}
else
{
context.SetError("invalid_grant", "Provided username and password is incorrect");
}
}
}
Now when I launch the APi and hit /token, I get this as below:
API Request
I think that code you have written in WebApiConfig.cs to suppress host authentication and some other code is creating the issue.
I have a working example for bearer token generation in web API, which is working properly and generating token.
WebApiConfig.cs file code:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
Startup.cs Code:
[assembly: OwinStartup(typeof(WebAPI.Startup))]
namespace WebAPI
{
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
ConfigureOAuth(app);
WebApiConfig.Register(config);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
}
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions
OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(60),
Provider=new ApplicationOAuthProvider(),
//AuthenticationMode = AuthenticationMode.Active
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions {
Provider = new OAuthBearerAuthenticationProvider()
}
);
}
}
}
Controller to check authorization call after adding bearer token in the request.
public class TokenTestController : ApiController
{
[Authorize]
public IHttpActionResult Authorize()
{
return Ok("Authorized");
}
}
install the following package
Microsoft.Owin.Host.SystemWeb

IAuthenticationFilter in SignalR 2.0

In my Web API 2 project I have JWT based authentication. The configuration is
var config = new HttpConfiguration();
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions {/**/});
config.Filters.Add(new MyAuthenticationFilter());
app.UseWebApi(config);
app.UseCors(CorsOptions.AllowAll);
app.MapSignalR();
MyAuthenticationFilter builds a custom principal based on an incoming JWT and attaches it to a request so that in my controller actions I can access it as this.User. Everything is working fine except the filter is ignored for SignalR requests:
public class MyHub : Hub {
public override Task OnConnected() {
// here Context.User is ClaimsPrincipal which contain a JWT from Authorization header
// I expect it to be MyCustomPrincipal
return base.OnConnected();
}
}
Why IAuthenticationFiltter is ignored? How do I fix that?
You cant use jwt on header with signalR. Send jwt in qs (query string) and add some customization on api that code below.
App_Start/Startup.Auth.cs
public void ConfigureAuth(IAppBuilder app)
{
// SignalR Auth0 custom configuration.
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
Provider = new OAuthBearerAuthenticationProvider()
{
OnRequestToken = context =>
{
if (context.Request.Path.Value.StartsWith("/signalr"))
{
string bearerToken = context.Request.Query.Get("token");
if (bearerToken != null)
{
string[] authorization = new string[] { "bearer " + bearerToken };
context.Request.Headers.Add("Authorization", authorization);
}
}
return null;
}
}
});
}
and you use Authorize attribute on hub
[Authorize]
public class MyHub:Hub

Web API 2 DelegateHandler Not Invoked When IdentityServer3 Implemented

I am having a very weird scenario when trying to add a custom DelegatingHandler. The SendAsync gets invoked. Up to this point, everything is happy with life.
However, as soon as I add Authentication using IdentityServer3, all of my DelegatingHandlers are ignored. SendAsync() is not invoked.
The DelegatingHandler:
public class LogRequestAndResponseHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(
HttpRequestMessage request, CancellationToken cancellationToken)
{
// log request body
string requestBody = await request.Content.ReadAsStringAsync();
//Trace.WriteLine(requestBody);
// let other handlers process the request
var result = await base.SendAsync(request, cancellationToken);
// once response body is ready, log it
var responseBody = await result.Content.ReadAsStringAsync();
//Trace.WriteLine(responseBody);
return result;
}
}
The startup.cs
public void Configuration(IAppBuilder app)
{
app.UseIdentityServerBearerTokenAuthentication(new IdentityServerBearerTokenAuthenticationOptions
{
Authority = Globals.TokenAuthenticationAuthority,
ValidationMode = ValidationMode.ValidationEndpoint,
RequiredScopes = new[] { "scope1", "scope2", "scope3" }
});
var config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Filters.Add(new AuthorizeAttribute());
app.UseWebApi(config);
}
The WebApiConfig:
public static class WebApiConfig
{
public static void Register(HttpConfiguration config)
{
// Web API configuration and services
// Configure Web API to use only bearer token authentication.
config.SuppressDefaultHostAuthentication();
config.Filters.Add(new HostAuthenticationFilter(OAuthDefaults.AuthenticationType));
config.MessageHandlers.Add(new LogRequestAndResponseHandler());
// Web API routes
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{action}/{id}",
defaults: new { id = RouteParameter.Optional }
);
}
}
After digging and playing around, I found that the line that breaks is the
config.MapHttpAttributeRoutes();
But I just dont understand why. Any help will be much appreciated.
From the comment chain on the question
Configuration() gets called after 'WebApiConfig.Register()'
This is the problem. The Configuration() method in Startup.cs creates a new HttpConfiguration and passes it to .UseWebApi(). This effectively undoes everything that WebApiConfig.Register() does, as it adds filters, message handlers, etc. to the HttpConfiguration that is passed in.
To fix this, you have two options:
Change var config = new HttpConfiguration(); in Startup.cs to var config = GlobalConfiguration.Configuration
Call Startup.Configuration() before WebApiConfig.Register() and be sure to pass in the new HttpConfiguration

Get custom claims from a JWT using Owin

I'm using Owin with JWTBearerAuthentication to authorize users and validate their tokens. I'm doing it like this:
public class Startup
{
public void Configuration(IAppBuilder app)
{
HttpConfiguration config = new HttpConfiguration();
config.MapHttpAttributeRoutes();
config.Routes.MapHttpRoute(
name: "DefaultApi",
routeTemplate: "api/{controller}/{id}",
defaults: new { id = RouteParameter.Optional }
);
ConfigureOAuth(app);
app.UseWebApi(config);
}
private void ConfigureOAuth(IAppBuilder app)
{
string issuer = ConfigurationManager.AppSettings.Get("auth_issuer");
string audience = ConfigurationManager.AppSettings.Get("auth_clientId");
byte[] secret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings.Get("auth_secret"));
app.UseJwtBearerAuthentication(new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new [] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
}
});
}
}
However, I have some custom claims in my token, and want to use their values in my ApiController, which looks like this:
[RoutePrefix("endpoint")]
public class MyApiController : ApiController
{
[Route("action")]
[Authorize]
public IHttpActionResult Post(string someValue)
{
bool res = DoSomeAction.withTheString(someValue);
if (res)
{
return Ok<string>(someValue);
}
return InternalServerError();
}
}
Is there anything like User.Claims["myCustomClaim"].Value, which provides the values of all claims?
Thank you,
Lukas
Something like this might help:
var identity = User.Identity as ClaimsIdentity;
return identity.Claims.Select(c => new
{
Type = c.Type,
Value = c.Value
});

Categories

Resources