I am currently working on multitenant saas webapp using aspboilerplate and would like to implement the permission management but I got little bit of confusion.
Firstly, what's the difference between MultitenancySides.Host and MultitenancySides.Tenant which I have found here....
public override void SetPermissions(IPermissionDefinitionContext context)
{
context.CreatePermission(PermissionNames.Pages_Users, L("Users"));
context.CreatePermission(PermissionNames.Pages_Roles, L("Roles"));
context.CreatePermission(PermissionNames.Pages_Tenants, L("Tenants"), multiTenancySides: MultiTenancySides.Host);
context.CreatePermission(PermissionNames.Pages_Events, L("Events"), multiTenancySides: MultiTenancySides.Tenant);
}
Secondly, how [AbpAuthorize] differs to
[AbpAuthorize(PermissionNames.Pages_Tenants)]
I found those in event service ( first link and second link) ,
[AbpAuthorize]
public class EventAppService : EventCloudAppServiceBase, IEventAppService
{
private readonly IEventManager _eventManager;
private readonly IRepository<Event, Guid> _eventRepository;
and in TenantService
[AbpAuthorize(PermissionNames.Pages_Tenants)]
public class TenantAppService : AsyncCrudAppService<Tenant, TenantDto, int, PagedResultRequestDto, CreateTenantDto, TenantDto>, ITenantAppService
{
private readonly TenantManager _tenantManager;
Here is what I want and expect to implement permissions in my Multitenant Saas (Core + Angualr SPA) ...
There will be different features ( I say modules) including Event (CRUD), Library(CRUD), Exam(CRUD), Result(CRUD), Attendance(CRUD) and I would like to have full access (CRUD) permission to tenant superadmin (by default assigned when tenant is created) and then superadmin can create role (Assigned module and permission (CRUD) to specific module).
To make it simple, if system has Attendance module/feature then by default a tenant's Superadmin will have full CRUD access whereas if Staff role is created and restricted to CR but not allowed to UD.
I have gone through this tutorial but unable to sort it out.
Thank you.
Firstly, what's the difference between MultiTenancySides.Host and MultitenancySides.Tenant?
MultiTenancySides.Host → can only be assigned to Host users (user.TenantId == null).
MultiTenancySides.Tenant → can only be assigned to Tenant users (user.TenantId != null).
Secondly, how [AbpAuthorize] differs from [AbpAuthorize(PermissionNames.Pages_Tenants)]?
[AbpAuthorize] → user is logged in.
[AbpAuthorize(PermissionNames.Pages_Tenants)] → user is logged in and has that permission.
Related
I'm new to web application in asp.net mvc 5. I'm curious about how static classes behaves in web application. I'd like to know how my program will behave.
Let's say I have CurrentUser static class which stores logged user id.
public static class CurrentUser{
public static int UserId {get; set;}
}
Which is set whenerever user is logging in.
My app is in external server.
So what will happen if:
User A log in -> userId is set to 1, then User B log in (they access to from differentlcoations) so user Id is set to 2. When User A would like to perform action which need to check his Id, will it be 1 or 2?
I checked one scenario where 2 differentpersons log in from one pc at the same time (different tabs) and I know that User Id will be 2 for both of them (when User B logged in as second to the app). How to resolve this?
I've already read: Static classes in web applications.
I know that my solution may be error prone because every one has access to that class but I don't know if static classes in web app aren't store per user (thread?)?
If you store current user in session storage it will be better than static class. Because there is one copy of static class and fields and for every user login the last login is kept.
I am looking for a solution/suggestion that helps me creating permission based access to web api endpoints/controller actions.
Role based access is not suitable becuase I don't have fixed rules that I could use in code like Role("Admin") oder Role("Controller").
Claim based permissions is also not feasable because each user/client can have different permissions on each business object/entity (e.g. Read/Write-access to own tickets and read access to all ticket of his/her company or if its a technician of my company full access to all tickets of all customers. So each user would have 10s or even hundrets of claims which I would have to evaluate at each access of my API.
It is some kind of multi tenancy in just on database and the tenants are our customers with some kind of "master tenant" that has access to all of the tenant data.
I think that something like Visual Guard would satisfy my needs but it is pretty expensive and they don't support net core for now and their documentation seems pretty outdated.
I don't need a usable solution at once but some hints and tricks how I could achieve that would very much be apprieciated because I am looking and searching for some time now.
Details on "database permissions":
What I mean is in my frontend (Winforms app) I want to establish a security system where I can create and assign roles to users and in those roles is defined which actions a user can execute and which CRUD operations he/she can do on specific business objects. Each role can have n users and each role can have n permissions. Each permission on itself declares for exmaple Create:false, Read:true, Write:true and Delete:false. If a permission for a specific business object is not found CRUDs on that BO is denied totally.
So whenever an action in my API is called I have to check if that user and his/her rule allows him to do that specific action based on rules and permissions in my database.
Details an application structure:
Frontend will be a Winforms app which calls the API in the background by OData. I don't want to rely solely on security in the Winforms app because the API will be accessible from the internet and I can't be sure if a user would not try to access the api with his credentials just to see what is possblie without the "frontend filter". So the permissions lie in the API and if a user tries to access s.t. in the frontend app the app itself "asks" the API if that is possible.
Later on I want to create mobile clients that also use the Odata Web API.
The relevant API in asp.net core are:
IAuthorizationService
AuthorizationPolicy
IAuhtorizationRequirement
IAuthorizationHandler
The authorization pattern you are looking for is called Resource-based authorization
https://learn.microsoft.com/en-us/aspnet/core/security/authorization/resourcebased?view=aspnetcore-2.2
Basically, you can define AuthorizationPolicy, and apply it to a instance of a resource:
var ticket = _ticketRepository.Find(ticketID);
var authorizationResult = await _authorizationService
.AuthorizeAsync(User, ticket, "EditTicketPolicy");
In the authorization handler, you can check if the user is the owner of the resource.
public class ResourceOwnerRequirement : IAuthorizationRequirement
{
}
public class ResourceOwnerHandler
: AuthorizationHandler<ResourceOwnerRequirement, MyBusinessObject>
//: AuthorizationHandler<ResourceOwnerRequirement> use this overload to handle all types of resources...
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
ResourceOwnerRequirement requirement,
MyBusinessObject resource)
{
int createdByUserId = resource.CreatedBy;
Claim userIdClaim = ((ClaimsIdentity)context.User.Identity).FindFirst("UserId");
if (int.TryParse(userIdClaim.Value, out int userId)
&& createdByUserId == userId)
{
context.Succeed(requirement);
}
}
}
//admin can do anything
public class AdminRequirementHandler : IAuthorizationHandler
{
public Task HandleAsync(AuthorizationHandlerContext context)
{
if (context.User.Claims.Any(c => c.Type == "Role" && c.Value == "Administator"))
{
while (context.PendingRequirements.Any())
{
context.Succeed(context.PendingRequirements.First());
}
}
return Task.CompletedTask;
}
}
BTW, this still can be called claims or role based authorization. Users with specific role can edit their own tickets, but users with admin role also other tickets. The difference is that you apply authorization to a resource, not just action
EDIT:
We are currently working on a smaller ASP.NET MVC 5 application using ASP.NET Identity. It allows us to maintain different projects and their tasks. We recently implemented basic authentication so we are able to register a user with our site and login with them.
We want to be able to manage access rights on project basis so we can say for every single user that he has read, write, admin or no permissions for a specified project.
My first thought was that we can create a simple new table in our database which stores the user rights. But I feel that there might be a built-in way to achieve this with ASP.NET Identity.
So my question really is, which path we should follow - manually building a new table to administer the rights or use something built-in provided by ASP.NET Identity.
use something built-in provided by ASP.NET Identity
The only things you could use there are claims or roles and both are not built for what you want IMO.
So I would go with your own table which links the project to a user, e.g.:
public class UserProjectRights
{
[Key]
public ApplicationUser User { get; set; }
[Key]
public Project Project { get; set; }
public AccessRight Right { get; set; }
}
Then whenever you do some actions where a specific right is required you need to check for that. There are several ways how you could do that. In my app I created "access right check extensions" like the following (I have defined a common interface for all "access right entities" to "reuse" that method):
public static bool? CanView(this ApplicationUser user, Project project)
{
var userRight = project.Rights.FirstOrDefault(r => r.User == user);
return userRight == null ? (bool?)null : userRight.Right.HasFlag(AccessRight.View);
}
assuming AccessRight is an enum like:
[Flags]
public enum AccessRight
{
View,
Edit,
Admin
}
Then you can do something like the following in your logic:
if (user.CanView(project) == true)
{
// show project
}
I used bool? so I can implement different "default behaviour" as I know if null is returned there is no right defined.
I am creating an application where I first login with my user account. This user account could be windows or self managed account in my own application database.
Now I want to authorize the logged in user before accessing any business objects of my application. Objects are mapped with database tables so eventually I want to authorize user first, whether to give data back to user or not.
After logging in I store user credentials globally as an object of UserCredential class. But I don't want to pass this credentials to each object when I am creating it.
Is there any way to check/reach the application context (including UserCredential object I stored globally) for each business objects automatically which I am creating further?
I want to achieve this in C#. Code example is much appreciated.
You should take a look at the PrincipalPermissionAttribute class, here is the MSDN documentation:
PrincipalPermissionAttribute class MSDN documentation
The PrincipalPermissionAttribute throws a SecurityException when the Thread.CurrentPrincipal does not match the security assertion.
Examples:
User's name is GDroid:
[PrincipalPermission(SecurityAction.Demand, Name = "GDroid")]
public void YourBusinessMethod()
{
// Do something
}
User belongs to Admin role:
[PrincipalPermission(SecurityAction.Demand, Role = "Admin")]
public void YourBusinessMethod()
{
// Do something
}
User is authenticated:
[PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
public void YourBusinessMethod()
{
// Do something
}
In my application there are different user roles like admin, user, superuser. I am using ASP .net membership provider in my application. In my machine.config file the maxInvalidPasswordAttempts is set to 5 which is default for all users. My issue is that, even for a admin user, the maximum invalid password attempts is 5. I need to change the maximum invalid password attempts for the admin user only. Please help.
I don't think that is going to be possible with the default provider. Since the MaxInvalidPasswordAttempts is not even persisted in the database, as far as I can tell. You will probably need to think about writing a derived Membership provider that implements this additional layer.
public class myMembershipProvider : System.Web.Security.SqlMembershipProvider
{
public override int MaxInvalidPasswordAttempts
{
get
{
//Check to the role of the user....and pass back the attempts allowed for them
if (HttpContext.Current.User.IsInRole(Admin))
{
return 9999; whatever...
}
return base.MaxInvalidPasswordAttempts;
}
}
}