I dont want to set the Effective permission when creating the role permissions. I want to set only for the allow checkbox selection.
When i check the "Site Owner Permissions" , automatically selected to all the Effective checkbox. I dont want to select the Effective selection.
Please refer the attached image.
Role-Effective checkbox image:
Any suggestion on what i might be doing wrong? Thanks.
Each module can define it's own permissions and the effective permission is determined based on the permission definitions:
http://docs.orchardproject.net/en/latest/Documentation/Custom-permissions/
Orchard supports so called ImpliedBy permissions and there are also hardcoded stuff like Administator role can do anything.
I struggled with this issue too and i solved it by using a custom authorization event handler to avoid the hardcoded Administator role handling:
public abstract class ExplicitPermissionAuthorizationEventHandler : Orchard.Security.IAuthorizationServiceEventHandler
{
// public
public ExplicitPermissionAuthorizationEventHandler(Orchard.Data.IRepository<Orchard.Roles.Models.UserRolesPartRecord> aUserRolesPartRecords)
{
mUserRolesPartRecords = aUserRolesPartRecords;
}
public void Checking(Orchard.Security.CheckAccessContext aContext) {}
public void Adjust(Orchard.Security.CheckAccessContext aContext) {}
public void Complete(Orchard.Security.CheckAccessContext aContext)
{
if (aContext.Granted && IsModulePermission(aContext.Permission) && aContext.User != null)
{
var lIsAdministrator = mUserRolesPartRecords.Fetch(r => r.UserId == aContext.User.ContentItem.Id && r.Role.Name == "Administrator").Any();
if (lIsAdministrator)
{
// check whether permission is explicitly assigned as Orchard grants all permissions by default when user is in role "Administrator"
var lHasPermissionExplicitly = mUserRolesPartRecords.Fetch(r => r.UserId == aContext.User.ContentItem.Id &&
r.Role.RolesPermissions.Any(p => p.Permission.FeatureName == ModuleName && p.Permission.Name == aContext.Permission.Name)).Any();
if (!lHasPermissionExplicitly)
aContext.Granted = false;
}
}
}
// protected
protected abstract bool IsModulePermission(Orchard.Security.Permissions.Permission aPermission);
protected abstract string ModuleName { get; }
// private
private Orchard.Data.IRepository<Orchard.Roles.Models.UserRolesPartRecord> mUserRolesPartRecords;
}
This should get you an idea how to use authorization handlers.
Related
Since roles don't contain permissions. I am a bit confused by the Roles and Permission in ServiceStack. It appears they are really the same thing? I want to implement a Group, that has roles, that has permissions. Based on the servicestack default implementation I don't think I can extend the provider and get the nested information.
How would i achieve this and still use the authentication attributes.
If i had an attribute
[RequiredPermission("CanAccessPerm")]
That is in Role:HasAccessRole That is in Group:HasAccessGroup
I would want to only use perms to determine access at the API level. Then Roles and Groups to determine who has perms. If Roles contained permissions then I could just extend the CredentialsAuthProvider TryAuthenticate and additionally look at a group table. Is there a way to do this and not rewrite the whole authentication?
Edit 12/12
I am using
container.Register(c =>
new OrmLiteAuthRepository(c.Resolve())
{
UseDistinctRoleTables = AppSettings.Get("UseDistinctRoleTables", true),
});
How do I get to the IManage roles? I see i can override the IAuthRepository.
I found this link. But its not a replacement for Auth
ServiceStack - roles and permissions
-_Edit 12/29 -- It is not calling the methods in MyOrmLiteAuthRepository. Do you know why?
AppHost.cs
container.Register<IAuthRepository>(c =>
new MyOrmLiteAuthRepository(c.Resolve<IDbConnectionFactory>())
{
UseDistinctRoleTables = AppSettings.Get("UseDistinctRoleTables", true),
});
CustomAuthRepo
public class MyOrmLiteAuthRepository : OrmLiteAuthRepository
{
public MyOrmLiteAuthRepository(IDbConnectionFactory dbFactory) : base(dbFactory) { }
public MyOrmLiteAuthRepository(IDbConnectionFactory dbFactory, string namedConnnection = null)
: base(dbFactory, namedConnnection)
{
DbFactory = dbFactory;
NamedConnnection = namedConnnection;
}
public IDbConnectionFactory DbFactory { get; set; }
public string NamedConnnection { get; set; }
public override ICollection<string> GetPermissions(string userAuthId)
{
var permissions = base.GetPermissions(userAuthId);
using (var ss = HostContext.ResolveService<SecurityService>(new BasicRequest()))
{
permissions = ss.UserPermissions(Convert.ToInt32(userAuthId));
}
return permissions;
}
public override bool HasPermission(string userAuthId, string permission)
{
var hasPermission = base.HasPermission(userAuthId, permission);
using (var ss = HostContext.ResolveService<SecurityService>(new BasicRequest()))
{
hasPermission = ss.UserHasPermInRoleOrGroup(permission, Convert.ToInt32(userAuthId));
}
return hasPermission;
}
}
Roles/Permissions work similar in that a User can have multiple Roles and Permissions but they're logically different in that a Role defines the Role a person has like "Employee", "Manager", etc and Permission defines functionality they have access to like "CanSubmitPurchaseOrders", "CanRefundCustomers", etc.
ServiceStack doesn't support Roles having permissions themselves but you can implement this functionality yourself in your own Custom AuthProvider by overriding OnAuthenticated() and populating the Permissions collections of AuthUserSession with a combination of all the permissions in all the Roles a User is in. If you're not using a custom AuthProvider you can modify the Users Session by implementing the OnAuthenticated() Session of Auth Event Hooks.
Alternatively if you're using an AuthRepository like OrmLiteAuthRepository you can change how permissions are managed by overriding its IManageRoles GetPermissions() and HasPermission() APIs to also inspect the Permissions that the Users Roles have assigned to them which you would need to maintain in an out-of-band table.
Overriding OrmLiteAuthRepository
OrmLiteAuthRepository implements IManageRoles so when needed you can cast IAuthRepository to IManageRoles, e.g:
var manageRoles = (IManageRoles)container.Resolve<IAuthRepository>();
You can override OrmLiteAuthRepository and implement your own GetPermissions() and HasPermission() with normal inheritance, e.g:
public class MyOrmLiteAuthRepository : OrmLiteAuthRepository
{
public MyOrmLiteAuthRepository(IDbConnectionFactory dbFactory) : base(dbFactory) { }
public MyOrmLiteAuthRepository(IDbConnectionFactory dbFactory, string namedConnnection = null)
: base(dbFactory, namedConnnection) {}
public override ICollection<string> GetPermissions(string userAuthId)
{
return base.GetPermissions(userAuthId);
}
public override bool HasPermission(string userAuthId, string permission)
{
return base.HasPermission(userAuthId, permission);
}
}
I am wondering how to create and assign roles in Razor Pages 2.1. application.
I have found how to make them for MVC application (How to create roles in asp.net core and assign them to users and http://hishambinateya.com/role-based-authorization-in-razor-pages), however it does not work for razor pages as I have no IServicesProvider instance.
What I want is just to create admin role and assign it to seeded administrator account. Something similar has been done in this tutorial https://learn.microsoft.com/en-us/aspnet/core/security/authorization/secure-data?view=aspnetcore-2.1, but it seems be sutied for MVC and does not work properly after I applied it to my application. Please help me to understand how to create and seed roles in Razor Pages.
Will be very greatfull for help!
I handle the task next way. First, I used code proposed by Paul Madson in How to create roles in asp.net core and assign them to users. Abovementioned method I have inserted into Startup.cs. It creates administrator role and assigned it to seeded user.
private void CreateRoles(IServiceProvider serviceProvider)
{
var roleManager = serviceProvider.GetRequiredService<RoleManager<IdentityRole>>();
var userManager = serviceProvider.GetRequiredService<UserManager<ApplicationUser>>();
Task<IdentityResult> roleResult;
string email = "someone#somewhere.com";
//Check that there is an Administrator role and create if not
Task<bool> hasAdminRole = roleManager.RoleExistsAsync("Administrator");
hasAdminRole.Wait();
if (!hasAdminRole.Result)
{
roleResult = roleManager.CreateAsync(new IdentityRole("Administrator"));
roleResult.Wait();
}
//Check if the admin user exists and create it if not
//Add to the Administrator role
Task<ApplicationUser> testUser = userManager.FindByEmailAsync(email);
testUser.Wait();
if (testUser.Result == null)
{
ApplicationUser administrator = new ApplicationUser
{
Email = email,
UserName = email,
Name = email
};
Task<IdentityResult> newUser = userManager.CreateAsync(administrator, "_AStrongP#ssword!123");
newUser.Wait();
if (newUser.Result.Succeeded)
{
Task<IdentityResult> newUserRole = userManager.AddToRoleAsync(administrator, "Administrator");
newUserRole.Wait();
}
}
}
Then, in the same file in Configure method I add argument (IServiceProvider serviceProvider), so you should have something like Configure(..., IServiceProvider serviceProvider). In the end of Configure method I add
CreateRoles(serviceProvider).
To make this code work create ApplicationUser class somwhere, for example in Data folder:
using Microsoft.AspNetCore.Identity;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
namespace Sobopedia.Data
{
public class ApplicationUser: IdentityUser
{
public string Name { get; set; }
}
}
Finally, inside ConfigureServices method substitute
services.AddIdentity<ApplicationUser>()
.AddEntityFrameworkStores<SobopediaContext>()
.AddDefaultTokenProviders();
with
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<SobopediaContext>()
.AddDefaultTokenProviders();
As a result, after programm starts in table AspNetRoles you will get a new role, while in table AspNetUsers you will have a new user acuiering administrator role.
Unfortunatelly, after you add the following code
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<SobopediaContext>()
.AddDefaultTokenProviders();
pages Login and Registration stop working. In order to handle this problem you may follow next steps:
Scaffold Identity following (https://learn.microsoft.com/en-us/aspnet/core/security/authentication/scaffold-identity?view=aspnetcore-2.1&tabs=visual-studio).
Then substitute IdentityUser for ApplicationUser in entire solution. Preserv only IdentityUser inheritance in ApplicationUser class.
Remove from Areas/identity/Pages/Account/Register.cs all things related to EmailSernder if you have no its implementation.
In order to check correctness of the roles system you may do as follows. In the end of ConfigureServices method in Startup.cs add this code:
services.AddAuthorization(options =>
{
options.AddPolicy("RequireAdministratorRole", policy => policy.RequireRole("Administrator"));
});
services.AddMvc().AddRazorPagesOptions(options =>
{
options.Conventions.AuthorizeFolder("/Contact","RequireAdministratorRole");
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
If it does not worki then just add [Authorize(Roles = "Administrator")] to Contact Page model, so it will look something like this:
namespace Sobopedia.Pages
{
[Authorize(Roles = "Administrator")]
public class ContactModel : PageModel
{
public string Message { get; set; }
public void OnGet()
{
Message = "Your contact page.";
}
}
}
Now, in order to open Contact page you should be logged in with login someone#somewhere.com and password _AStrongP#ssword!123.
after login user can go to any action but think when action is decorated with authorized attribute and role names are specific there. just refer a sample code.
public class HomeController : Controller
{
[Authorize(Roles = "Admin, HrAdmin")]
public ActionResult PayRoll()
{
return View();
}
}
suppose user Foo has no role like Admin or HRAdmin then what will happen when user foo will try to access PayRoll action ?
in this kind of situation i want to redirect user to my error page where i will show a friendly message to user. please guide me how to do it ?
do i need to write a custom authorized attribute from there i need to check user has those roles are not and then redirect user from there?
I don't know if that's the best way to do it, but here's how I did it:
using System.Web.Mvc;
namespace YourNamespace
{
public class AccessDeniedAuthorizeAttribute : AuthorizeAttribute
{
public override void OnAuthorization(AuthorizationContext filterContext)
{
base.OnAuthorization(filterContext);
// Redirect to the login page if necessary
if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
{
filterContext.Result = new RedirectResult(System.Web.Security.FormsAuthentication.LoginUrl + "?returnUrl=" + filterContext.HttpContext.Request.Url);
return;
}
// Redirect to your "access denied" view here
if (filterContext.Result is HttpUnauthorizedResult)
{
filterContext.Result = new RedirectResult("~/Account/Denied");
}
}
}
}
Controller:
public class HomeController : Controller
{
[AccessDeniedAuthorize(Roles = "Admin, HrAdmin")]
public ActionResult PayRoll()
{
return View();
}
}
That's all you have to do if your User has its Roles defined correctly. If you are not using ASP.NET Identity to manage your users and roles, you will need some more code to make this work, in that case this might help you: How can I attach a custom membership provider in my ASP.NET MVC application?.
I have the following code inside MyDataService.svc.cs (This is an example from DevExpress):
namespace MyDataService {
[System.ServiceModel.ServiceBehavior(IncludeExceptionDetailInFaults = true)]
[JSONPSupportBehavior]
public class DataService : DataService<TestDataEntities>, IServiceProvider {
public static void InitializeService(DataServiceConfiguration config) {
config.SetEntitySetAccessRule("*", EntitySetRights.AllRead);
config.DataServiceBehavior.MaxProtocolVersion = DataServiceProtocolVersion.V3;
}
public object GetService(Type serviceType) {
if (serviceType == typeof(IDataServiceStreamProvider)) {
return new ImageStreamProvider();
}
return null;
}
protected override void OnStartProcessingRequest(ProcessRequestArgs args) {
CustomBasicAuth.Authenticate(HttpContext.Current);
if (HttpContext.Current.User == null)
throw new DataServiceException(401, "Invalid login or password");
base.OnStartProcessingRequest(args);
}
}
}
So while this is will check the Entity for a username and password, how safe is it that config.SetEntitySetAccessRule is set to AllRead. Wouldn't someone just be able to see this information on a url such as www.website.com/MyDataService.svc/Customer (where Customer is the table). If this is not so can someone please fill in the conceptual gap I am facing. Thanks!
You are correct that all entities will be returned when queried - AllRead just disallows insert updates and deletes.
You will need to use Query Interceptor to add your logic to restrict users to the set of data they have permission to view, for example adding a check user id to the query.
I'm trying to set a value to true after the user has been authenticated, so that they can use the page after authentication. When I set the value to true and redirect them to that same page that value is false again. I'm sure it has to do with different instances of the class but I dont know how to fix it.
This is the class that sets the value:
if (IsUserAuthorized())
{
Admin admin = new Admin
{
IsAuthorized = true
};
Response.Redirect("~/Admin.aspx");
}
else
{
LblErrorMessage.Text = "Please check your \"User Name\" or \"Password\" and try again.";
}
This is the class that needs to know the value:
public partial class Admin : System.Web.UI.Page
{
public bool IsAuthorized { get; set; }
protected void Page_Load(object sender, EventArgs e)
{
if (IsAuthorized)
{//Do something} }
else
{
Response.Redirect("~/UserAuthentication.aspx");
}
}
classes do not persist between pages. What you need is either of the following two
Store the login status in cookies. That is how most sites do it. That is how e.g. on an email client you can navigate to various pages but still stay logged in.
Store the login status as session variables. Your login variable (true/false) resides in session.