Multi-Tenant Administration Example
Example application that demonstrates and explains multi-tenancy in Mendix.
How to setup a multi tenant app
Are you thinking about making your app multi-tenant but are not sure about how to start or what challenges you might come across? It might not seem that complex to build a multi-tenant app, but there are several best practices that will ensure you are building a secure and well-performing app for your customer. We've set up an example application that can help you better understand the choices you need to make when developing a multi tenant application. This example app exists of a very basic desk reservation system that can be used by multiple companies.
Please note this how-to is not supported by Mendix, but it can provide help when you want to set up a multi-tenant app.
In this example app you can find the following user roles:
- SystemAdministrator: transcends the tenants, and can manage the companies
- CompanyAdmin: can manage the employees of only their company
- Employee: can reserve a desk
The CompanyAdmin should not have any userroles selected under the user management tab (see image below). This might seem counterintuitive, since you want the CompanyAdmin to manage the employees. However if we would select employee here, the CompanyAdmin would be able to manage all users with the user role Employee, not just from his own company. This is due to the way the Mendix Platform combines the settings of the user management in the Project Security and access rules on entities that are a specialization of the System.User entity.
Note: When you select the (No user roles) option, this means that you can see all the users that do not have a user role linked to their account. Make sure that this one is disabled too.
Company is the Tenant in this MultiTenancy example. There are multiple companies that use this application and we want to make sure all data is separated.
The Employee is the entity that can sign in. It inherits from System.User. Some values from User are duplicated on employee, because we can't put an entity access rule on the User entity. Employee.Blocked_ is calculated because it can be set by both the Administrator and the System.
The CompanyUserRole entity is used for duplication of the System.Userrole. We are not able to use System.Userrole on our pages because the CompanyAdmin doesn’t have user management configured.
Similar to the AccountPasswordData from the Administration module to enable change-password functionality.
User Role Management
The second step is to rebuild the user management functionality for user roles as you normally would via the Security. To make this possible, the functions below have been created.
With an after-startup event, the CompanyUserRoles entities are synchronized with the System.UserRole entities. This way you can use the CompanyUserRoles entities to select a user role for your tenant users. The SystemAdministrator user role is not synchronized, because this will never be assigned to a Company user.
The next step is to manage the companies. This is a function that is offered to the SystemAdministrator role and consists out of the standard CRUD access.
Similar to Account Management from the Administration module, Employee Management is used to create employees (users) for the companies. This feature is available for SystemAdministrators and CompanyAdministrators. This way, the SystemAdministrator can create at least one user for each company, and this user can create more users for their own company. By default, the email address is used as a username. This is done to overcome a duplicate username error due to a situation where different companies would like to use the same username.
Managing passwords is done using the EmployeePasswordData entity. This is done in a similar matter as in the Administration Module. There is one important distinction: the Administration module uses Entity access in the microflow ChangePassword to make sure that only users with the right permissions can change the passwords. Since Entity access can’t be enabled for the CompanyAdministrator (no user management) a validation needs to be used instead (see Employee_SetPasswordData).
The way to start protecting the data of your app is to set access rules on the entities in your domain model. In a multi-tenant app, it is required to add an XPath constraint to your access rule. This constrains your data to your tenant. In this way, you prevent tenants from seeing information of other tenants. Examples of this can be found in the DeskReservation module.