Adding user to role / group in code

Adding user to role / group in code

  
Hi, I'm sure I'm missing the glaringly obvious here, but I need to develop some automated user management, and I can't figure out how, from code, to add a user to either a role or a group - I potentially need to be able to do both.

Can one of you please point me to the relevant action?

Or is it supposed to be done by directly editing the system entities? That felt a little 'wrong' to me, so I assumed there'd be a better way.

Cheers, Iain
Outsystems has 2 user management espaces out-of-the-box:
  • User Management (V6.0 & V7.0) : This is a System Espace so you aren't actually able to look at the code, but you could either use this espace or get ideas from the Front End.
  • Enterprise Manager (V5.0 & V6.0):  This Espace is no longer being supported by Outsystems.  You are able to download the Espaces and look at the code to see how they are managing users, groups, and roles.
Hi Rebecca, thanks for the info. I've had a look at the Enterprise Manager eSpace, to be honest it seemed a huge thing, and as it was also a user provider, I wasn't really clear what effect that has - I've not created an eSpace that is a user provider before, I'm afraid.. It seems to add loads and loads of its own entities around the existing user / group / roles stuff, and I couldn't work out what was going on with it. I'd expected to simply see some code that added its own actions to update the existing entities, rather than something with loads of its own data.

If I give a bit more context, maybe that'll help. We are developing a CRM type application, will have a list of people at its core. Some of those people will be on the various teams within our organisation, and will often be on multiple teams. They may head one team up, and be a team member on another team. Also, some but not all of the people will have a user account.

My goal is to build something around the Team entity that we'll create, so if you get added to a particular team as part of the normal contact list updating, that will automatically add your user login (if you have one) to the appropriate groups / roles related to that team (and your role on that team, e.g. team leader). For example, if you get marked as a team leader, you'd then get allocated to a group that'd give you access to a budget app.

If we have to go into the Users eSpace, it becomes detached from the screens that I want various people in the organisation to be able to access in our application, where they can add or remove people to / from their teams as they get involved - that needs to automatically update people's access rights. Also, using the Users interface is essentially an admin function, where I wouldn't want our team leaders to be going.

I can see in the Users eSpace that there are public methods to create / update / delete users and groups (but not roles, for some reason), but there aren't any methods there to add or remove a user from the group or roles.

Does that outline help at all?

Thanks!
Hi, just wondering if anyone else has any ideas on this? Surely this is a common issue, wanting the application itself to configure user permissions, rather than using the Users or Enterprise Manager interfaces? Hoping you can help...

Thanks, Iain
There's built-in actions for granting the roles. Just burrow through the Actions tree and looked at the roles and you'll see it. If you want to really do it the wrong way, you can get a reference to the Roles and UserRole entities under System and create records in them to make the roles and link them to the users like that. J.Ja
Thanks Justin. Actually, I was hoping to use groups rather than roles if possible. 

I don't really need to create groups and roles dynamically, I'm happy to use the Users app for that. It's really about how I assign the users to a group when they are added to a particular team within my app.

Is the only way to do this to create Group_User records directly from my code? I'm really surprised there's not a GrantGroup or GrantRole that allows you to assign a user to a group / role (where the user and group / role would be passed in as a parameter rather than by calling the action associated with each role).

Thanks
Hi Iain,

As I understand you still want to use the Users eSpace to manage your Groups. My suggestion would be for you to map your Team concept to the Group system entity and extend it with whatever extra information you want. This way you'd have something like:

In #1 you have your Team extended from Group so every time you assign someone to this team you're really adding a User to the Group_User entity and you can still manage the roles assigned to this group in the Users app. You can also have a different Leader Group within the team so that you can distinguish the roles assigned to the team leader from the rest of the team. I also added in my example the possibility that teams are hierarchical which you can use to combine the groups you want to assign to the users.

So how do you assign a User to a Group?
You simply create a record in the Group_User entity. I assume that in the context you have you now have both the GroupId and the UserId which are the only two attributes you need. We could have an API like Group_AddUser(GroupId, UserId) but that wouldn't be much different than the CreatGroup_User(record of Group_User) that you already have built in.



In #2 in the first image I point to an attribute in the Group system entity that basically indicates that that Group is not managed by the Users app. In that scenario you could even use your application to define also what roles belong to the Group.

So how do you assign a Role to a Group?
I think you can guess my answer :)


It's not any different than how you add a user to a group.

So, what about giving a specific role to a user?
Well my first guess is that you don't want to manage your permissions that way but exceptions do come along and for completeness sake here's how you can do it.

First thing is that you have an API in ServiceStudio just like Justin said.



Thing is that you need to have the role in your context and if you're trying to manage roles in a cross-application fashion you don't have references to all of them and you shouldn't.

So you can use the same approach and use the User_Role system entity.

But you need to get the Role Id and for that you'll need to use again the System data model...

With this you can build your own role list from where you can select the role you want to add to the group:

Sorry for being so thorough in my answer but I hope someone else from the community could benefit from this.

I also hope I helped you out.

Cheers,
André
Hi Andre, thanks so much for taking the time to fully explain your suggestion. In terms of how to assign users to groups, and roles to groups, the method you outlined above will work perfectly, that will be a big help.

Also, your comment about the Has_Custom_Management attribute was very helpful. I know I said I was happy to use the Users application to configure the groups, but if it's possible to move this into our own application, that would make it even more seamless, which would be great.

I'm going to do some design work to try and apply the principles you've outlined, and I hope that I'll be able to achieve our goals now - thanks again!

Iain
Iain Fogg wrote:
Hi Andre, thanks so much for taking the time to fully explain your suggestion. In terms of how to assign users to groups, and roles to groups, the method you outlined above will work perfectly, that will be a big help.

Also, your comment about the Has_Custom_Management attribute was very helpful. I know I said I was happy to use the Users application to configure the groups, but if it's possible to move this into our own application, that would make it even more seamless, which would be great.

I'm going to do some design work to try and apply the principles you've outlined, and I hope that I'll be able to achieve our goals now - thanks again!

Iain
 
Appreciated.
Keep us posted on your achievements ;)

Cheers,
André
Iain Fogg wrote:
I've had a look at the Enterprise Manager eSpace, to be honest it seemed a huge thing, and as it was also a user provider, I wasn't really clear what effect that has - I've not created an eSpace that is a user provider before, I'm afraid.. 
 
 Hi Iain!

I forgot to include this bit in my answer and I know you'd like to know more about it.

The Is User Provider and User Provider attributes of the eSpace configuration relate to the Single Sign-On feature of the Platform. You can read all about it in our help.

Let me just summarize it in two bullets. When you set the Is User Provider to Yes the impact is has follows:
  • All eSpaces that use this eSpace as their User Provider will share the same user database in the system entity User (How? System entity User is multi-tenant and the tenant Id(s) of your eSpace will be used to filter the users from the system entity - all this out-of-box :))
  • They'll also share the same session, hence the OnSessionStart if defined will be executed.
What you should keep in mind?
ServiceStudio uses the Users eSpace as the default User Provider hence non-blank eSpaces (  ) come with references to the Users eSpace, namely in what respects to user authentication.

 


When you implement your own User Provider you'll need to deal with this. You need to create the users using the entity API:


Note!
Don't forget to encrypt the password or your login will fail and you store clear passwords in the database which is a no no.
Use the built-in Encrypt() function that provides one way encryption.


Now in your login page you can use the built-in System action Login passing the username and the password in clear text. The action will also encrypt it and compare it with what's stored in the database. If it is ok the Session.UserId variable is initialized.

Now that you've dealt with authentication you need to deal with security, you need to assign the roles to the users and groups.

So, basically if you decide to create your own User Provider you'll end up creating something similar to the Users eSpace. By the way if you look into Enterprise Manager you'll see that it does what I described here plus a bunch of other things :)

Cheers,
André
OK, let me check I'm on the right lines here... So...
  • A User Provider eSpace is a wrapper over the top of the existing User table (and also Role and Group tables)
  • A user provider has its own login action, but this is still just running against the User table (albeit separated from other user records due to multi-tenancy) in terms of where to verify the user name and password
So, if it all simply sits over the top of existing entities, what's the benefit of creating your own user provider? What scenario does it help with?

I'd imagined when I first looked at this that it would allow me to use my own entities for users, groups etc. - however, I think it simply allows you to have a separate set of users which are isolated from the main set of users. Is that correct?

I did look at the documentation - I fear this is one of those occasions where if you already understand it, it looks like it makes great sense, but if you don't understand it, I'm not sure it actually makes it that clear - it would be good if it were clearer on the reasons for it, the benefits it brings, and the criteria you have to meet (e.g. which actions you need to incorporate).

I did look a little at the Enterprise Manager which is no longer supported, and there were loads of actions in there - I wasn't clear whether they were all required or not?

Finally I will be using multi-tenancy anyway for my applications - does this impact whether I should be using my own user provider or not?

Thanks again for your input!
Hi Iain!
 
 Iain Fogg wrote:
  • A User Provider eSpace is a wrapper over the top of the existing User table (and also Role and Group tables)

I don't understand what you mean by wrapper in this case... When you set an eSpace as a User Provider the platform will use that eSpace's tenant Id to filter data from the User and Group system entities. The Role entity is not multi-tenant because it represents the roles defined in the eSpace, but as you'd expect the Group_Role and User_Role are.
 
 Iain Fogg wrote:
  • A user provider has its own login action, but this is still just running against the User table (albeit separated from other user records due to multi-tenancy) in terms of where to verify the user name and password

A User Provider needs to deal with login, using the system built-in LoginPassword action, which it may wrap in its own action. The LoginPassword action will know "where" to look in the User entity to search for that username with that encrypted password .

 Iain Fogg wrote:
So, if it all simply sits over the top of existing entities, what's the benefit of creating your own user provider? What scenario does it help with?

I'd imagined when I first looked at this that it would allow me to use my own entities for users, groups etc. - however, I think it simply allows you to have a separate set of users which are isolated from the main set of users. Is that correct?

I think that the necessity to create a different User Provider is two folded:
  1. when you want a different set of users and don't want single sign-on between those applications
  2. when you have an authentication mechanism not supported by the existing User Providers. 
Give me just a second to elaborate on this...

When you install the platform you have basically two User Providers: Users and Service Center. This gives you two user databases, one used by the application developers and devops (the Service Center one) and another one for you to use in your applications and we clearly don't want to mix both, because application users won't have access to service center and vice-versa. Both need to do their own user management and authentication logic.

In the second situation Users provides authentication using:
  • Internal Authentication - default, username and password both validated in the User system entity using system action LoginPassword
  • Active Directory - authentication is performed in Active Directory as you can see in the Users application when you configure it: "The Active Directory authentication uses the underlying Windows machine authentication. Windows domain users will be able to authenticate, provided that the front-end server belongs to the Active Directory domain." .  In this case if you set to use Windows Integrated Authentication authentication is performed by the browser and you won't probably use the login page.
  • LDAP - authentication is done using the LDAP protocol.
In the last 2 options you still have an entry in the User system entity to identify the user and to perform security checking but authentication is performed outside the Agiel Platform. To set the session with UserId and Username you use the system action Login which receives only the User Id.

By now you can imagine that if you want to support another authentication mechanism like OAuth (both Google and facebook use it) for instance you need to implement it in your User Provider.

 Iain Fogg wrote:
I did look a little at the Enterprise Manager which is no longer supported, and there were loads of actions in there - I wasn't clear whether they were all required or not?

Enterprise Manager main goal was to provide single sign-on (which was included in the plaform). It also provided user management and a bunch of different other things that we tipically found in our enterprise applications but with all that it introduced a huge complexity in the application itself and inheritly in the solutions we built with it. Answering your question it isn't all needed for what you wanted to do although I don't think that it would really solved your problem as well.

 Iain Fogg wrote:
Finally I will be using multi-tenancy anyway for my applications - does this impact whether I should be using my own user provider or not?

Yes it sure has. You can check our documentation that hopefully in this case can explain this better then I can. You should check all the Multi-tenant chapter for end user management in particular you have this topic.

Cheers,
André
André Vieira wrote:
I don't understand what you mean by wrapper in this case... 
 
Hi Andre, by wrapper I simply meant that it uses a subset of the data in the User table/entity, rather than you needing to define your own User or Group entites yourself.

 André Vieira wrote:
Yes it sure has. You can check our documentation that hopefully in this case can explain this better then I can. You should check all the Multi-tenant chapter for end user management in particular you have this topic.
 

Sorry, I am still confused by the connection between multi-tenancy and writing your own user provider. If I write my own user provider, and deal with the issues of having unique user names across all tenants, doing the TenantSwitch action etc. that were in the documentation you pointed me to, am I then automatically able to use that user provider in my different tenants?


Thanks for your help with all this
You might want to consider if your User Provider should be multi-tenant also. If you look into Users you'll find out that it is in fact multi-tenant.

And you might ask: why? if it is relying on User system entity that is itself multi-tenant?

The answer to that implies drilling down a bit deeper into multi-tenant. If you read our documentation you'll find out that entities aren't the only language object that is impacted by multi-tenancy, in fact also timers and site properties are configured per tenant.
So if you look into service center you'll find out that you can have different authentication configuraions per tenant and that configuration you do in the Users' user interface is stored in site properties.



Cheers,
André
OK that helps - so my own user provider should be multi-tenant in its own design, then the applications I write should be marked to use that user provider. That way, I can alter site properties per tenant.

I'd not connected some of this stuff up clearly before - I'm not sure it's obvious in the documentation about tenants that when you create a tenant, it's a tenant of the specific user provider. I always assumed the tenancy was separate from the user provider, which is why I was surprised to find that the default tenant is called 'Users'!!!

I'll do some testing with this to work out the best approach - thanks again!