Creating Organization in Liferay using OrganizationLocalServiceUtil.addOrganization? - liferay

I am creating an Organization in Liferay using:
OrganizationLocalServiceUtil.addOrganization (
userId, parentOrganizationId, name,
type, recursable, regionId, countryId,
statusId, comments, false, serviceContext);
Following are my confusions:
Why we need parentOrganizationId?
What does organization status refer to?
Why ServiceContext?

The short answer: There's javadoc
Somewhat longer:
Organizations have an implicit hierarchy - thus, if you create an organization, you might as well create it at the intended position in the hierarchy, thus parentOrganizationId.
You might want to try ListTypeConstants.ORGANIZATION_STATUS_DEFAULT as the status you give
Typically, Liferay stores owners or other data with created entities (e.g. for later permission checks). This is data that can be retrieved from serviceContext.

The answer lies in this documentation.
From the documentation as it is:
userId - the primary key of the creator/owner of the organization
parentOrganizationId - the primary key of the organization's parent organization
name - the organization's name
type - the organization's type
recursable - whether the permissions of the organization are to be inherited by its sub-organizations
regionId - the primary key of the organization's region
countryId - the primary key of the organization's country
statusId - the organization's workflow status
comments - the comments about the organization
site - whether the organization is to be associated with a main site
serviceContext - the organization's service context (optionally null). Can set asset category IDs, asset tag names, and expando bridge attributes for the organization.
To add to the above documentation some specifics in response to your question:
Why we need parentOrganizationId?
Liferay has a concept of heirarchical Organization structure, so you can have levels of Organizations.
So if you want to create top-level Organization then use com.liferay.portal.model.OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID to pass for
parentOrganizationId
What does organization status refer to?
Liferay has workflow (like Kaleo-workflow) for various assets. If you don't want to use this than pass [com.liferay.portal.kernel.workflow.WorkflowConstants.STATUS_APPROVED][4]
Why ServiceContext?
This you can pass as null as stated.
Basically you can think of this class as a collection of different general methods and attributes like Expando, asset-tags, asset-categories etc which can be passed as a single argument by being enclosed in the ServiceContext object rather than as individual arguments and making the method call tedious.
Here is the documentation.
Here are some more details for you to understand this better: Development Guide & Wiki.

A working snippet for Liferay 6.2 for top level organizations is:
ServiceContext serviceContext = ServiceContextFactory.getInstance(request); //or null
Organization organization = OrganizationServiceUtil.addOrganization(
OrganizationConstants.DEFAULT_PARENT_ORGANIZATION_ID,
organizationName,
OrganizationConstants.TYPE_REGULAR_ORGANIZATION,
RegionConstants.DEFAULT_REGION_ID,
CountryConstants.DEFAULT_COUNTRY_ID,
ListTypeConstants.ORGANIZATION_STATUS_DEFAULT,
"",
false,
serviceContext
);
The comment of Olaf Kock before is correct, and using
WorkflowConstants.STATUS_APPROVED
for the status will yield a
com.liferay.portal.NoSuchListTypeException.
I would upvote him, if this would not be a new account.

Related

Add-AzADAppPermission Where to put what Guids? "Resource does not exist or one of its queried reference-property objects are not present."

Within Azure, we set up our OATH2.0 credentials in AAD with three separate AppRegistrations.
I will be referring to these below.
1: Client : this is the main registration.
2: Read: This one holds the AppRole 'Read'
3: Write: This one holds the AppRole 'Write'
Here's some pictures to clearify:
3 Registrations
enter image description here
AppRole inside Read:
enter image description here
enter image description here
I am trying to automate adding these last two as APIpermissions to the first one with powershell.
I have found this command:
Add-AzADAppPermission and took a good look at the documentation here:https://learn.microsoft.com/en-us/powershell/module/az.resources/add-azadapppermission?view=azps-9.3.0
However, Either I am missing something, or this maybe cannot be done with custom appregistrations?
I keep getting the message
"Resource does not exist or one of its queried reference-property objects are not present."
I have checked that I am on the correct Tenant, and I have sufficient rights.
There are four parameters to consider, some more clear to me then others.
APIid: Which I assume, based on the documentation, should be Client.AppId
ApplicationId: Could be ObjectId/ ApplicationId from Read, but perhaps it's from it's corresponding ServicePrincipal (External Application)?, the documentation is not very clear on this one.
ObjectId: Can replace ApplicationId, but I have the exact same question. the documentation does not specify anything other then "The unique identifier in Azure AD."
PermissionId: The documentation says but in the examples they use Guids. I have seen other examples with Strings like "User.Read", so I figure this could be my DisplayName from the appRole inside my Read / Write AppRegistrations.
I've looked for other examples beside the documentation, but so far I've found only examples regarding Built-in appRoles in MsGraph.
The fact that the message is twofold (either it is not there OR something is missing) does not help either.
Bottom line is, I can't figure out which Guid goes where.
I have tried numerous combinations of parameters and AAD Guids, be it ObjectIds and AppIds from both AppRegistrations and their respective Service Principles.
I tried to reproduce the same in my environment and got the same error as below: 
 
Note that: By using Add-AzADAppPermission, one can add the API permissions to the Application, but it is not possible to add
custom roles as API permissions.
Add-AzADAppPermission -ObjectId ObjectID -ApiId APIIdofthepermissions -PermissionId GUIDofAPIPermission
I am trying to add Group.Read.All Microsoft Graph API permission like below:
 
Add-AzADAppPermission -ObjectId ObjectID -ApiId 00000003-0000-0000-c000-000000000000 -PermissionId 5f8c59db-677d-491f-a6b8-5f174b11ec1d
  

NestJS - How to implement RBAC with organization-scoped roles

I am designing a REST backend in Nest.js that needs to allow Users to be a part of multiple Organizations. I want to use role-based access control, such that a user can have one or more named roles. Crucially, these roles need to be able to be either "global" (not dependent on any organization, ex. SUPERUSER), or "scoped" (specific to an organization, ex. MANAGER).
I have decided on this basic database design, which links Users to Organizations using the Roles table in a many-one-many relationship:
As you can see, the organizationId field on a Role is optional, and if it is present, then the user is linked to that organization through the role. If it is not present, I assume this to be a "global" role. I find this to be an elegant database design, but I am having trouble implementing the guard logic for my endpoints.
The guard logic would go something like this:
Look up all the Roles from the database that match the current userId.
For global routes, check that at least one of the returned roles is in the list of required roles for the route.
For scoped routes, do the same, but also check that the organizationId of the role matches the organization ID associated with the operation (I'll elaborate below).
Consider these two endpoints for Jobs. The first will retrieve all the jobs associated with a specified organization. The second will find a single job by its id:
Example route 1:
GET /jobs?organizationId=XXXXX
#Roles(Role.MANAGER, Role.EMPLOYEE)
#UseGuards(JwtAuthGuard, RolesGuard)
#Get()
getMyJobs(#Query() query: {organizationId: string}) {
return this.jobsService.getJobs({
organizationId: query.organizationId,
})
}
Example route 2:
GET /jobs/:jobId
#Roles(Role.MANAGER, Role.EMPLOYEE)
#UseGuards(JwtAuthGuard, RolesGuard)
#Get(':jobId')
getJob(#Param('jobId') jobId: string) {
return this.jobsService.getJob(jobId)
}
In the first example, I know the organizationId without doing any work because it is required as a query parameter. This id can be matched against the id specified in the Role. This is trivial to validate, and ensures that only users who belong to that organization can access the endpoint.
In the second example, the organizationId is not provided. I can easily query it from the database by looking up the Job, but that is work that should be done in the service/business logic. Additionally, guard logic executes before getJob. This is where I am stuck.
The only solution I can come up with is to pass the organizationId in every request, perhaps as a url parameter or HTTP header. Seems like there should be a better option than that. I'm sure this pattern is very common, but I don't know what it is called to do any research. Any help regarding this implementation would be greatly appreciated!
It is just another option for you.
You can modify a user object inside RolesGuard by adding a field that stores available organizations for him/her. So you need to calculate organizations for user, who makes a request inside a guard and then put a result array with ids of organizations to a user field (user.availableOrganizationIds = []). And then use it for filtering results
#Roles(Role.MANAGER, Role.EMPLOYEE)
#UseGuards(JwtAuthGuard, RolesGuard)
#Get()
getMyJobs(#User() user) { // get a user from request
return this.jobsService.getJobs({
organizationIds: user.availableOrganizationIds, // <<- filter by organizations
})
}

How to protect Azure Function Endpoints with custom roles and permission?

I need a starting point to solve the following problem:
Assume there is a model with different entities (e.g. school classes) and different roles that are connected to entities.
Now I want to check in my Azure Function if Bob has a role on this entity which entitles him to rate a student from the school class.
I think of a claim of the form:
TEACHER : [
"class 2b"
]
before.
Which Azure Resources do I need to map such a thing?
I already use Azure AZ for the ID token and my API is implemented in an Azure Function.
I would like to call Azure AD to get an access token which contains those roles and resources of my domain.
I'm afraid that this form is not supported by Azure AD.
The supported form should be "{claim name}": "{claim value}".
If you accept this form, you can refer to my previous answer.
What you need to modify is:
When you create the extensionProperty, you should name the extensionProperty as "TEACHER".
Post https://graph.microsoft.com/v1.0/applications/{object id of the Azure AD application}/extensionProperties
{"name":"TEACHER","dataType":"string","targetObjects":["User"]}
And update the extension property for your account:
Patch https://graph.microsoft.com/v1.0/me
{"extension_6d8190fbf1fe4bc38a5a145520221989_TEACHER":"class 2b"}
Then you can get the custom claim as "TEACHER": "class 2b".

Is there a notion of a tenant name within an MS Teams bot context or function?

In botbuilder, there's a context.activity.channelData object that my bot received. That has a tenant object which only contains an id property. Is there any property or function that can return to me the name of the tenant (organization) who belongs to that id?
Here's an example. A user works for Acme Inc. and has three MS Teams teams: Team1, Team2, and Team3. I can get the names of all the teams, and I can get the tenantId for "Acme Inc." but how can I get the name of the tenant that owns those team, a.k.a. the text Acme Inc.?
Unfortunately, you can't get that info from channelData.
You can use GraphAPI to return the org name.
https://graph.microsoft.com/v1.0/organization?$select=displayName
https://developer.microsoft.com/en-us/graph/graph-explorer
Here is a bot sample on how to use graph in a bot. And here is a sample on using auth in Teams. With all that together, you should be able to get that info.
If needed at all you can get the AAD group ID from TeamsInfo. Info here.
While it's not possible to get the actual tenant name per se from channel data, what you can do in your bot is make a call to get "conversation members", in order to get a UPN for the user(s). Here's an example in C# (I'm sure there's a Node equivalent) an that will give you properties including:
"userPrincipalName": "MeganB#[whatever].OnMicrosoft.com"
That might be enough for what you need?

DDD suggest a relation between entities

I have a following structure.
Resources can have multiple endpoints.
Example:
Resource tickets can be accessed on following endpoints:
/api/tickets
/api/agent/tickets
/api/group/5/tickets
/api/tickets/closed etc.
At first, this looks like aggregate, where Resource is AR, and endpoints are child entities.
I also have UserTypes.
What I need is to build a relation between Usertypes and Endpoints, so each UserType can have a diferrent access for endpoints.
Example for, UserType admin could access all endpoints for tickets resource, while user type agent could have access to only portion of endpoints for the same resource.
What would be a suggested way to connect EndPoints and UserTypes in terms of DDD?
Do you need anything else other than a collection of mapping a between Resources and Endpoints on a UserType? This would give you all usertypes their unique resource endpoint access rights
Also seems to be the same question as Solve apparent need for outside reference to entity inside aggregate (DDD)
I would probably create something like the following:
class ResourceEndpoint {
Guid resourceId;
Guid endpointId;
}
class UserType {
List<ResourceEndpoint> ThingsICanAccess;
}

Resources