How can I add a Role in the new ASP.NET Identity system (1.0)?
There is a UserStore class but no RoleStore class.
I can't find any documentation on this issue.
RoleManager = new RoleManager<IdentityRole>(
new RoleStore<IdentityRole>(new MyDbContext()));
var roleresult = RoleManager.Create(new IdentityRole(roleName));
Starting with the .NET Framework 4.5, Windows Identity Foundation (WIF) has been fully integrated into the .NET Framework.
I would advice to examine the possibility, in my opinion the preferred, to implement Authorization through Claims (Expressing Roles as Claims).
When the IsInRole() method is called, there is a check made to see if the current user has that role.
In claims-aware applications, the role is expressed by a role claim type that should be available in the token.
The role claim type is expressed using the following URI:
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role"
So from the UserManager you can do something like this (without the RoleManager):
var um = new UserManager();
um.AddClaimAsync(1, new Claim(ClaimTypes.Role, "administrator"));
Claims can simplify and increase the performance of authentication and authorization processes.
You can use the roles stored as claims to eliminate back-end queries every time authorization takes place.
Using Claims you will not need the RoleStore anymore (at least for the equivalent authorization purposes...)
I used below snippets in one sample asp.net web page page_load for starting to grasp the way ASP Identity works
UserManager userManager = new UserManager();
var roleStore = new RoleStore<IdentityRole>(new ApplicationDbContext());
var roleManager = new RoleManager<IdentityRole>(roleStore);
var applicationRoleAdministrator = new IdentityRole("superadmin");
if (!roleManager.RoleExists(applicationRoleAdministrator.Name))
{
roleManager.Create(applicationRoleAdministrator);
}
ApplicationUser applicationUserAdministrator = userManager.FindByName(User.Identity.Name);
if (!userManager.GetRoles(applicationUserAdministrator.Id).Contains("superadmin"))
{
Response.Redirect("~/account/login.aspx?ReturnUrl=" + Request.Url.AbsolutePath);
}
Of course below ApplicationDbContext is automatically generated with ASP.NET 4.5+ templates like below
public class ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
: base("DefaultConnection")
{
}
}
Also Create application Role Manager class too
public class ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole, string> roleStore)
: base(roleStore)
{
}
public static ApplicationRoleManager Create(IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
{
//return new ApplicationRoleManager(new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
return new ApplicationRoleManager(new RoleStore<IdentityRole>(new ApplicationDbContext()));
}
}
also add below line in your startup.Auth.cs => ConfigureAuth(IAppBuilder app) method
app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
And then in your controller:
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
{
get
{
return _roleManager ?? HttpContext.GetOwinContext().Get<ApplicationRoleManager>();
}
private set
{
_roleManager = value;
}
}
I am new to this Identity Stuff and I am not sure if it is necessary or I am doing it clean and right, but these steps worked for me
ASP.NET identity is claims aware with respect to roles. That really confused me because in the previous system you configured membership and role providers in web.config.
The issue for me is that I have code like this:
HttpContext.Current.User.IsInRole("some role")
Fortunately, this logic still works. You can see the logic in the CreateAsync function in ClaimsIdentityFactory.cs which is in Microsoft.AspNet.Identity.Core. One of the arguments is UserManager. It asks it if it SupportsUserRole and if so then it calls GetRolesAsync and adds each role as a claim to the ClaimIdentity. There is no need to do this yourself.
IsInRole uses claims as described here:
http://msdn.microsoft.com/en-us/library/hh545448.aspx
Related
In previous versions of ASP.NET, if I wanted to have a custom class as my current logged in user, what I did was: I let the FormsAuthentication module do its work, and then, in the PostAuthenticateRequest event I replaced the current Principal (HttpContext.Current.User) with my custom principal object that I fetched from the database (with some caching for performance).
How can I achieve the same in ASP.NET Identity? I have my own ApplicationUser (not the default that comes with the EntityFramework ASP.NET Identity) and my own UserStore.
In every authenticated request, I have the HttpContext.User as a ClaimsPrincipal object. Is there a way to replace that with my CustomClaimsPrincipal?
Is there another, better way, to retrieve the current ApplicationUser instance based on the current ClaimsPrincipal?
If you have your own IUserStore you can implement IUserClaimStore to customize the claims identity which is passed to the claims principal.
If you need to replace the default claims principal you should implement the IUserClaimsPrincipalFactory and pass your implementation to the SignInManager and register the configured manager to your owin context.
It should look like this along the lines.
(Assuming you are using ASP.NET Core Identity, for Identity v2 the interfaces and constructors may differ!)
class CustomClaimsFactory<TUser> : Microsoft.AspNetCore.Identity.IUserClaimsPrincipalFactory<TUser>
where TUser : class
{
public Task<ClaimsPrincipal> CreateAsync(TUser user)
{
// create and return your custom principal
}
}
class OwinStartup
{
public void Configuration(IAppBuilder app)
{
app.CreatePerOwinContext(CreateSignInManager);
}
Microsoft.AspNetCore.Identity.SignInManager CreateSignInManager()
{
UserManager manager; // the manager that uses your custom IUserStore
IHttpContextAccessor accessor; // I don't know where to get it from...
var factory = new CustomClaimsFactory();
return new SignInManager(manager, accessor, factory, null, null, null);
}
}
For ASP.Net Core the OWIN-like startup configuration is done via dependency injection.
I'm looking into asp.net core and the new security policies and claims functionality. Having just looked at it I don't see how it is much better than the existing authorize attribute logic in the past where hard-coded roles or users are decorated on controllers, methods etc. To me the issues has just been moved from hard-coding in attributes to hard-coding policies.
Ideally I would like to perform activity/resource based authorization where everything would be database driven. Each activity or resource would be stored in the database and a permission/role would be assigned to the resource.
While researching the topic I found this fantastic article by Stefan Wloch that pretty much covers exactly what I'm looking to do.
http://www.codeproject.com/Articles/1079552/Custom-Roles-Based-Access-Control-RBAC-in-ASP-NE
So my question is with the new core features how does it prevent us from having to hard-code and recompile when the time comes to change what roles/permissions are allowed to access a controller or method in a controller? I understand how claims can be used to store anything but the policy portion seems susceptible to change, which gets us back to square one. Don't get me wrong, loving asp.net core and all the great changes, just looking for more information on how to handle authorization.
There are at least 2 things that need to be consider in implementing what you want. The first one is how to model the Controller-Action access in database, the second one is to apply that setting in asp.net core Identity.
The first one, there are too many possibilities depend on the application itself, so lets create a Service interface named IActivityAccessService that encapsulate. We use that service via dependency injection so that anything that we need can be injected to it.
As for the second one, it can be achieved by customize AuthorizationHandler in a policy-based authorization. The first step is to setup things in Startup.ConfigureServices :
services.AddAuthorization(options =>
{
options.AddPolicy("ActivityAccess", policy => policy.Requirements.Add( new ActivityAccessRequirement() ));
});
services.AddScoped<IAuthorizationHandler, ActivityAccessHandler>();
//inject the service also
services.AddScoped<IActivityAccessService, ActivityAccessService>();
//code below will be explained later
services.AddHttpContextAccessor();
next we create the ActivityAccessHandler:
public class ActivityAccessHandler : AuthorizationHandler<ActivityAccessRequirement>
{
readonly IActivityAccessService _ActivityAccessService;
public ActivityAccessHandler (IActivityAccessService r)
{
_ActivityAccessService = r;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext authHandlerContext, ActivityAccessRequirement requirement)
{
if (context.Resource is AuthorizationFilterContext filterContext)
{
var area = (filterContext.RouteData.Values["area"] as string)?.ToLower();
var controller = (filterContext.RouteData.Values["controller"] as string)?.ToLower();
var action = (filterContext.RouteData.Values["action"] as string)?.ToLower();
var id = (filterContext.RouteData.Values["id"] as string)?.ToLower();
if (_ActivityAccessService.IsAuthorize(area, controller, action, id))
{
context.Succeed(requirement);
}
}
}
}
public class ActivityAccessRequirement : IAuthorizationRequirement
{
//since we handle the authorization in our service, we can leave this empty
}
Since we can use dependency injection in AuthorizationHandler, it is here that we inject the IActivityAccessService.
Now that we have access to what resource is being requested, we need to know who is requesting it. This can be done by injecting IHttpContextAccessor. Thus services.AddHttpContextAccessor() is added in code above, it is for this reason.
And for the IActivityAccessService, you could do something like:
public class ActivityAccessService : IActivityAccessService
{
readonly AppDbContext _context;
readonly IConfiguration _config;
readonly IHttpContextAccessor _accessor;
readonly UserManager<AppUser> _userManager;
public class ActivityAccessService(AppDbContext d, IConfiguration c, IHttpContextAccessor a, UserManager<AppUser> u)
{
_context = d;
_config = c;
_accessor = a;
_userManager = u;
}
public bool IsAuthorize(string area, string controller, string action, string id)
{
//get the user object from the ClaimPrincipals
var appUser = await _userManager.GetUserAsync(_accessor.HttpContext.User);
//get user roles if necessary
var userRoles = await _userManager.GetRolesAsync(appUser);
// all of needed data are available now, do the logic of authorization
return result;
}
}
Please note that the code in IsAuthorize body above is an example. While it will works, people might say it's not a good practice. But since IActivityAccessService is just a common simple service class, we can inject anything that wee need to it and modify the IsAuthorize method signature in any way that we want to. For example, we can just pass the filterContext.RouteData instead.
As for how to apply this to a controller or action:
[Authorize(Policy = "ActivityAccess")]
public ActionResult<IActionResult> GetResource(int resourceId)
{
return Resource;
}
hope this helps
I'm having problems with custom membership within MVC 4 I keep getting a context lifetime related error when I do a ajax call to get a partial result from the server(controller), the error is always {"The provider has been closed"} or {"There is already an open DataReader associated with this Command which must be closed first."} the error always lands within the custom RoleProvider.
I will try to explain the current setup im using.
I have inherited from the Membership and RoleProvier and overridden all the methods like so
public class CustomRoleProvider : RoleProvider
{
private IAccountService _accountService;
public CustomRoleProvider()
{
_accountService = new AccountService();
}
public override string[] GetRolesForUser(string username)
{
return _accountService.GetRolesForUser(username);
}
}
The Membership provider is implemented in the same way the IAccountService above is the service layer that deals with all user accounts & roles all the service layer classes implement a base service class called ServiceBase that creates the DB context
public class ServiceBase
{
protected Context Context;
protected ServiceBase() : this("Context") {}
protected ServiceBase(string dbName)
{
IDatabaseInitializer<Context> initializer = new DbInitialiser();
Database.SetInitializer(initializer);
Context = new Context(dbName);
}
}
The Controller that has the ajax to made to it
[Authorize(Roles = "Administrator,Supplier")]
public class AuctionController : Controller
{
private IAuctionService _service;
public AuctionController()
{
_service = new AuctionService();
}
public AuctionController(IAuctionService service)
{
_service = service;
}
[CacheControl(HttpCacheability.NoCache), HttpGet]
public ActionResult RefreshAuctionTimes(int auctionId)
{
return PartialView("_AuctionTimer", BusinessLogic.Map.ConvertAuction(_service.GetAuction (auctionId)));
}
}
The problem only started when I added the [Authorize(Roles = "Administrator,Supplier")] attribute to the controller that handled the ajax call, I know this is the lifetime of the DbContext being for the life of the app and the controllers service layer being destroyed and recreated on every post but I'm not sure of the best way to handle this, I have used this setup before but with DI and Windsor and never had this problem as the IOC was controlling the context.
Would it be best to create the providers its own DB context or is the conflict between the 2 providers and really they need to share the same db context?
Any help would be great thanks
The problem is exactly what you're suspecting. Is due to the fact that you're creating a single instance of the DbContext and therefore you're having connection issues. If you use it with an IOC/DI schema, you're going to fix it. The other option is to manually handle the connections.
An example of how to do this using Ninject as IOC container is here
They need to share the same context in order for the problem to stop.
I would suggest you create your service layer class on each call to GetRolesForUser:
public override string[] GetRolesForUser(string username)
{
return new AccountService().GetRolesForUser(username);
}
Edit: This question is outdated
The Identity Framework was a moving target at the moment I asked this. The authors changed quite a few things and they have decoupled several others, making everything easier.
Have a look at the Asp.NET Identity Sample project on github.
I'm creating a small application that requires user management. Registration is not allowed, instead there is a super user that will create and modify login information.
I'm using the new ASP.NET Identity membership system, and sure enough, creating users and adding roles is easy and intuitive.
Now, my question: How to obtain a list of users using the AuthenticationIdentityManager class that is used by the generated AccountController class? I couldn't find a way to access the user list from my controller.
(By the way, the new name "Identity" may sound awesome to some people but it is a pain to search for.)
Edit: If I try to do this
ApplicationDbContext UsersContext = new ApplicationDbContext();
UsersContext.Users.ToList(); // Exception
I get an exception Invalid column name 'Discriminator'. The definition of ApplicationDbContext is generated automatically by the new application wizard:
using Microsoft.AspNet.Identity.EntityFramework;
namespace Cobranzas.Models
{
public class ApplicationUser : User
{
}
public class ApplicationDbContext : IdentityDbContextWithCustomUser<ApplicationUser>
{
}
}
So my guess is that Discriminator column is for telling apart ApplicationUser from User. However, it does not exists in my database (which was created automatically by the application.)
I found out that I wasn't using the derived ApplicationUser object for anything, so I just went ahead and changed all uses of it for plain old User. Then I just changed ApplicationDbContext definition for the following:
public class ApplicationDbContext : IdentityDbContext<
User, UserClaim, UserSecret, UserLogin,
Role, UserRole, Token, UserManagement>
{
}
And now I can access the user list:
UsersContext = new ApplicationDbContext();
...
UsersContext.Users.ToList();
However, I think this will come back and haunt me in the future (I'll probably need to add more fields to User) so probably I'll have to use the same approach as in this question:
Get all role names in ASP.NET MVC5 Identity system
Edit: Since I got the need to add a new property, I had to revert my changes. So I went ahead and did a line by line comparison with the ASP.NET Identity Sample Project, and found out that the generated project had the following line:
IdentityManager = new AuthenticationIdentityManager(new IdentityStore());
while the Sample application had included the database context in the constructor. So I added it in my constructor, recreated the database and the problem went away.
IdentityManager = new AuthenticationIdentityManager(new IdentityStore(new ApplicationDbContext()));
Create ASP .NET MVC5 project by default
Create ASP .NET Identity tables properly and change connection string as well.
To get users just do the following test
A. Go to AccountController
B. Create any dummy method and put there
var context = new ApplicationDbContext();
var allUsers = context.Users.ToList();
For RTM, you will have to drop down to your DbContext or whatever your specific store implementation has to enumerate all users. In the next release, we will most likely be adding an optional IQueryable Users/Roles method on the Manager classes that stores can implement to expose IQueryables for both users and stores.
using System.Linq;
using System.Data;
using System.Data.Entity;
var db = new ApplicationDbContext();
var Users = db.Users.Include(u => u.Roles);
If we can use the following type of Constructor in Identity AccountController.
public AccountController(ApplicationUserManager userManager,
ISecureDataFormat<AuthenticationTicket> accessTokenFormat)
{
UserManager = userManager;
AccessTokenFormat = accessTokenFormat;
}
public ApplicationUserManager UserManager
{
get
{
return _userManager ?? Request.GetOwinContext().GetUserManager<ApplicationUserManager>();
}
private set
{
_userManager = value;
}
}
then we can directly used UserManager object to get user list like
var userList= UserManager.Users.ToList();
You can do this by explicitly setting right types:
var userStore = new UserStore<IdentityUser>();
var userManager = new UserManager<IdentityUser>(userStore);
IQueryable<IdentityUser> usersQuery = userManager.Users;
List<IdentityUser> users = usersQuery.ToList();
Imoports:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using System.Linq;
using System.Collections.Generic;
I need to create Unit Tests for an ASP.NET MVC 2.0 web site. The site uses Windows Authentication.
I've been reading up on the necessity to mock the HTTP context for code that deals with the HttpContext. I feel like I'm starting to get a handle on the DI pattern as well. (Give the class an attribute of type IRepository and then pass in a Repository object when you instantiate the controller.)
What I don't understand, however, is the proper way to Mock the Windows Principal object available through User.Identity. Is this part of the HttpContext?
Does any body have a link to an article that demonstrates this (or a recommendation for a book)?
Thanks,
Trey Carroll
I've used IoC to abstract this away with some success. I first defined a class to represent the currently logged in user:
public class CurrentUser
{
public CurrentUser(IIdentity identity)
{
IsAuthenticated = identity.IsAuthenticated;
DisplayName = identity.Name;
var formsIdentity = identity as FormsIdentity;
if (formsIdentity != null)
{
UserID = int.Parse(formsIdentity.Ticket.UserData);
}
}
public string DisplayName { get; private set; }
public bool IsAuthenticated { get; private set; }
public int UserID { get; private set; }
}
It takes an IIdentity in the constructor to set its values. For unit tests, you could add another constructor to allow you bypass the IIdentity dependency.
And then I use Ninject (pick your favorite IoC container, doesn't matter), and created a binding for IIdentity as such:
Bind<IIdentity>().ToMethod(c => HttpContext.Current.User.Identity);
Then, inside of my controller I declare the dependency in the constructor:
CurrentUser _currentUser;
public HomeController(CurrentUser currentUser)
{
_currentUser = currentUser;
}
The IoC container sees that HomeController takes a CurrentUser object, and the CurrentUser constructor takes an IIdentity. It will resolve the dependencies automatically, and voila! Your controller can know who the currently logged on user is. It seems to work pretty well for me with FormsAuthentication. You might be able to adapt this example to Windows Authentication.
I don't know for MVC 2.0, but in newer versions you can mock the ControllerContext:
// create mock principal
var mocks = new MockRepository(MockBehavior.Default);
Mock<IPrincipal> mockPrincipal = mocks.Create<IPrincipal>();
mockPrincipal.SetupGet(p => p.Identity.Name).Returns(userName);
mockPrincipal.Setup(p => p.IsInRole("User")).Returns(true);
// create mock controller context
var mockContext = new Mock<ControllerContext>();
mockContext.SetupGet(p => p.HttpContext.User).Returns(mockPrincipal.Object);
mockContext.SetupGet(p => p.HttpContext.Request.IsAuthenticated).Returns(true);
// create controller
var controller = new MvcController() { ControllerContext = mock.Object };
see also How to unit-test an MVC controller action which depends on authentification in c#?
Scott Hanselman shows in his blog how to use IPrincipal and ModelBinder to make easier to test the controller by mocking IPrincipal.
Example for mocking username and SID on MVC4.
The username and SID (Windows Authentication) in the following action should be tested:
[Authorize]
public class UserController : Controller
{
public ActionResult Index()
{
// get Username
ViewBag.Username = User.Identity.Name;
// get SID
var lIdentity = HttpContext.User.Identity as WindowsIdentity;
ViewBag.Sid = lIdentity.User.ToString();
return View();
}
}
I use Moq and Visual Studio Test Tools. The test is implemented as follows:
[TestMethod]
public void IndexTest()
{
// Arrange
var myController = new UserController();
var contextMock = new Mock<ControllerContext>();
var httpContextMock = new Mock<HttpContextBase>();
var lWindowsIdentity = new WindowsIdentity("Administrator");
httpContextMock.Setup(x => x.User).Returns(new WindowsPrincipal(lWindowsIdentity));
contextMock.Setup(ctx => ctx.HttpContext).Returns(httpContextMock.Object);
myController.ControllerContext = contextMock.Object;
// Act
var lResult = myController.Index() as ViewResult;
// Assert
Assert.IsTrue(lResult.ViewBag.Username == "Administrator");
Assert.IsTrue(lResult.ViewBag.Sid == "Any SID Pattern");
}
I've changed dev environment global.asax and Web.Config for use FormsAuth for force a specific user. The username uses the same WindowsAuth format. See:
public override void Init()
{
base.Init();
this.PostAuthenticateRequest +=
new EventHandler(MvcApplication_PostAuthenticateRequest);
}
void MvcApplication_PostAuthenticateRequest(object sender, EventArgs e)
{
FormsAuthentication.SetAuthCookie("Domain\\login", true);
}
The Windows or Forms Auth shares the same login patterns.
The application will work with both Windows authentication and Form authentication.
To mock WindowsIdentity you can do the following:
var mockedPrincipal = new Mock<WindowsPrincipal>(WindowsIdentity.GetCurrent());
mockedPrincipal.SetupGet(x => x.Identity.IsAuthenticated).Returns(true);
mockedPrincipal.SetupGet(x => x.Identity.Name).Returns("Domain\\User1");
mockedPrincipal.Setup(x => x.IsInRole("Domain\\Group1")).Returns(true);
mockedPrincipal.Setup(x => x.IsInRole("Domain\\Group2")).Returns(false);
then use mockedPrincipal.Object to get the actual WindowsIdentity