Unable to add and fetch custom claims values - c#

I am using mvc 5 with identity 2.0. I want use custom claim values over the application but I get null values. What am I doing wrong?
Updated code
Login Code in account controller
if (!string.IsNullOrEmpty(model.UserName) && !string.IsNullOrEmpty(model.Password))
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var result = SignInManager.PasswordSignIn(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
//Generate verification token
Dictionary<string, string> acceccToken = null;
if (SignInStatus.Success == 0)
{
var userDeatails = FindUser(model.UserName, model.Password).Result;
if (userDeatails != null)
acceccToken = GetTokenDictionary(model.UserName, model.Password, userDeatails.Id);
}
if (model.RememberMe)
{
HttpCookie userid = new HttpCookie("rembemberTrue", "1");
userid.Expires.AddDays(1);
Response.Cookies.Add(userid);
}
else
{
HttpCookie userid = new HttpCookie("rembemberTrue", "0");
userid.Expires.AddDays(1);
Response.Cookies.Add(userid);
}
#region custom claims
var claims = new Claim[]
{
new Claim("urn:Custom:MasterUniqueId", Convert.ToString(Guid.NewGuid()))
};
ClaimsIdentity identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);
IAuthenticationManager authenticationManager = System.Web.HttpContext.Current.GetOwinContext().Authentication;
authenticationManager.SignIn(identity);
Starup.Auth.cs
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))
},
SlidingExpiration = true,
ExpireTimeSpan = TimeSpan.FromMinutes(60)
});
another controller
Here I am trying to fetch that claim values but it shows null
var identity = (ClaimsIdentity)User.Identity;
var res= identity.FindFirst("urn:Custom:MasterUniqueId");
res is null

You should add those claims on identity validation phase. Please check similar implementation here: Server side claims caching with Owin Authentication

In your account controller, to get a valid authenticationManager, you should use Request.GetOwinContext().Authentication. Im affraid System.Web.HttpContext.Current.GetOwinContext().Authentication gets you a fresh authenticationManager instead of the current Owin context one

First you need to convert identity to claims identity and then try to get claim using identity type
(HttpContext.Current?.User?.Identity as ClaimsIdentity)?.Claims?.FirstOrDefault(x => x.Type == "urn:Custom:MasterUniqueId")?.Value

Related

How to redirect user to same page from which it's logout due to login expire in MVC C#?

I am using MVC5 identity for user login. Currently I using to logout an user if he/she inactive for specific period of time. Now I want to redirect him/her on the same page from which it logout; after the login once again. I am not sure whether it possible or not. Here is my Login ActionResult
public ActionResult Login(string username, string password)
{
var user = new UserManager().IsValid(username, password);
if (user!=null)
{
var ident = new ClaimsIdentity(
new[] {
// adding following 2 claim just for supporting default antiforgery provider
new Claim(ClaimTypes.NameIdentifier, username),
new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string"),
new Claim(ClaimTypes.Name,username),
new Claim(ClaimTypes.Sid,user.UserId.ToString()),
// optionally add roles if any
new Claim(ClaimTypes.Role,user.OperationType),
//new Claim(ClaimTypes.Role, "User"),
},
DefaultAuthenticationTypes.ApplicationCookie);
var claimsPrincipal = new ClaimsPrincipal(ident);
// Set current principal
Thread.CurrentPrincipal = claimsPrincipal;
HttpContext.GetOwinContext().Authentication.SignIn(
new AuthenticationProperties { IsPersistent = false }, ident);
UserManager userManager=new UserManager();
userManager.GetUserMenu();
return RedirectToAction("Index","Home"); // auth succeed
}
// invalid username or password
ModelState.AddModelError("", "invalid username or password");
return View();
}
And my Startup Class class where I set mechanism for logout after a time period and all other,
public class Startup
{
public void Configuration(IAppBuilder app)
{
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=316888
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
CookieSecure = CookieSecureOption.SameAsRequest,
LoginPath = new PathString("/Account/Login") ,
LogoutPath = new PathString("/Account/Logout"),
SlidingExpiration = true,
Provider = new CookieAuthenticationProvider
{
OnResponseSignIn = context =>
{
context.Properties.AllowRefresh = true;
context.Properties.ExpiresUtc = DateTimeOffset.UtcNow.AddMinutes(1); //for test purpose
}
},
ReturnUrlParameter = ""
});
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ApplicationCookie);
}
}
My question is: Is it possible if someone get logout for say home/test with /Account/Login?=%2Fhome%2Ftest as returnurl and then login once again, could it redirect him/her to home/test rather than home/index? If yes, then how could I achieve this?
Once you are logged out and redirected past that point you no longer have any reference to the previous url. When you hit your logout method though you have access to that. Store that in a cookie, check if it exists in your login method, and if it does expire the cookie and send them to the stored route.

GetExternalLoginInfo() returns null

I'm trying to use an Azure AD to authenticate users. Everything seems to be working fine until the redirect to RegisterExternalLogin.aspx.cs. For some reason the Context.GetOwinContext().Authentication.GetExternalLoginInfo() method keeps returning null, causing the application to redirect. Since it redirects here it's failing to create a new Identity User which is causing me issues further down the line.
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);
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
// app.UseCookieAuthentication(new CookieAuthenticationOptions());
var openIDOptions = new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
RedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
}
};
openIDOptions.Scope = "openid profile email";
app.UseOpenIdConnectAuthentication(openIDOptions);
}
Here's the Page_Load() from RegisterExternalLogin.aspx.cs
protected void Page_Load()
{
// Process the result from an auth provider in the request
ProviderName = IdentityHelper.GetProviderNameFromRequest(Request);
if (String.IsNullOrEmpty(ProviderName))
{
RedirectOnFail();
return;
}
if (!IsPostBack)
{
var manager = Context.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = Context.GetOwinContext().Get<ApplicationSignInManager>();
var loginInfo = Context.GetOwinContext().Authentication.GetExternalLoginInfo();
if (loginInfo == null)
{
RedirectOnFail();
return;
}
var user = manager.Find(loginInfo.Login);
if (user != null)
{
signInManager.SignIn(user, isPersistent: false, rememberBrowser: false);
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
}
else if (User.Identity.IsAuthenticated)
{
// Apply Xsrf check when linking
var verifiedloginInfo = Context.GetOwinContext().Authentication.GetExternalLoginInfo(IdentityHelper.XsrfKey, User.Identity.GetUserId());
if (verifiedloginInfo == null)
{
RedirectOnFail();
return;
}
var result = manager.AddLogin(User.Identity.GetUserId(), verifiedloginInfo.Login);
if (result.Succeeded)
{
IdentityHelper.RedirectToReturnUrl(Request.QueryString["ReturnUrl"], Response);
}
else
{
AddErrors(result);
return;
}
}
else
{
email.Text = loginInfo.Email;
}
}
}
I saw a couple of answers related to cookies but these don't seem to fix the issue for me. Any help would be much appreciated.
To implement Azure AD external login using OpenID Connect with ASP.NET identity .You need to enable the application to use a cookie to store information for the signed in user and use a cookie to temporarily store information about a user logging in with a third party login provider . Please refer to below configuration:
// 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
{
OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
validateInterval: TimeSpan.FromMinutes(30),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
// Use a cookie to temporarily store information about a user logging in with a third party login provider
app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when they are verifying the second factor in the two-factor authentication process.
//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);
var openIDOptions = new OpenIdConnectAuthenticationOptions
{
ClientId = clientId,
Authority = authority,
PostLogoutRedirectUri = postLogoutRedirectUri,
RedirectUri = postLogoutRedirectUri,
Notifications = new OpenIdConnectAuthenticationNotifications
{
AuthenticationFailed = context =>
{
context.HandleResponse();
context.Response.Redirect("/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
}
};
openIDOptions.Scope = "openid profile email";
app.UseOpenIdConnectAuthentication(openIDOptions);

Use Azure AD only for Authentication and not Authorization

I've been messing with this for a few days now...
What I would like to do is Authenticate users with Azure AD, and when successful, automatically log them in using ASP.NET Identity for authorization. If they do not have an account I would like to create one automatically.
Essentially Azure AD is just confirming that they are a part of the organization, the ASP.NET Identity portion is it's own database where I can use the [Authorize] attribute to set up custom roles OUTSIDE of Azure AD.
This is my ConfigureAuth() method:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(IntranetApplicationDbContext.Create);
app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
app.CreatePerOwinContext<ApplicationSignInManager>(ApplicationSignInManager.Create);
app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseOpenIdConnectAuthentication(
new OpenIdConnectAuthenticationOptions
{
ClientId = SettingsHelper.ClientId,
Authority = SettingsHelper.Authority,
Notifications = new OpenIdConnectAuthenticationNotifications()
{
// If there is a code in the OpenID Connect response, redeem it for an access token and refresh token, and store those away.
AuthorizationCodeReceived = (context) =>
{
var code = context.Code;
ClientCredential credential = new ClientCredential(SettingsHelper.ClientId, SettingsHelper.AppKey);
String signInUserId = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
AuthenticationContext authContext = new AuthenticationContext(SettingsHelper.Authority, new ADALTokenCache(signInUserId));
AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, SettingsHelper.AADGraphResourceId);
return Task.FromResult(0);
},
RedirectToIdentityProvider = (context) =>
{
// This ensures that the address used for sign in and sign out is picked up dynamically from the request
// this allows you to deploy your app (to Azure Web Sites, for example)without having to change settings
// Remember that the base URL of the address used here must be provisioned in Azure AD beforehand.
string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase;
context.ProtocolMessage.RedirectUri = appBaseUrl + "/";
context.ProtocolMessage.PostLogoutRedirectUri = appBaseUrl;
return Task.FromResult(0);
},
AuthenticationFailed = (context) =>
{
// Suppress the exception if you don't want to see the error
context.HandleResponse();
return Task.FromResult(0);
}
}
});
// 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))
},
});
}
Right now the ASP.NET Identity is taking over when I do a HttpContext.Request.IsAuthenticated which is okay, I just need a way to check if the OpenID portion is authenticated or not so I can put in my custom logic to automatically sign the user in.
Got it!
My biggest problem was attempting to use the OWIN middleware to do everything for me. The OpenID middleware is not needed for simple authentication to Azure AD. I essentially created a OpenIdAuth method in the Account controller which acts as my in-between to authenticate the user with Azure before they have access to the site.
[AllowAnonymous]
public ActionResult OpenIdAuth(string code)
{
string clientId = "00000000-0000-0000-0000-000000000000"; // Client ID found in the Azure AD Application
string appKey = "111111111112222222222223333333333AAABBBCCC="; // Key generated in the Azure AD Appliction
if (code != null)
{
string commonAuthority = "https://login.windows.net/<TENANT_URL>"; // Eg. https://login.windows.net/MyDevSite.onmicrosoft.com
var authContext = new AuthenticationContext(commonAuthority);
ClientCredential credential = new ClientCredential(clientId, appKey);
AuthenticationResult authenticationResult = authContext.AcquireTokenByAuthorizationCode(code, new Uri(HttpContext.Request.Url.GetLeftPart(UriPartial.Path)), credential, "https://graph.windows.net");
var userManager = HttpContext.GetOwinContext().GetUserManager<ApplicationUserManager>();
var signInManager = HttpContext.GetOwinContext().Get<ApplicationSignInManager>();
var user = UserManager.FindByName(authenticationResult.UserInfo.UniqueId);
if (user != null)
{
signInManager.SignIn(user, false, false);
}
else
{
var newUser = new ApplicationUser { UserName = authenticationResult.UserInfo.UniqueId, Email = authenticationResult.UserInfo.DisplayableId };
var creationResult = UserManager.Create(newUser);
if (creationResult.Succeeded)
{
user = UserManager.FindByName(newUser.UserName);
signInManager.SignIn(user, false, false);
}
else
{
return new ViewResult { ViewName = "Error" };
}
}
return Redirect("/");
}
else
{
var url = new Uri($"https://login.microsoftonline.com/<TENANT_URL>/oauth2/authorize?client_id={clientId}&response_type=code&redirect_uri=https://localhost/Account/OpenIdAuth");
return Redirect(url.AbsoluteUri);
}
}
The awesome part is the code variable that will be passed by Microsoft when the user logs in successfully. (As documented Here) I used the same controller method and checked if it was null but technically two different controller methods can be used (Microsoft will redirect back to the url you specify for the redirect_uri parameter).
After I got the authorization code I can use the AuthorizationContext from the Microsoft.IdentityModel.Clients.ActiveDirectory nuget package to call: AcquireTokenByAuthorizationCode. The last parameter is the Resource URI. I'm using the Graph Resource but you can use any other resource that you've given your app access to in the Azure Management Portal.
Finally my ConfigureAuth Method is back to the plain ol' ASP.NET Identity version:
public void ConfigureAuth(IAppBuilder app)
{
// Configure the db context, user manager and signin manager to use a single instance per request
app.CreatePerOwinContext(IntranetApplicationDbContext.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))
},
});
}

Microsoft Owin Sign-Out

I am using Microsoft.Owin to build Sign-On Application integrated with many other applications.
As summary, I generate an accessToken for every application try to login. the application verify accessToken and sign in successfully.
Code sample:
var identity = UserService.UserManager.CreateIdentity(user, DefaultAuthenticationTypes.ExternalBearer);
AuthenticationTicket ticket = new AuthenticationTicket(identity, new AuthenticationProperties());
var currentUtc = new SystemClock().UtcNow;
ticket.Properties.AllowRefresh = true;
ticket.Properties.IssuedUtc = currentUtc;
ticket.Properties.ExpiresUtc = currentUtc.Add(TimeSpan.FromMinutes(30));
var dataProtectionProvider = new EFileDataProtectionProvider(client.ClientID, client.ClientSecret);
var accessTokenFormat = new TicketDataFormat(dataProtectionProvider);
Startup.OAuthBearerOptions.AccessTokenFormat = accessTokenFormat;
string accessToken = Startup.OAuthBearerOptions.AccessTokenFormat.Protect(ticket);
return accessToken;
The problem is:
How to force all other applications to sign out when a user signed out from one application ???
As far as I understood you are trying to logout all the other devices once one device is logged in thus making only one user on the account at all times.
What you need to do is update your user security stamp like so :
await UserManager.UpdateSecurityStampAsync(user.Id);
and then the asp.identity validation will take care of the rest
Please note to have the validation enabled with "OnValidateIdentity" like so:
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.FromSeconds(60),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
This will check stamp validation every 60 seconds on every device.

User.IsInRole() does not work right after role assignment, but does after re-login

In a ASP.NET MVC 5 application I'm using Unity container to create OWIN/Identity objects and resolve all the dependencies.
The problem is when I register as a new user and assign him a role like this
userManager.AddToRole(user.Id, "NewUser");
...
await userManager.UpdateAsync(user);
it actually creates a record in AspNetUserRoles table, but right after that if I check his role with User.IsInRole("NewUser") I get false, unless I log out and then log in again, then it is true.
I guess the problem could be with Identity objects (UserManager, RoleManager, etc.) lifetime management in Unity context.
UnityConfig.cs
public static void RegisterTypes(IUnityContainer container)
{
// DbContext
container.RegisterType<DbContext, AppEntitiesDbContext>();
container.RegisterType<AppIdentityDbContext>();
// Identity
container.RegisterType<IUserStore<ApplicationUser>, UserStore<ApplicationUser>>(
new InjectionConstructor(typeof(AppIdentityDbContext)));
container.RegisterType<IAuthenticationManager>(
new InjectionFactory(c => HttpContext.Current.GetOwinContext().Authentication));
container.RegisterType<IRoleStore<IdentityRole, string>, RoleStore<IdentityRole>>(
new InjectionConstructor(typeof(AppIdentityDbContext)));
container.RegisterType<ApplicationUserManager>();
container.RegisterType<ApplicationSignInManager>();
container.RegisterType<ApplicationRoleManager>();
}
IdentityConfig.cs
(I use <add key="owin:AppStartup" value="MyApp.IdentityConfig" /> in Web.config)
public class IdentityConfig
{
public void Configuration(IAppBuilder app)
{
var container = UnityConfig.GetConfiguredContainer();
app.CreatePerOwinContext(() => container.Resolve<AppIdentityDbContext>());
app.CreatePerOwinContext(() => container.Resolve<ApplicationUserManager>());
app.CreatePerOwinContext(() => container.Resolve<ApplicationSignInManager>());
app.CreatePerOwinContext(() => container.Resolve<ApplicationRoleManager>());
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
LoginPath = new PathString("/Account/Login")
});
}
}
That's because using anything from the User object (IPrincipal) is looking at the identity token of the user for the current HTTP request, not the persisted values of the user.
When you log in that token gets created from the roles and other claims. If you change the user's roles in the database the token needs to be recreated and set as the user's new identity.
When you change a part of the user's identity. Just invalidate the old token and re-issue an new one by signing them out/back in.
private async Task SignInAsync(User user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
Once an user sign in, the some of user information (including current role) stored in the authentication cookie which is created part of the sign in process. This cookie and its information will not update unless if you force re-issue new cookie with newly added role.
So that you will not get newly added role information with User.IsInRole("NewUser"); method.
You need to re-issue the cookie to have the request's user reflect the changes.
https://aspnetidentity.codeplex.com/workitem/2295
Or you need to change your owin startup as follows to set validationInterval to 0. Then every request will hit the database to validate the 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.FromSeconds(0),
regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager))
}
});
For anyone else with this problem (who couldn't get Shoe's solution working, like me), a slightly different approach uses GenerateUserIdentityAsync. This can be placed right in any controller code where you modify the user's roles.
UserManager.AddToRole(User.Identity.GetUserId(), "NewUser");
var updatedUser = await UserManager.FindByNameAsync(User.Identity.Name);
var newIdentity = await updatedUser.GenerateUserIdentityAsync(UserManager);
AuthenticationManager.SignOut();
AuthenticationManager.SignIn(newIdentity);
The answer above didn't solve my problems. My problem get fixed by editing Shoe's answer. I put this code after role assignment .
Request.GetOwinContext().Authentication.SignOut(Microsoft.AspNet.Identity.DefaultAuthenticationTypes.ApplicationCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);

Categories

Resources