Decouple self-host OWIN authorization server - oauth-2.0

I have a self-hosted OWIN application configured as an authorization server and a signalr resource server.
My clients are successfully obtaining the bearer token and presenting it for authorization in subsequent calls to the signalR hub.
My next step is to decouple the authorization service so that it can run on its own host. To get started I created a separate self-hosted app that contains only the authorization service code. It's still all in one solution on my development machine, but the authorization service and signalR resources are hosted in separate processes.
The auth flow is still working properly. The token is getting to my resource server, but now getting 401 unauthorized from the signalR hub.
There is alot of support out there for solving this in ASP.Net Web API, in which you would sync up a machine.config value in your web.config files. But that is not my architecture. Running as a self-hosted app under HttpListener uses different encryption, DPAPI by default.
There doesn't seem to be much discussion out there about solving this in a self-hosted architecture. My theory is that even under different processes on the same machine, the DPAPI decryption is failing and so I get 401.
I'm trying to figure out if there is some minimal approach to solving this or if I have to completely refactor maybe to use JWT instead.
EDIT: adding some code to help display my setup
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/account/login"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
public void ConfigureOAuth(IAppBuilder app)
{
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new ApplicationOAuthBearerAuthenticationProvider(),
});
}

Posting my own solution hopefully to help someone else down the road.
I did decide to implement a JWT solution rather than use the default. I think this is the better architecture anyway, decoupling your token encryption from the OS. I used this tutorial http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
The crucial bits were creating your custom OAuthAuthorizationServerProvider and ISecureDataFormat for encrypting the token as shown in the tutorial. This just shows the OWIN config.
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = false,
TokenEndpointPath = new PathString("/account/login"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(30),
Provider = new JwtAuthorizationServerProvider(),
AccessTokenFormat = new CustomJwtFormat("https://foo.test.com")
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
Another issue you might face is getting the token to SignalR, where setting the Authorization header is not as straight forward as you might think. As it happens the cookie based implementation in this tutorial worked beautifully with JWT as well! http://blog.marcinbudny.com/2014/05/authentication-with-signalr-and-oauth.html#.VmWgMXarSCd
Again here is the OWIN config example.
public void ConfigureOAuth(IAppBuilder app)
{
//app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
//{
// Provider = new ApplicationOAuthBearerAuthenticationProvider()
//});
var issuer = "https://foo.test.com";
var audience = "client_id";
var secret = TextEncodings.Base64Url.Decode("ABCDEF");
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret)
},
Provider = new ApplicationOAuthBearerAuthenticationProvider()
});
}

FWIW, consider that self-hosted OWIN authorization servers use DPAPI protection, but ASP.NET apps default to MachineKey data protection.
If you need to make those two collaborate, in the OWIN config you can specify a provider like this:
app.SetDataProtectionProvider(new DpapiDataProtectionProvider("myApp"));
Just make sure to add it in both Configuration methods for the IAppBuilder (Both projects)
HTH

Related

Owin Middleware per controller in asp.net web API

I am using the following JWT middleware to authorize all controllers with a valid JWT and it works as expected. I need to enable client certificate based authorization on one of the controllers. I understand that i can create a new middleware and plug it into owin pipeline which validates client certificates.
How to decide which controller to use which middleware? As far as i know OWIN does not have any knowledge of any controller. Please suggest
public void ConfigureAuth(IAppBuilder app)
{
TextEncodings.Base64Url.Decode("IxrAjDoa2FqElO7IhrSrUJELhUckePEPVpaePlS_Xaw");
var issuer = System.Configuration.ConfigurationManager.AppSettings["issuer"].ToString();
var audience = System.Configuration.ConfigurationManager.AppSettings["ClientID"].ToString();
var secret = TextEncodings.Base64Url.Decode(System.Configuration.ConfigurationManager.AppSettings["ClientSecret"].ToString());
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audience },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, secret),
}
});
}
Owin "knows" which controller to authorise because of the [Authorise] tag on top of it.
Why don't you do the same for the other system? Create another tag which then fires up the other authentication system? It's the easiest way to keep a clean system working.
You can more than likely use the owin source code to get some inspiration and se exactly how things are done.

Can I use two authentication methods in Owin?

In my application I use MVC and Web.API.
The MVC portion handles the admin front-end, serving the cshtml pages, communication with the back-end, regular authentication using cookies, etc:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
The Web.API one handles the REST requests made by the iOS and Android applications. For that one I want to use token based authentication:
var oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true, //todo-err: change in prod
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new SimpleAuthorizationServerProvider()
};
// Token Generation
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
My question is, what do I need to make this work? Regular and token authentication. Will I need to create a custom AuthorizeAttribute for the API controllers?
I appreciate any help :)
Your SimpleAuthorizationServerProvider needs to be implemented.
Generating a WebAPI project in VS2015 with authentication gives you something like this.
The article Applying Cookie-Stored Sessions With ASP.NET and OpenID Connect 1.0 by Kelvin Amorim is very useful for understanding multiple factors for supporting multiple authentication middlewares.
Some main points are:
Each authentication options middleware should use a different AuthenticationType (it is just a string key and there are some defaults to choose from)
You can set the cookie path and use corresponding MVC Areas (see RouteAreaAttribute) to control which cookies are used for which requests

Using An OAuth Bearer Token (JWT) With MVC

I've created a backend WebApi to create JWT tokens and they're working fine when I use PostMan to access restricted resources by adding the token to the header, e.g. [Authorise(Roles="SuperAdmin")].
I want to use this infrastructure with my MVC app, but don't quite know how to tie it together.
I'm guessing that when the user creates an account and I generate a JWT for them (Via the WebApi), I need to stick the token in a cookie, but how do this and also extract the JWT from the cookie on future requests, so that it will work with the normal [Authorize] attribute that I decorate the ActionResults with?
Do I need to put something in the Owin pipeline?
Or do I need to create a custom [Authorize] attribute?
My Startup.cs file currently looks like this:
public void Configuration(IAppBuilder app)
{
HttpConfiguration httpConfig = new HttpConfiguration();
ConfigureOAuthTokenGeneration(app);
ConfigureOAuthTokenConsumption(app);
ConfigureWebApi(httpConfig);
app.UseCors(Microsoft.Owin.Cors.CorsOptions.AllowAll);
app.UseWebApi(httpConfig);
}
private void ConfigureOAuthTokenGeneration(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
//TODO: enforce https in live
//For Dev enviroment only (on production should be AllowInsecureHttp = false)
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/oauth/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new CustomOAuthProvider(),
AccessTokenFormat = new CustomJwtFormat("https://localhost:443")
};
// Plugin the OAuth bearer JSON Web Token tokens generation and Consumption will be here
// OAuth 2.0 Bearer Access Token Generation
app.UseOAuthAuthorizationServer(OAuthServerOptions);
}
private void ConfigureOAuthTokenConsumption(IAppBuilder app)
{
var issuer = "https://localhost:443";
string audienceId = ConfigurationManager.AppSettings["as:AudienceId"];
byte[] audienceSecret = TextEncodings.Base64Url.Decode(ConfigurationManager.AppSettings["as:AudienceSecret"]);
// Api controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
AllowedAudiences = new[] { audienceId },
IssuerSecurityTokenProviders = new IIssuerSecurityTokenProvider[]
{
new SymmetricKeyIssuerSecurityTokenProvider(issuer, audienceSecret)
}
});
}
private void ConfigureWebApi(HttpConfiguration config)
{
config.MapHttpAttributeRoutes();
var jsonFormatter = config.Formatters.OfType<JsonMediaTypeFormatter>().First();
jsonFormatter.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
}
If it helps, I was following this guide:
http://bitoftech.net/2015/02/16/implement-oauth-json-web-tokens-authentication-in-asp-net-web-api-and-identity-2/
The infrastructure your referred to is really designed to handle direct web API calls. A classic redirect based web app would fall back on more traditional patterns, where the app receives one token, validates it and uses it to initiate an authenticated session (by saving the results of the token validation in some session artifact, like a token). Although you can implement this patters starting form any token based system, including your custom one, usually it's more convenient (and secure) to leverage existing protocols (like OpenId Connect) and existing products (like Azure AD or Identity Server). See this for a simple example based on Azure AD - the middleware remains the same no matter what OpenId Provider you pick.

.net web api Bearer token exipres within a few minutes

I've set up Web API + oauth2 bearer token authentication successfully. I get a token via the /authtoken endpoint and can use it for calls to protected areas of the web api.
However, I have set the expiration on 7 days, but the token seems only valid for about 5 minutes:
public void ConfigureOAuth(IAppBuilder app)
{
OAuthAuthorizationServerOptions OAuthServerOptions = new OAuthAuthorizationServerOptions()
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/authtoken"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(7),
Provider = new SimpleAuthorizationServerProvider()
};
app.UseOAuthAuthorizationServer(OAuthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
}
What could be wrong here?
Weird, adding a machine key to the web.config fixed it. I'm not using different servers nor different webapps so why adding a machine key works beats me, but I guess it's good practice anyway.

Why does Owin Startup order affect Cookie Authentication

I have Owin configured to issue both a token and cookie upon authentication:
public void Configuration(IAppBuilder app)
{
var cookieOptions = new CookieAuthenticationOptions
{
AuthenticationMode = AuthenticationMode.Active,
CookieHttpOnly = true, // JavaScript should use the Bearer
//AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieName = "MyCookie",
LoginPath = new PathString("/app/index.html#/login"),
};
var oAuthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1),
Provider = new MyAuthorizationServerProvider(),
};
var oAuthBearerOptions = new OAuthBearerAuthenticationOptions
{
};
// Must be registered in this order!
app.UseCookieAuthentication(cookieOptions);
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseOAuthBearerAuthentication(oAuthBearerOptions);
}
This works fine - it issues both the Bearer token for my SPA to call my API and the cookie so my old school MVC pages can be logged in too.
But if I register the OAuth server before declaring that I want to use CookieAuth, no cookie is issued. In other words if I do this, it doesn't work:
app.UseOAuthAuthorizationServer(oAuthServerOptions);
app.UseCookieAuthentication(cookieOptions);
app.UseOAuthBearerAuthentication(oAuthBearerOptions);
Also, if I uncomment this line, it also doesn't issue the cookie:
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
My question is why does the order of registration with Owin matter? And why does setting the AuthenticationType in the cookie as "ApplicationCookie" also make it fail?
I'm not familiar with the UseOAuthAuthorizationServer() middleware, but I assume it works the same as other external authentication middleware (e.g. the Google middleware).
An authentication middleware that redirects to an external source for authentication, will only be used once, at the start, of each browsing session. It will then defer the authentication of the up-coming requests to a cookie authentication that maintains the session. This is good, because it means the overhead of the external authentication is only done once for each session.
A middleware that wants to set a cookie does typically not do it itself. Instead it sets a property in the Owin context with an AuthenticationResponseGrant. The grant is then processed by the cookie middleware that extracts the identity and sets the cookie.
For this to work:
The cookie handler must be registered before the external authentication middleware in the pipeline.
The authentication type in the AuthenticationResponseGrant must match the type of the cookie middleware.
So changing the order of the registration violates 1. and excluding the authentication type violates 2.
I have written an in depth blog post about it if you want more details.

Resources