In Liferay when a site page is added, it is assigned VIEW permission automatically for Owner role, Guest role and Site Member role.
Is it possible to assign VIEW permissions dynamically to custom role when page is created instead of manually assigning VIEW permission from Manage-permission tab of the site-page?
One of the possible way is Using LayoutListener via hook
For this you need to create hook (portal properties) and override following property:
value.object.listener.com.liferay.portal.model.Layout
See the following example:
value.object.listener.com.liferay.portal.model.Layout=com.smb.mypermissions.hook.listeners.LayoutListener
Here LayoutListener is the custom class created under package com.smb.mypermissions.hook.listeners to override default LayoutListener.
Signature for this class: public class LayoutListener extends BaseModelListener<Layout>
Now override the method
public void onAfterCreate(Layout model)throws ModelListenerException
to assign permission to the role, use following one liner:
ResourcePermissionLocalServiceUtil.setResourcePermissions(
companyId, Layout.class.getName(),
ResourceConstants.SCOPE_INDIVIDUAL,
String.valueOf(primKey), role.getRoleId(),
new String[] {
ActionKeys.VIEW
});
where role can be obtained from RoleLocalServiceUtil and primkey is the page unique id i.e plid
long primKey = model.getPlid();
long companyId = model.getGroup().getCompanyId();
Role role = RoleLocalServiceUtil.fetchRole(companyId, "<Your Role name here>");
Related
I have a web api application which I allow an access to only authorized user.
I do it by using attribute [Authorize] with controllers
Can I restrict from accessing the application a particular user with a given username even though he/she's in Azure AD?
Can I restrict from accessing the application a particular user with a given username even though he/she's in Azure AD?
What you need is to create a policy and check current user against this policy whenever you want.
There're two ways to do that.
Use a magic string to configure policy (e.g. [Authorize(policy="require_username=name")]), and then create a custom policy provider to provide the policy dynamically. For more details, see https://learn.microsoft.com/en-us/aspnet/core/security/authorization/iauthorizationpolicyprovider?view=aspnetcore-2.2
Create a static policy and use a custom AuthorizeFilter to check whether current user is allowed.
Since this thread is asking "Restricting Azure AD users from accessing web api controller", I prefer to the 2nd way.
Here's an implementation for the 2nd approach. Firstly, let's define a policy of requirename:
services.AddAuthorization(opts =>{
opts.AddPolicy("requirename", pb => {
pb.RequireAssertion(ctx =>{
if(ctx.User==null) return false;
var requiredName = ctx.Resource as string;
return ctx.User.HasClaim("name",requiredName);
});
});
});
And to check against this policy, create a custom AuthorizeFilter as below:
public class RequireNameFilterAttribute : Attribute, IAsyncAuthorizationFilter
{
public string Name{get;set;}
public RequireNameFilterAttribute(string name) { this.Name = name; }
public async Task OnAuthorizationAsync(AuthorizationFilterContext context)
{
var user= context.HttpContext.User;
if(user==null){
context.Result = new ChallengeResult();
return;
}
var authZService = context.HttpContext.RequestServices.GetRequiredService<IAuthorizationService>();
var result= await authZService.AuthorizeAsync(user, this.Name, "requirename");
if (!result.Succeeded) {
context.Result = new ForbidResult();
}
}
}
Finally, whenever you want to deny users without required names, simply decorate the action method with a RequireNameFilter(requiredName) attribute:
[RequireNameFilter("amplifier")]
public string Test()
{
return "it works";
}
[Edit]
AAD can restrict Azure AD users from accessing web api controller on an Application level. But cannot disallow an user to access a Controller API (API level).
Here's how-to about restricting Azure AD users on an Application Level
Login your Azure portal:
Choose an Activity Directory (e.g. Default Directory)
Click [Enterprise applications]
Choose the application you want to restrict (e.g. AspNetCore-Quickstart)
Select [Properties], Change the [User assignment required] to Yes
Select [Users and groups], Add/Relete users for this application as you need :
Be aware Azure AD is actually an Indentity Provider. This approach only works for the entire application. It's impossible to allow some user to access the App but disallow him to access a specific controller without coding/configuring the Application. To do that, we have no choice but to authorize uses within the application.
For instance, I have an application 'myApp' in app registrations and I have a user in Azure Active Directory User1 which is an Admin in AD. I want to use authentication via Azure AD in that app and want User1 to have a permissions only to access 'api/todos' and 'api/vehicles'. So there can be a role 'Role1with permissionsTodos,Vehicles`. Is there a way to configure that? Thanks.
Yes, there is a way to configure that. Azure works with a Role concept. This sample shows how to do it in a web API.
In short: You need to define the possible roles and assign users to them via the application configuration in the admin portal. And then you need to define which roles the user should be in using the [Authorize] attribute, on the web API controller methods, e.g. like in one of the sample's controllers:
[Authorize(Roles = "Admin, Observer, Writer, Approver")]
public ActionResult Index()
{
ViewBag.Message = "Tasks";
ViewData["tasks"] = TasksDbHelper.GetAllTasks();
return View();
}
As usual with [Authorize] it is inherited, so you can put it on the entire controller class.
I am using MVC5, windows authentication, structuremap DI and custom role provider.
MvcSiteMapProvider for MVC5 is not picking up the roles to show menu based on user role. When security trimming is enabled it shows only menu items which do not have any roles attribute defined.
I have ActionFilterAttribute implemented and used on controller for authorization. Controller correctly redirects the user to unauthorized page based on roles but menu is not picking the role attributes to hide the menu.
Custom RoleProvider has implementation for GetRolesForUser and GetUsersInRole.
Any suggestion will be helpful.
Also want to know where to look for roles attributes in SiteMapNodeModel. I am thinking of customizing to look for permission in the HtmlHelper while building the menu.
Note: Same implementation is working fine in MVC4. Once upgraded to MVC5 and it does not work.
Thanks
MvcSiteMapProvider for MVC5 is not picking up the roles to show menu based on user role. When security trimming is enabled it shows only menu items which do not have any roles attribute defined.
As per the documentation, the roles attribute is not for use with MVC. It is for interop with ASP.NET pages.
It only functions when the security framework implements IPrincipal and IIdentity as Membership and Identity do.
I have ActionFilterAttribute implemented and used on controller for authorization. Controller correctly redirects the user to unauthorized page based on roles but menu is not picking the role attributes to hide the menu.
This is most likely your issue. Security trimming only looks for AuthorizeAttribute and subclasses of AuthorizeAttribute. If you have subclassed ActionFilterAttribute, it will not be used to hide links from navigation.
Of course, for the standard AuthorizeAttribute to work, you need to implement IPrincipal and IIdentity or use one of the pre-built security frameworks that does the same.
Alternatively, you could build your own IAclModule or ISiteMapNodeVisibilityProvider if you have completely custom security.
Also want to know where to look for roles attributes in SiteMapNodeModel. I am thinking of customizing to look for permission in the HtmlHelper while building the menu.
You would not need to look for roles from the SiteMapNodeModel. Instead, you should get the roles from the current context and make the changes to the menu templates in /Views/Shared/DisplayTemplates/ accordingly.
If you are using a framework that supports IPrincipal and IIdentity, you could just use:
#if (User.IsInRole("SomeRole"))
{
...
}
Also see the following:
ASP.NET MVC 5 Customise Bootstrap navbar based on User Role
Implementing Role Based Menu in ASP.NET MVC 4
If you want to get the current roles that are configured for an action method, you can build an extension method to read the roles from the current AuthorizeAttribute. Again, the roles attribute is only for interoperability with ASP.NET and should not be used for pure MVC, since it means you need to duplicate your roles on AuthorizeAttribute anyway.
public static class ControllerContextExtensions
{
public static IEnumerable<string> Roles(this ControllerContext controllerContext)
{
var controllerType = controllerContext.Controller.GetType();
var controllerDescriptor = new ReflectedControllerDescriptor(controllerType);
var actionName = controllerContext.RouteData.Values["action"] as string;
var actionDescriptor = controllerDescriptor.FindAction(controllerContext, actionName);
var authorizeAttribute = FilterProviders.Providers.GetFilters(controllerContext, actionDescriptor)
.Where(f => typeof(AuthorizeAttribute).IsAssignableFrom(f.Instance.GetType()))
.Select(f => f.Instance as AuthorizeAttribute).FirstOrDefault();
string[] roles = { };
if (authorizeAttribute != null && authorizeAttribute.Roles.Length > 0)
{
roles = Array.ConvertAll(authorizeAttribute.Roles.Split(','), r => r.Trim());
}
return roles;
}
}
Usage
In view:
{ var roles = this.ViewContext.Controller.ControllerContext.Roles(); }
In controller:
var roles = this.ControllerContext.Roles();
To get the roles from the SiteMapNodeModel:
var siteMap = MvcSiteMapProvider.SiteMaps.Current;
var siteMapNode = siteMap.FindSiteMapNodeFromKey(SiteMapNodeModel.Key);
var roles = siteMapNode.Roles;
Suppose I have a simple model, such as "Record":
#Model
public class Record {
private Principal owner; // presume getter/setters as well
}
Then I want to have a simple EJB that controls creating and deleting records. For the sake of argument let's only worry about deleting:
#EJB
#Named
#Stateless
public class RecordMgr {
#PersistenceContext private EntityManager em;
public void delete(Record r) {
em.remove(r);
}
}
I want to restrict access to RecordMgr#delete(Record r) to administrators and the owner: in other words, admins and the people who created the object, and only them, can delete it. I don't see how to accomplish both of these with declarative security. What's the right way to approach this problem?
You cannot do that with declarative security, because there is no way to have connection between role in #RolesAllowed and user that created entity.
Only way is programmatic security and checking that user is creator of bean or Administrator, or both.
Only part where you could utilize declarative security is to list roles that are aloud to create such a record, and administrator role. After that it have to be programmatically checked further that current user's role is administrator or that current user created record. In any case whole logic of declarative security is then duplicated in programmatic security.
I am using the SharePoint Object Model to create new sites programmatically (with a custom web part). It works fine but I am wondering if it is possible to grant permission for groups as well?
When I create the site I have set it to not inherit permission
newWeb = SPContext.GetContext(HttpContext.Current).Web.Webs.Add(siteUrl, siteName, siteDescription, (uint)1033, siteTemplate, true, false);
In the GUI I can then go to Site Actions (on the newly created site) -> Grant Permission -> search for groups in the parent site and then grant permission for this group. So, in the parent site myGroup can have Full Access permissions but in this site I can set it to Contribution or whatever. Is it possible to do this when I create the site or just after (programmatically)?
Thanks in advance.
You must assign a role definition to your group.
Here's a code snippet I wrote to assign a group one of the predefined sharepoint role definitions.
public bool AssignExistingGroupToWeb(SPWeb siteWeb, string GroupName, SPRoleDefinition roleDefinition)
{
//retrieve a group
SPGroup siteGroup = siteWeb.SiteGroups.FindGroupByName(GroupName);
//create a role assignment for the group using the specified SPRoleDefinition
//examples of roles as "Full Control", "Design", etc...
SPRoleAssignment roleAssignment = new SPRoleAssignment(siteGroup);
roleAssignment.RoleDefinitionBindings.Add(roleDefinition);
siteWeb.RoleAssignments.Add(roleAssignment);
siteWeb.Update();
}
You can retrieve a SPRoleDefinition by accessing the RoleDefinitions collection, like so...
siteWeb.RoleDefinitions["Contribute"]