I've uploaded some files to the Document Library with the Portlet_DL_DLFileEntryService (/tunnel-web/secure/axis/Portlet_DL_DLFileEntryService). Now I'd like modify their permissions. If I'm right I could do that with the Portal_PermissionService (/tunnel-web/secure/axis/Portal_PermissionService). Could someone give me some working examples? Simple soapUI requests would be fine.
For example, I've a DLFileEntrySoap instance and want to add VIEW permission to the Guest role and VIEW and UPDATE permissions to the Publisher role. Which method of the Portal_PermissionService should I call and what are the values of the parameters of the method?
You should use Portal_ResourcePermissionService instead of Portal_PermissionService, it has the following method:
setIndividualResourcePermissions(long groupId, long companyId, String name, String primKey, long roleId, String[] actionIds)
where:
groupId equals with the community id
companyId is probably 1
name is com.liferay.portlet.documentlibrary.model.DLFileEntry or com.liferay.portlet.documentlibrary.model.DLFolder
primKey can be obtained with fileEntry.getPrimaryKey() or folder.getPrimaryKey()
roleId is the id of the role, you can obtain it through Portal_RoleService
actionIds contains the permissions (e.g. VIEW, DELETE)
Related
I want to use Google Secret Manager in my project. To access a saved secret it is necessary to provide a secret name which contains Google project number. It will be convinient to get this number proramatically to form secret name and no to save it in the enviroment variable. I use node.js runtime for my project. I know there is a library google-auth-library which allow to get project id. Is it possible to get project number somehow?
You can access secrets by project_id or project_number. The following are both valid resource IDs that point to the same secret:
projects/my-project/secrets/my-secret
projects/1234567890/secrets/my-secret
You can get metadata, including project_id and project_number from the metadata service. There are many default values. The ones you're looking for are numeric-project-id and project-id.
Here is an example using curl to access the metadata service. You would run this inside your workload, typically during initial boot:
curl "https://metadata.google.internal/computeMetadata/v1/project/project-id" \
--header "Metadata-Flavor: Google"
Note: the Metadata-Flavor: Google header is required.
To access these values from Node, you can construct your own http client. Alternatively, you can use the googleapis/gcp-metadata package:
const gcpMetadata = require('gcp-metadata');
async function projectID() {
const id = await gcpMetadata.project('project-id');
return id
}
You can send a GET request to the Resource Manager API
https://cloudresourcemanager.googleapis.com/v1/projects/PROJECT_ID?alt=json
Not sure if the following method can be useful in your case, but I put it here, just in case:
gcloud projects list --filter="$PROJECT_ID" --format="value(PROJECT_NUMBER)"
it should return the project number based on the project identifier (in the PROJECT_ID variable), under assumption, that a user (or a service account) who/which runs that command has relevant permissions.
If you're doing this from outside a Cloud VM, so that the metadata service is not available, you can use the Resource Manager API to convert the project name to project number:
const {ProjectsClient} = require('#google-cloud/resource-manager').v3;
const resourcemanagerClient = new ProjectsClient();
let projectId = 'your-project-id-123'; // TODO: replace with your project ID
const [response] = await resourcemanagerClient.getProject({name: projectId});
let projectNumber = response.name.split('/')[1];
I have an AWS Amplify application that has a structure with multi-organizations:
Organization A -> Content of Organization A
Organization B -> Content of Organization B
Let's say we have the user Alice, Alice belongs to both organizations, however, she has different roles in each one, on organization A Alice is an administrator and has more privileges (i.e: can delete content or modify other's content), while on Organization B she is a regular user.
For this reason I cannot simply set regular groups on Amplify (Cognito), because some users, like Alice, can belong to different groups on different organizations.
One solution that I thought was having a group for each combination of organization and role.
i.e: OrganizationA__ADMIN, OrganizationB__USER, etc
So I could restrict the access on the schema using a group auth directive on the Content model:
{allow: group, groupsField: "group", operations: [update]},
The content would have a group field with a value: OrganizationA__ADMIN
Then I could add the user to the group using the Admin Queries API
However, it doesn't seem to be possible to add a user to a group dynamically, I'd have to manually create each group every time a new organization is created, which pretty much kills my idea.
Any other idea on how I can achieve the result I'm aiming for?
I know that I can add the restriction on code, but this is less safe, and I'd rather to have this constraint on the database layer.
Look into generating additional claims in you pre-token-generation handler
Basically you can create an attribute that includes organization role mapping
e.g.
{
// ...
"custom:orgmapping": "OrgA:User,OrgB:Admin"
}
then transform them in your pre-token-generation handler into "pseudo" groups that don't actually exist in the pool.
I'm new in Laravel that's why I'm pretty sure that my ideas are wrong. To the point...
I'm building Laravel application.
What I have among other:
Users ( build in with Laravel auth with my custom fields )
Roles ( pivot, many to many )
Companies ( each user belongs to company ( many users can belong to one company ).
Locations ( each company has many Locations )
Now I'm in the middle of creating documents. For now it doesn't matter if user_id or company_id will be included in the document header.
What I need is to have ability to e.g.
Show documents - when I go to page with documents list with ADMIN role I will see all docs stored in db BUT when user with USER role goes to the same route ... he'll get the list of owned docs
location/edit/{id} - prevent going to url with not mine id - this is simpler and I guess can be dealed using middleware
I have 3 ideas:
Create somekind of FrontController and inside constructor run method that returns all users_ids ( or all companies_ids ) if user is ADMIN or when USER return only one id. All controller in the application then extends this FrontController
Create Service Class ( end up with many services depends on what model to retrieve ), method to get records from db calling repository with role parameter. Then in this method do the checks which ids should be used.
Maybe User somehow Laravel Policies and before() method. Nów I’m reading documentation but I really don't know how to use it in this case but I feel that this idea is also possible.
I feel that these ideas are "dirty". Can you, please, provide information how to implement this nicely with code snippet? I think this subject is very common and a lot of people will use this thred. I would be grateful for any tips.
One approach could be using local scopes.
https://laravel.com/docs/5.5/eloquent#local-scopes
On your Document model define two scopes:
public function scopeBelongingToUser($query)
{
return $query->where('user_id', auth()->user()->id);
}
// this is the same as doing on your User model
public function documents()
{
$this->hasMany(Document::class);
}
public function scopeBelongingToAdmin($query)
{
if (auth()->user()->roles->contains('admin') {
return $query->select('*');
}
abort(403, 'Unauthorized');
}
Then you can use it later with:
Document::belongingToUser();
Document::belongingToAdmin();
I am trying to consume liferay web services.
I want to check whether a user has permission(add/update/delete) on a resource but I didn't find any method to do that.
I found that liferay implemented permission checking inside the web service methods.
In this way I can show an error message when a user try to perform an action on which he don't have permission.
But I think it's better to not to allow him instead of showing error message.
For ex:
A user don't have permission to add document.
Webservice call will throw an exception when he tries to add a document.
In my view hiding the add button is better than showing an error.
You can use something like this:
PermissionChecker permissionChecker = getPermissionChecker();
if(!permissionChecker.hasPermission(groupId, permissionModelKey, groupId, permissionKey))
throw new PortalException("You don't have the required permissions!");
Where permissionModelKey is the model-name of your resource (ex: com.your.namespace.model.YourClass) and permissionKey is a action-key, that may be defined in your resource-actions/default.xml.
Use this as the first lines of YourClassServiceImpl service method and if the user doesn't have the right permission (don't test it with admin user) it will throw a PortalException. Or if you rather, you can do a graceful exit. It depends only of the way you want to treat that use case.
Hope this helps.
I have no time to elaborate, but you can use hasResourcePermission from ResourcePermissionLocalServiceUtil in order to solve your issue:
public static boolean hasResourcePermission(long companyId,
String name,
int scope,
String primKey,
long roleId,
String actionId)
throws PortalException,
SystemException
Returns true if the role has permission at the scope to perform the action on resources of the type.
Depending on the scope, the value of primKey will have different meanings. For more information, see ResourcePermissionImpl.
Parameters:
companyId - the primary key of the company
name - the resource's name, which can be either a class name or a portlet ID
scope - the scope
primKey - the primary key
roleId - the primary key of the role
actionId - the action ID
Returns:
true if the role has permission to perform the action on the resource; false otherwise
Throws:
PortalException - if a role with the primary key or a resource action with the name and action ID could not be found
SystemException - if a system exception occurred
Link to javadocs: hasResourcePermission
I'm building quite complex REST API. The whole API is protected with authentication.
Some of the resources (like, let's say, Person) should be accessible for anyone in the system, however I'd like to "hide" some fields for specific user's roles.
Let's say the Person resource has following fields:
FirstName
LastName
BirthDate
Address
I'd like them all to be visible for users with HRManager role, hide Address for JuniorHRManager and leave FirstName + LastName for everyone else.
Is that RESTful way to just remove fields from the response based on rules applied for the role which logged in user has?
This would be most simple to implement I guess (since I'm using an excellent ServiceStack which has global response filters), yet I'm not sure if that doesn't break the REST rules?
The only other way I've so far thought of is creating role-specific Resources (like PersonForHRManager etc.) however this would be ridiculous as the system is supposed to have variety of combinations of visible & hidden fields for roles.
I agree with your approach, the response filter would probably be the best solution to do this; and simply mark up the response DTO with an attribute describing the required roles. I haven't seen a better way to do property level permissions.
It is perfectly acceptable to remove properties from response based on roles, if it is a public API just make sure to document the properties people can expect back in each role.
Response Filter, in your AppHost:
this.ResponseFilters.Add((req, res, dto) => {
// Get the roles you are permitted to access. You will need to store these in the request Items collection
var roles = (from r in req.Items where r.Key == "Roles" select r.Value).FirstOrDefault() as string[];
// Get the type of the response dto
var dtoType = dto.GetType();
// Loop through the properties
foreach(var property in dtoType.GetPublicProperties()){
// Ignore properties that are read-only
if(!property.CanWrite)
continue;
// Get all the role attributes on the property
var attributes = property.GetCustomAttributes(typeof(RequireRoleAttribute), false) as RequireRoleAttribute[];
// Get all the permitted roles
var permittedRoles = new List<string>();
foreach(var attribute in attributes)
permittedRoles.AddRange(attribute.Roles);
// Check if there are specific permitted roles assigned to this attribute
if(permittedRoles.Count != 0)
{
bool permitted = false;
// Check if check require role against roles we may have.
foreach(var role in permittedRoles){
if(roles.Contains(role))
{
// We have a matching role
permitted = true;
break;
}
}
// No permission to the property
if(!permitted) {
var type = property.GetType();
// Set the field to a default value.
property.SetValue(dto, null);
}
}
}
});
The attribute:
public class RequireRoleAttribute : Attribute
{
public string[] Roles { get; set; }
public RequireRoleAttribute(params string[] roles) { Roles = roles; }
}
On the DTO:
[RequireRole("Spiderman","Superman","Batman")]
public string Address { get; set; }
Notes:
You will need to save you permitted roles into the request.Items.Add("Roles", string[])
I haven't tested the above code, so it may not be perfect, but it should be pretty close.
I hope this helps.
I think you got it right. RESTful services is nothing more than simple HTTP requests. Therefore, you have to protect http resources as a whole. I see two possible strategies:
Implement different RESTful service for each role, which is the strategy you suggest. This is not very easy to maintain, as you probably understand.
Implement one RESTful service which returns for all roles but you would have to check for authorization while forming each property value. For example, when you shape the value to be returned for the property Address on the server side, you will have to check the user's role. If the user is an HRManager you would return the right value. If the user is a JuniorHRManager you would have to return the specific property empty or with a respective message indicating that the user is not allowed to access the specific property. This strategy could be easier to maintain, depending on the server side technology used to implement the web service (I don't know which you are using). In .NET for example you could use attributes for each property indicating which authorization roles have access to a specific property. If you use .NET, this and this tutorials could provide some extra guidance.
Hope I helped!