Adding AD authentication to OWIN Server Middleware pipeline - asp.net

I have inherited a project that has been developed using OWIN, Server Middleware that manages a kind-of WebApi in order to communicate with mobile devices using ApiKeys. The Server side has a small web interface (which really is a set of test pages) but did not have authentication added. I am trying to wrap my head around the different frameworks being used and the ways one can authenticate around these OWIN techniques.
Let me show what I have first:
public class Startup
{
public void Configuration(IAppBuilder app)
{
log.Info("RT Server app starting up ...");
// Initialize the ApiKey Needed for ApiClient Library
ApiClient.ApiKey = Globals.ApiKey;
// Initialize the Services Library
Services.Startup.Initialize();//creates a configuration map of values for devices
// Setup Server Middleware
app.Use(typeof(ServerMiddleware), "RTrak.Server", "RTrak.Server");
app.Use(typeof(ServerMiddleware), "RTrak.Server.Pages", "RTrak.Server");
// HttpListener listener = (HttpListener)app.Properties["System.Net.HttpListener"];//throws an KeyNotFoundException
// listener.AuthenticationSchemes = AuthenticationSchemes.IntegratedWindowsAuthentication;
//ConfigureAuth(app)
}
public void ConfigureAuth(IAppBuilder app)
{
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = MyAuthentication.ApplicationCookie,
LoginPath = new PathString("/Login"),
Provider = new CookieAuthenticationProvider(),
CookieName = "RTrakCookie",
CookieHttpOnly = true,
ExpireTimeSpan = TimeSpan.FromHours(12), // ...
});
}
the ServerMiddleware
public ServerMiddleware(OwinMiddleware next, string baseNamespace, string defaultClass) : base(next)
{
BaseNamespace = baseNamespace;
DefaultClass = defaultClass;
}
public override async Task Invoke(IOwinContext owinContext)
{
var absolutePath = owinContext.Request.Uri.AbsolutePath;
string serverNamespace = BaseNamespace;
Type type;
string classToLoad = "";
if (absolutePath == "/")
classToLoad = DefaultClass;
else
{
classToLoad = absolutePath.Substring(1).Replace('/', '.');
if (classToLoad.EndsWith("."))
classToLoad = classToLoad.Substring(0, classToLoad.Length - 1);
}
type = Type.GetType($"{serverNamespace}.{classToLoad}, {serverNamespace}", false, true);
if (type == null)
{
classToLoad += ".Default";
type = Type.GetType($"{serverNamespace}.{classToLoad}, {serverNamespace}", false, true);
}
if (type != null)
{
try
{
object objService = Activator.CreateInstance(type);
((Resource)objService).Execute(owinContext);
}
catch (System.MissingMethodException)
{
//"403 INVALID URL");
}
}
else
await Next.Invoke(owinContext);
}
}
That ServerMiddleware is first calling Default Pages class that is HTML markup which links to the other test Pages
A thought was to add an MVC LoginController with AdAuthenticationService managing cookies Model to manage login that is configured as part of the Startup noted in the line ConfigAuth(app), but the middleware is ignoring the controller. Is MVC appropriate here?
then, I am looking at this ServerMiddleware and trying to understand how to intercept the Default page browser call with ActiveDirectory authentication.
I know that I may be overlooking something. Many thanks for anything (suggestions or resources) you can offer to help clear up this confusion for me.

What I did to resolve this was to leave the OWIN Middleware objects alone except for Startup.cs had to define CookieAuthentication route
app.UseCookieAuthentication(new Microsoft.Owin.Security.Cookies.CookieAuthenticationOptions
{
AuthenticationType = "ApplicationCookie",
LoginPath = new Microsoft.Owin.PathString("/Auth/Login")
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
for the pages that were built as OWIN Resources. These OWIN Resource "Pages" then check
if (!this.Context.Authentication.User.Identity.IsAuthenticated)
I then implement an MVC controller that uses the AdAuthenticationService as above and UserManager to manage the AD credentials and Identity where the OWIN resource redirects to the MVC view+controller for authentication. That controller handles the login page actions. Upon authentication, the MVC redirects to the OWIN resource pages.
Thus, OWIN Middleware and MVC can live side-by-side so long as OWIN does not try to define the routes that MVC wants to use. Owin can maintain its own authentication as well.

Related

deliver token manually (in addition to the owin configuration way)

I have actually an asp.net website application, that can deliver token to an user with the following way :
the user logs into the application, go to a specific page and obtains a clientid and a clientsecret.
then, he calls the following api "....api/token" by giving clientid and clientsecret (client credentials grant type) to get the token.
This is the associated code :
using Microsoft.Owin;
using Owin;
using System;
using Microsoft.Owin.Security.OAuth;
[assembly: OwinStartup(typeof(MyApp.Web.App_Start.OwinStartup))]
namespace MyApp.Web.App_Start
{
public class OwinStartup
{
public void Configuration(IAppBuilder app)
{
OwinWebApiStartup.Configuration(app);
}
}
}
public static class OwinWebApiStartup
{
public static void Configuration(IAppBuilder app)
{
var provider = //my provider implementation;
var oauthServerOptions = new OAuthAuthorizationServerOptions
{
AllowInsecureHttp = true,
TokenEndpointPath = new PathString("/api/token"),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(20),
Provider = provider,
};
app.UseOAuthAuthorizationServer(oauthServerOptions);
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions()
{
AccessTokenProvider = //my provider implementation,
});
}
}
This is working nicely. But I would like to add a new feature, where a javascript client code, not an user anymore, would like to call my apis, and so it will need to have a token, but do not have a clientid and clientsecret.
This is my idea :
Create a new api endpoint, (only this one will be reachable by my javascript client code without token, and there, the code will generate a token (thanks to the username of the current user connected) and return this one (that will
be the same that an user could have obtained with the existing method) to be used by the javascript client code
I faced this problem in the past. I solved this via querystring, cause owin could only provide one token ressource. In fact it makes sense to rely on owin and on not implementing your own code.
My pseudo solution:
KeyValuePair<string, string[]> typePair = ctx.Request.Query.FirstOrDefault(x => x.Key == "type");
LoginType? loginType = GetLoginType(typePair);
[...]
switch (loginType)
{
case LoginType.User:
[...]
////within this routine you could set your claims depending on your needs
If you get another solution, I'd be grateful for sharing

OWIN Oauth differentiate expired and invalid token

I use OWIN Oauth in my ASP.NET MVC application to provide access token for mobile applications. Here's the setup of OAuth:
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/api/authenticate/login"),
Provider = dependencyContainer.GetService<IOAuthAuthorizationServerProvider>(),
RefreshTokenProvider = dependencyContainer.GetService<IAuthenticationTokenProvider>(),
AccessTokenExpireTimeSpan = TimeSpan.FromMinutes(applicationSettings.AccessTokenLifeTimeInMinutes),
AllowInsecureHttp = true
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());
I also have custom provider and custom refresh token provider as you can see above. Everything is working fine, when a request from mobile is expired or invalid, I use a custom AuthorizeAttribute to return a json with message "unauthorized"
public class ApiAuthorizeAttribute : AuthorizeAttribute
{
protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
{
filterContext.Result = new JsonResult
{
Data = new
{
success = false,
error = "Unauthorized"
},
JsonRequestBehavior = JsonRequestBehavior.AllowGet
};
}
}
However in one scenario, the mobile applications need to differentiate the response from server for 2 cases: access token is expired, or access token is invalid (.e.g. modified in the middle). I'm not sure how I can implement that requirement. I tried to create a custom access token provider, inheriting from AuthenticationTokenProvider, register it in UseOAuthAuthorizationServer() above, but both Receive() and ReceiveAsync() are not called when server receives access token from mobile
Solved the issue. My approach of creating custom access token provider works. Initially I registered it with UseOAuthAuthorizationServer(), but it should be registered using UseOAuthBearerAuthentication() instead
Here's my custom class, in case anyone needs:
public class CustomAccessTokenProvider : AuthenticationTokenProvider
{
public override void Receive(AuthenticationTokenReceiveContext context)
{
context.DeserializeTicket(context.Token);
var expired = context.Ticket.Properties.ExpiresUtc < DateTime.UtcNow;
if (expired)
{
//If current token is expired, set a custom response header
context.Response.Headers.Add("X-AccessTokenExpired", new string[] { "1" });
}
base.Receive(context);
}
}
Register it when setting up OWIN OAuth:
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
AccessTokenProvider = new CustomAccessTokenProvider()
});

Disable GET functionality of WEB API token call

I developed an application using ASP.NET WEB API 2. The application is completed and in the process of having security review done on it, but one of the requirements is that any GET requests for login must be disabled.
We are making the call to the token action over POST, but the security team picked up that you can still make the same request with GET and that needs to be removed. I know the token call is one that is built into the whole OWIN/OAUTH system, but is it possible to configure it so that it will only accept POST requests and block GET?
Thanks in advance.
By looking into Katana project sources I can see that in Microsoft.Owin.Security.OAuth.OAuthAuthorizationServerHandler they have the following check:
if (Options.TokenEndpointPath.HasValue && Options.TokenEndpointPath == Request.Path)
{
matchRequestContext.MatchesTokenEndpoint();
}
As you can see there is no additional check for HTTP METHOD. Therefore as one of the possible solution I can propose you to write your own middleware which is executing before authentication one and checks for the HTTP METHOD:
public class OnlyPostTokenMiddleware : OwinMiddleware
{
private readonly OAuthAuthorizationServerOptions opts;
public OnlyPostTokenMiddleware(OwinMiddleware next, OAuthAuthorizationServerOptions opts) : base(next)
{
this.opts = opts;
}
public override Task Invoke(IOwinContext context)
{
if (opts.TokenEndpointPath.HasValue && opts.TokenEndpointPath == context.Request.Path && context.Request.Method == "POST")
{
return Next.Invoke(context);
}
context.Response.StatusCode = (int)HttpStatusCode.NotFound;
context.Response.ReasonPhrase = "Not Found";
return context.Response.WriteAsync("Not Found");
}
}
then in Startup.cs you would have something similar to:
var authOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/token"),
Provider = Resolver.GetService<OAuthProvider>(),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(1)
};
app.Use<OnlyPostTokenMiddleware>(authOptions);
app.UseOAuthAuthorizationServer(authOptions);

How to authenticate an access token using OWIN OAuthBearerAuthentication?

What I want:
A token generator use OAuthAuthorizationServer and token consumer use OAuthBearerAuthentication (authenticate the access token).
Use OWIN pipeline to manage all stuff, token stuff and web api stuff.
What about the code:
public void Configuration(IAppBuilder app)
{
app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
AuthorizeEndpointPath = "/Authorize",
AllowInsecureHttp = true,
Provider = new OAuthAuthorizationServerProvider
{
OnGrantCustomExtension = GrantCustomExtension,
OnValidateClientRedirectUri = ValidateClientRedirectUri,
OnValidateClientAuthentication = ValidateClientAuthentication,
}
});
app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
{
Provider = new OAuthBearerAuthenticationProvider
{
//Handles applying the authentication challenge to the response message.
ApplyChallenge=MyApplyChallenge,
//Handles processing OAuth bearer token.
RequestToken=MyRequestToken,
//Handles validating the identity produced from an OAuth bearer token.
ValidateIdentity = MyValidateIdentity,
}
});
app.UseWebApi(new WebApplication3.Config.MyWebApiConfiguration());
}
What's the question:
The 3 properties of OAuthBearerAuthenticationProvider,
ApplyChallenge, RequestToken and ValidateIdentity. How to
implement the 3 methods?
In the token authetication process, What I thought is to decrypt the access token, validate the token from the client, and if the token is validated, put the identities of the token to the HttpContext.Current.User.
The OAuthBearerAuthenticationProvider's responsibility is to fulfill the
previous steps. Am I right?
As you know, UseOAuthAuthorizationServer has the job of authenticating the user. Then, UseOAuthBearerAuthentication has the job of ensuring that only authenticated users can access your application. Often, these two jobs are assigned to different web application. It looks like your application is doing both.
There are certainly some cases were you need to override the default OAuthBearerAuthenticationProvider. Maybe you do, or maybe you don't In my case, ApplicationCookie didn't quite fit the scenario. So, I'm storing a 3rd party JWT token in a cookie, rather than the header, and using it to indicate that the user is authenticated to a web application. I also needed to redirect to my own login page, rather than provide a 401.
Here's an implementation that does both:
public class CustomOAuthBearerProvider : IOAuthBearerAuthenticationProvider
{
public Task ApplyChallenge(OAuthChallengeContext context)
{
context.Response.Redirect("/Account/Login");
return Task.FromResult<object>(null);
}
public Task RequestToken(OAuthRequestTokenContext context)
{
string token = context.Request.Cookies[SessionKey];
if (!string.IsNullOrEmpty(token))
{
context.Token = token;
}
return Task.FromResult<object>(null);
}
public Task ValidateIdentity(OAuthValidateIdentityContext context)
{
return Task.FromResult<object>(null);
}
}
I didn't need to do anything special in ValidateIdentity, but I needed to satisfy the interface.
To wire this up, tell your app to use JwtBearerAuthentication with your provider:
// controllers with an [Authorize] attribute will be validated with JWT
app.UseJwtBearerAuthentication(
new JwtBearerAuthenticationOptions
{
AllowedAudiences = audiences.ToArray(),
IssuerSecurityTokenProviders = providers.ToArray(),
Provider = new CookieOAuthBearerProvider()
}
);

SignalR ISAuthenticated using Headers

My goal is:
To use custom headers with my own token to authenticate a user or machine against my signalr service.
We've been using this methodology succesfully under ASP.net WEB API to perform our own custom claims based authentication and authorization.
Our Web Api was as follows:
protected void Application_Start()
{
GlobalConfiguration.Configuration.MessageHandlers.Add(new AuthorizationHeaderHandler());
}
Then we would have a AuthorizationHandler that would overwrite the Thread.CurrentPrincipal = principal; and we would be done.
Within SignalR I have tried to implement:
1. Mark our hub using Authorize
2. Implemented custom authorize atributes
3. Tried A Custom Module. But besides returning true if the correct headers we're send I still do not get the Context.User to change to the claims based principal that we generate.
But never can we get the Context.User to show the actual user that's being used to connect to the hub.
Any suggestions are Welcome.
Main reason why we want to achieve this is because we have a couple of different user/machine types that connect to our system.
Anybody any suggestions.
Finally found the solution.
I added my own owin security middleware allowing me to handle customer header based authentication.
This could be easily expanded allowing you to combine multiple authenitication scheme's within on service.
First Create Custom Authentication Middleware:
public class AuthenticationMiddleware : OwinMiddleware
{
public AuthenticationMiddleware(OwinMiddleware next) :
base(next) { }
public override async Task Invoke(IOwinContext context)
{
var request = context.Request;
var value = request.Headers["Phocabby-MachineKey"];
var username = value;
var usernameClaim = new Claim(ClaimTypes.Name, username);
var identity = new ClaimsIdentity(new[] { usernameClaim }, "ApiKey");
var principal = new ClaimsPrincipal(identity);
principal.Identities.First().AddClaim(new Claim("CanGetApiKey", "False"));
principal.Identities.First().AddClaim(new Claim("Cabinet", "True"));
request.User = principal;
await Next.Invoke(context);
}
}
Then register it in the startup class
public void Configuration(IAppBuilder app)
{
app.Use(typeof(AuthenticationMiddleware));
app.MapSignalR();
}

Resources