I\'m having problems trying to decide on a route to take on a project I have.
I\'ve been reading up on OWIN specs and Katana implementation within .NET. The reason why I
Cmedine, based on Brett's answer i configured my authentication and authorization. I show you the code as you requested some sample code.
public partial class Startup
{
public void ConfigureAuth(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
SlidingExpiration = false,
CookieName = "identity",
//short time for testing only
ExpireTimeSpan = TimeSpan.FromSeconds(120),
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = ctx =>
{
ctx.Identity = TransformClaims(ctx);
}
}
});
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
MetadataAddress = "https://[[ADFS_Url]]/FederationMetadata/2007-06/federationmetadata.xml",
Wtrealm = "[[realm]]",
UseTokenLifetime = false
}
);
}
private ClaimsIdentity TransformClaims(CookieResponseSignInContext ctx)
{
return new IdentityCreator().CreateIdentity(ctx.Identity, [[ApplicationName]]);
}
}
The IdentityCreator takes the ClaimsIdentity and an Application name and goes to a DB and gets the claims for that user in that application. Hope it helps!!
I can offer that the WsFederation option in OWIN is nice but requires cookies...and they're a different kind of cookie than local auth with cookies. ADFS 2.0/WsFederation uses AuthenticationType="Cookies", and local auth uses AuthenticationType="ApplicationCookie". They are apparently incompatible as far as I can tell. I think you'll have to use token auth for ADFS but I believe that requires ADFS 3.0 on 2012R2. For that use OWIN OAuth.
UPDATE: after working on this for a while, I've figured out how to get these two authentication types to coexist peacefully in the same web application. Using OWIN, set up to call UseCookieAuthentication TWICE, once to enable the new WsFederationAuthentication middleware, and again to enable local cookie authentication. It's not intuitive but behind the scenes, specifying different authentication types for each sets them up as different auth "engines". Here's how it looks in my Startup:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = ctx =>
{
ctx.Identity = TransformClaims(ctx, app);
}
}
});
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = ctx =>
{
ctx.Identity = TransformClaims(ctx, app);
}
}
});
app.UseWsFederationAuthentication(new WsFederationAuthenticationOptions
{
Wtrealm = Realm,
MetadataAddress = Metadata,
Caption = "Active Directory",
SignInAsAuthenticationType = CookieAuthenticationDefaults.AuthenticationType
});
This is successfully allowing users to authenticate to either local SQL tables or to ADFS 2.0. The TransformClaims callout is allowing me to normalize my claims between these two providers so they are consistent.
EDIT: Here's a very rudimentary TransformClaims. You can do a lot of things inside this: get the user from your DB, setup claims for navigation, custom permissions, role collections, whatever. I just built this slimmed-down version from a much larger implementation so I've not run it but hopefully you get the idea of how to leverage the OnResponseSignIn event.
private static ClaimsIdentity TransformClaims(CookieResponseSignInContext ctx, IAppBuilder app)
{
var ident = ctx.Identity;
var claimEmail = ident.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Email);
var claimName = ident.Claims.SingleOrDefault(c => c.Type == ClaimTypes.Name);
//normalize my string identifier
var loginString = (claimEmail != null) ? claimEmail.Value : (claimName != null) ? claimName.Value : null;
var efctx = ctx.OwinContext.Get<DBEntities>();
var user = UserBL.GetActiveUserByEmailOrName(efctx, loginString);
if (user == null)
{
//user was auth'd by ADFS but hasn't been auth'd by this app
ident.AddClaim(new Claim(ClaimTypesCustom.Unauthorized, "true"));
return ident;
}
if (ident.Claims.First().Issuer == "LOCAL AUTHORITY")
{
//Local
//local already has claim type "Name"
//local didn't have claim type "Email" - adding it
ident.AddClaim(new Claim(ClaimTypes.Email, user.Email));
}
else
{
//ADFS
//ADFS already has claim type "Email"
//ADFS didn't have claim type "Name" - adding it
ident.SetClaim(ClaimTypes.Name, user.UserName);
}
//now ident has "Name" and "Email", regardless of where it came from
return ident;
}