Mixing Owin Asp.Net Identity Cookie Authentication with Owin OpenId Authentication - asp.net

Does anyone know a good example of mixing Owin Asp.Net Identity Cookie Authentication (local db) with Owin OpenId Authentication (cloud)? Users could then choose to login/register with either creating new user&pass (stored in local database) or via e.g. Office 365 account. But all users will use the claims and roles in the asp.net Identity (local database).

I have done it like this, but I have some weird issues. Here is my ConfigureAuth method in Startup.Auth.cs
public void ConfigureAuth(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.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
//app.Properties["Microsoft.Owin.Security.Constants.DefaultSignInAsAuthenticationType"] = "ExternalCookie";
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
// LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri
});
}
Logoff method in AccountController
public ActionResult LogOff()
{
//AuthenticationManager.SignOut();
AuthenticationManager.SignOut(
DefaultAuthenticationTypes.ExternalCookie,
DefaultAuthenticationTypes.ApplicationCookie,
OpenIdConnectAuthenticationDefaults.AuthenticationType,
CookieAuthenticationDefaults.AuthenticationType
);
return RedirectToAction("Login", "Account");
}
Here is the issue, I tried to explain on another thread which hasn't got any response yet.
Link for the question

Related

Is it possible to Implement Azure Ad Authentication in webforms without cookie authentication type?

the below is working code.
But I need to implement the solution without sing coockies (UseCookieAuthentication).
After Azure authentication, when we check the AuthenticationTyoe in Identity it shown as Cookies, which i need to avoid. any suggetions/other implementations
public void Configuration(IAppBuilder app)
{
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
// Sets the ClientId, authority, RedirectUri as obtained from web.config
ClientId = clientId,
Authority = authority,
RedirectUri = redirectUri,
// PostLogoutRedirectUri is the page that users will be redirected to after sign-out. In this case, it is using the home page
PostLogoutRedirectUri = redirectUri,
Scope = OpenIdConnectScope.OpenIdProfile,
// ResponseType is set to request the code id_token - which contains basic information about the signed-in user
ResponseType = OpenIdConnectResponseType.CodeIdToken,
// OpenIdConnectAuthenticationNotifications configures OWIN to send notification of failed authentications to OnAuthenticationFailed method
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = OnAuthenticationFailed
}
}
);
}

Asp.NET Identity setting persistent cookie to expire after specific time

I have written a following code like below to refresh user roles after they subscribed to my website like following:
private void RefreshUserRoles()
{
var AuthenticationManager = HttpContext.GetOwinContext().Authentication;
var Identity = new ClaimsIdentity(User.Identity);
Identity.RemoveClaim(Identity.FindFirst(ClaimTypes.Role));
Identity.AddClaim(new Claim(ClaimTypes.Role, "Subscriber"));
AuthenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
new ClaimsPrincipal(Identity),
new AuthenticationProperties { IsPersistent = true}
);
}
Please note this line of code:
AuthenticationManager.AuthenticationResponseGrant = new AuthenticationResponseGrant(
new ClaimsPrincipal(Identity),
new AuthenticationProperties { IsPersistent = true}
);
After user comes back to my website I set the cookie to be persistent, but I forgot to set the expiration for this cookie. I should set this cookie to last for 30 minutes, after which user should be asked to re-log onto the system.
Since some users never re-log on website, this leaves me with an issue, now I need to reset all users cookies in their browsers when they access the website and change their role if they cancelled the subscription. I noticed some users cancelled their subscription and never relogged but yet they still are able to use features on my website...
So my questions are:
How to set expiration of cookie to 30 minutes after which user will be asked to re-log onto the system.
How to Setup to re-check users cookies if they haven't expired in a long time so that I can reset their cookies to regular user if they cancelled subscription?
Here is the ConfigureAuth method I was talking about:
public void ConfigureAuth(IAppBuilder app)
{
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Controller/Action"),
Provider = new CookieAuthenticationProvider
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
That's how I have it set and it works for me.

GetExternalLoginInfoAsync() loginInfo return null - but only after a few hours

I'm using Strava as my external login provider (I assume this is not related to Strava, could be google or facebook also) After running for a few hours / days or even weeks GetExternalLoginInfoAsync return null. I've read a bunch of other questions with the same problem, but did not find a solution. I post my entire ConfigureAuth method, just in case I did something wrong with the order.
If you have a strava account you could probably experience the problem here: fartslek.no/Account/Login
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a user logging in with a third party login provider
// Configure the sign in cookie
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
},
CookieManager = new SystemWebCookieManager()
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
app.UseStravaAuthentication( new StravaAuthenticationOptions{
ClientId="XXX",
ClientSecret= "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
});
}
I'm using this https://github.com/Johnny2Shoes/Owin.Security.Strava to get StravaAuth.
When it stop working a azure reset is not enough, but if I do a new deploy everything works for a while.
I'm using Owin 3.0.1 and Mvc 5.2.3
I had the same problem. After googling a little, I've discovered this is a known bug in Owin, because of the way they handle cookies.
This issue was submitted to Katana Team, but it looks they won't fix it at all. There are many workarounds for this, but this was the simplest I could find:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
ControllerContext.HttpContext.Session.RemoveAll();
// Request a redirect to the external login provider
return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
See this question for more details about this bug, and let me know if this works well for you.

Asp.net MVC when to reload claims when lost

I have added a few custom claims when logging in.
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
var accesses = _roleAccessRepository.GetAssignedAccess(roleId);
foreach (var access in accesses)
{
identity.AddClaim(new Claim("AccessCode", access));
}
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
They work fine until I recently found that after certain inactivity, I assume of more than 30 minutes, these claims are lost. However the user is still logged in.
How do I reload these claims when the user is still logged in?
Update: How it occured.
I logged in to a user and then after roughly 30 minutes opened it again, and logged out of it. Instead of being logged out it refreshed my page, with no claims.
You are facing SecurityStampValidator in action. In the standard MVC5 template from VS2013/VS2015 there is a file App_Start\Startup.Auth.cs that has these lines:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login"),
Provider = new CookieAuthenticationProvider
{
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a password or add an external login to your account.
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
You need to look at SecurityStampValidator.OnValidateIdentity - this method regenerates cookie every 30 minutes (in default configuration). And it does not preserve claims added outside of user.GenerateUserIdentityAsync(manager).
So you need to find ApplicationUser class and modify GenerateUserIdentityAsync(UserManager<ApplicationUser> manager) method to include your claims. And don't add claims anywhere else.

How should I be handling authentication with Identity 2.0 and WebAPI 2.1 and Owin 2?

I'm using
New browser only clients on the same domain
Identity 2.0
WebAPI 2.1
Owin 2.1
AngularJS front-end for registration, login and data display
In a WebAPI application with an AngularJS front-end.
I'm reading about token authentication but I am very confused now and I cannot find any good examples out there that use my combination. What I would like to know is should I be using cookies or tokens for the authentication. Should I be using a Userfactory or the CreatePerOwinContext?
Here's what I have in my Startup.Auth.cs
public partial class Startup {
public void ConfigureAuth(IAppBuilder app) {
app.CreatePerOwinContext(ApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
app.UseCookieAuthentication(new CookieAuthenticationOptions {
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/"),
Provider = new CookieAuthenticationProvider {
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
app.UseTwoFactorSignInCookie(DefaultAuthenticationTypes.TwoFactorCookie, TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such as phone or email.
// Once you check this option, your second step of verification during the login process will be remembered on the device where you logged in from.
// This is similar to the RememberMe option when you log in.
app.UseTwoFactorRememberBrowserCookie(DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
}
}
Here's my WebAPI config:
public static class WebApiConfig
{
public static void CustomizeConfig(HttpConfiguration config)
{
config.Formatters.Remove(config.Formatters.XmlFormatter);
var json = config.Formatters.JsonFormatter;
json.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
json.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
json.SerializerSettings.Converters.Add(new IsoDateTimeConverter { DateTimeFormat = "yyyy-MM-ddTHH:mmZ" });
}
I saw some examples using this code but I am not sure how I can call this:
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new ApplicationOAuthProvider(PublicClientId, UserManagerFactory),
AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
AllowInsecureHttp = true
};
Could I just replace the cookie authentication with this?
Not an expert, but in my dabbling I've found that tokens work great for api and from javascript to api, and traditional cookies lean mostly for a ui. Either or both will work depending on what your trying to do.
You can follow something like this link that does cookie for the ui and token for the api http://blog.iteedee.com/2014/03/asp-net-identity-2-0-cookie-token-authentication/
app.CreatePerOwinContext(ApplicationSession.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Token Authentication
app.UseOAuthBearerAuthentication(new OAuthBearerOptions());
I think you can set the cookie authentication options authentication type to bearer if you want bearer for both, but you would have to play with it. The token would be in the owincontext under ".AspNet.ExternalBearer".
I also think if you register the Identity 2.0 middleware i think it also registers the oauth middleware stuff so you don't need to register the oauthserver middleware yourself. Thats the OAuthAuthorizationServerOptions code you posted. You dont need it.
if the ui and api are in separate then its a bit harder if you want to do some sort of single sign on from the ui pass to the api. I would recommend looking at opensource identity server or authorization server from thinktecture.
If your set on owin middleware and Identity 2.0 you would need to make sure the token can be read by both application and api and you probably would need to implement ISecureDataFormat. But remember, decryption doesn't mean you can 100% trust a token, it should be signed and verified. Depends on your needs.
Sorry, I guess thats a long ramble... Good luck.

Resources