I have an Owin application I'm running in Mono, and I'm trying to get authentication to work properly on it. I used the info on this page as a start. I quickly realized that Owin Authentication uses some Windows specific libraries. This question had a workaround for that, though, which I thought would be enough. It wasn't.
The following code throws the exception described in the other question (in another place than the question describes (see comment in code)). If I try to comment out stuff to locate the error exceptions about Owin pipeline are being thrown (because of dependencies). If I comment out enough to remove that the first exception appears again.
Has anybody successfully been able to set up authentication in Owin (using AspNet Identity) in Mono?
Startup
public void Configure(IAppBuilder app)
{
// Add the AspNet Identity user manager to the Owin context
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// This was the first line to fail, but adding the AesDataProtectorProvider as
// described in the referred question fixed that
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
TicketDataFormat = new SecureDataFormat<AuthenticationTicket>(
DataSerializers.Ticket,
new AesDataProtectorProvider("myAuthKey"),
TextEncodings.Base64)
});
// This causes an exception complaining that the Windows only assembly
// DpapiDataProtector can't be loaded, as described in the referred question
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Set up the custom middleware as described in the first link
// Something inside this causes other exceptions.
app.Use(typeof(AuthMiddleware), app, new AuthOptions());
}
AuthMiddleware
public class AuthMiddleware : AuthenticationMiddleware<AuthOptions>
{
public AuthMiddleware(OwinMiddleware next, IAppBuilder app, AuthOptions options)
: base(next, options)
{
if (string.IsNullOrEmpty(Options.SignInAsAuthenticationType))
{
options.SignInAsAuthenticationType = app.GetDefaultSignInAsAuthenticationType();
}
if (options.StateDataFormat == null)
{
var dataProtector = app.CreateDataProtector(typeof(AuthMiddleware).FullName,
options.AuthenticationType);
options.StateDataFormat = new PropertiesDataFormat(dataProtector);
}
}
protected override AuthenticationHandler<AuthOptions> CreateHandler()
{
return new AuthHandler();
}
}
AuthOptions
public class AuthOptions : AuthenticationOptions
{
public AuthOptions()
: base("MyApp")
{
Description.Caption = "MyApp";
// Where to redirect requests if not authenticated
CallbackPath = new PathString("/login"); AuthenticationMode = AuthenticationMode.Passive;
}
public PathString CallbackPath { get; set; }
public string SignInAsAuthenticationType { get; set; }
public ISecureDataFormat<AuthenticationProperties> StateDataFormat { get; set; }
}
AuthHandler
public class AuthHandler : AuthenticationHandler<AuthOptions>
{
protected override Task<AuthenticationTicket> AuthenticateCoreAsync()
{
var identity = new ClaimsIdentity(Options.SignInAsAuthenticationType);
var properties = Options.StateDataFormat.Unprotect(Request.Query["state"]);
return Task.FromResult(new AuthenticationTicket(identity, properties));
}
protected override Task ApplyResponseChallengeAsync()
{
if (Response.StatusCode == 401)
{
var challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);
if (challenge != null)
{
var state = challenge.Properties;
if (string.IsNullOrEmpty(state.RedirectUri))
{
state.RedirectUri = Request.Uri.ToString();
}
var stateString = Options.StateDataFormat.Protect(state);
Response.Redirect(WebUtilities.AddQueryString(Options.CallbackPath.Value, "state", stateString));
}
}
return Task.FromResult<object>(null);
}
public override async Task<bool> InvokeAsync()
{
Request.Environment.Add("Context", Context);
// If user is not logged in and tries to access any page that is not in
// the list of allowed pages, redirect to login page
if (Context.Authentication.User == null &&
!Request.Path.ToString().StartsWith("/login"))
{
Response.Redirect(Options.CallbackPath.Value);
return true;
}
return false;
}
}