Introduction
In the Basic Service example, we learned to perform a heartbeat check on a service, in order to monitor its health.
Moreover, sample tests to expose the basic functionalities of a SOAJS service, and those of the IMFV.
In the oAuth Security example, one of the APIs from the Basic Service example will be secured with oAuth.
The example allowed the user to explain the integration of the oAuth service with a SOAJS service.
This example explores SOAJS' ability of multitenancy.
Multitenancy allows a collection of tenants/users to share the same set of resources (i.e., a database, service, etc) by allowing each tenant to access only the allowed portion of that resource, and prohibiting them from accessing resources of other tenants.
SOAJS allows different tenants to use the same service, each using their own settings, ACL and configurations.
This example also introduces the User Registration & Access Control (URAC) service, which holds records of all the tenants and its corresponding users.
Moreover, the example teaches how to benefit from multitenancy, and how to configure ACLs, in addition to securing the APIs using tenant keys.
Code Walkthrough
This page shows you how to interact with the example03 & URAC services after you install them and run them. It also demonstrates how SOAJS implements multitenancy.
The code walkthrough is located in a sub page and explained in depth. Click here to read the explanation.
Service Exploration
To turn on URAC in a development environment you just need to start the environment as follow
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
sudo soajs services start --env=example |
Info | ||
---|---|---|
| ||
To verify if oauth is running you need to login to soajs console and
|
Code Block | ||||
---|---|---|---|---|
| ||||
# go to examples/example03 and start the service
cd soajs.examples/example03/
# start the soajs example environment
sudo soajs services start --env=example
# export necessary environment variables to create local awareness
export SOAJS_ENV=EXAMPLE
export SOAJS_SRVPORT=4023
export SOAJS_DEPLOY_MANUAL=1
export SOAJS_REGISTRY_API=127.0.0.1:21000
# start service
node . |
The service is now running and listens on port 4023. Therefore, its maintenance port is 5023.
Next, a heartbeat request is sent to check the health of the service.
Code Block | ||||
---|---|---|---|---|
| ||||
curl -X GET "http://127.0.0.1:5023/heartbeat" |
A response similar to the one below indicates a healthy functioning of the service.
Code Block | ||||
---|---|---|---|---|
| ||||
{"result":true,"ts":1425372737466,"service": {"service":"example03","type":"rest","route":"/heartbeat"}} |
Tenant Level Access Control
Using the Service APIs
As mentioned previously, this example is multitenant. Therefore, this tutorial simulates several tenants, which will be used across the examples that follow.
...
The table above lists three packages. each package represents a list of permissions.
Package1 does not have access to the service.
Package2 has full access to the service.
Package3 has access to only the buildName API of the service.
For instance, a tenant with Package1 may not access any API of the service, whereas a tenant with package3 may only use the buildName API.
...
The example considers three tenants. Each of which using a package, as can be seen in the table above.
An application is defined as the combination of a tenant and a package assigned to that tenant.
Therefore, the table above presents four applications.
Application1 is composed of tenant1 and package1.
Similarly, application2 is composed of tenant2 and package1. However, package1 is overriden in this application.
Thus, this application is able to have full access to the service APIs.
Now that the tenants, packages, and applications are clearly listed, it is time to explore the service APIs using the different tenants.
At the end of this tutorial, the user will have a clear idea on how multitenancy operates, and how SOAJS implements this concept,
in order to efficiently share the resources between tenants and clients, while protecting their data.
buildName using application1: Tenant1, package1
As stated above, tenant1 possesses two applications. This example shows a request to use the buildName API, sent using the external key of tenant1 using package1, which
does not have access to any of the service's APIs. The response should be an error stating that the user is not allowed to access the service API.
Note |
---|
Make sure the controller is running. Make sure oAuth is running. Make sure you have a valid access token by logging in to oAuth. Use your valid access token in the curl request below. |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4ea5db4c70b6168aeede6a8a56cb4624efdb6cb2cf3c7b88cbc1f5d97080a44f18083fa195e20dcc0b42496ae268ea91c657dd9b252b72de14c862e64f8522a9dbdaa1ce0f48ba2d5ed5eff49b47d0f728bddb2080c8cbc7bde3771116192b51" "http://127.0.0.1:4000/example03/buildName?lastName=Smith&access_token=valid_access_token" |
The key sent with the request is that generated for tenant1 using application1.
The response to the request is shown below
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": false,"errors": {"codes": [154],"details": [{"code": 154,"message": "Access denied: The service is not available in your current package."}]}} |
buildName using application2: Tenant1, package1, overriden package
Next, the same API is requested. However, this time, the external key generated for the second application is used.
The tables above clearly show that the second application (Tenant1, package1, overridden package), has access
to all of the APIs of the service. Therefore, a correct request, using the key of this application should allow access to the API,
and generate the corresponding answer.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4ea5db4c70b6168aeede6a8a56cb4624efdb6cb2cf3c7b88cbc1f5d97080a44f18083fa195e20dcc0b42496ae268ea91c657dd9b252b72de14c862e64f8522a9dbdaa1ce0f48ba2d5ed5eff49b47d0f728bddb2080c8cbc7bde3771116192b51" "http://127.0.0.1:4000/example03/buildName?lastName=Smith" |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": true,"data": {"tenantName": "Client One","fullName": "John Smith"}} |
Clearly, the response generated proves that the second application has access to the API, and the response came back with a positive result to the tenant's query.
More importantly, the response containts the name of the tenant that requested the query.
buildName using application3: Tenant2, package2
The same API is going to be called again. However, the external key of the third application (tenant2, package2) is used.
This application has access to all of the APIs of the service.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/buildName?lastName=Thomas" -H "key:2423205b6ccd825aaa3dbf7f248f807996c1f39f4e128801107a10ea55eac9686f23b883b778b1763876fe47f7cc651fea232f7aa9dae3dfd1978d4948a3f26b948ebc1b71a9d6cacf08852312866d757b22392d8d3c0e28ee47edb0e7478157" |
As expected, the response below indicates a positive response, with a correct answer for the user's query.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": true,"data": {"tenantName": "Client Two","fullName": "John Thomas"}} |
testGet using application3: Tenant2, package2
Using the third application (tenant2, package2), a request for the second API (testGet) of the service is going to be generated. Since this application has access
to all of the APIs, the application should be able to receive a legitimate response with the correct data for the query:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/testGet?lastName=Smith&firstName=John" -H "key:2423205b6ccd825aaa3dbf7f248f807996c1f39f4e128801107a10ea55eac9686f23b883b778b1763876fe47f7cc651fea232f7aa9dae3dfd1978d4948a3f26b948ebc1b71a9d6cacf08852312866d757b22392d8d3c0e28ee47edb0e7478157" |
The response below contains the answer to the user's query.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": true,"data": {"firstName": "John","lastName": "Smith"}} |
buildName using application4: Tenant3, package3
Application4 gives tenant3 access to buildName API only. In order to test the validity of this statement, the next request uses API buildName with the external key of application4.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:7bc1e66d003a3b2acfce1557cbda7320ec45057be0505fd7e9dec19e9fe74c194b109a48568f53449c1cc607a3cb23d70de86831a2ac4b87f1c0c5d57d19702a74ac22a64531185af11f75967f9ba54cb930149ed8a1384f924be9baa4ed5b0b" "http://127.0.0.1:4000/example03/buildName?lastName=Smith" |
The response below indicates a valid answer.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": true,"data": {"tenantName": "Client Three","fullName": "John Smith"}} |
testGet using application4: Tenant3, package3
Application4 however, does not have access to testGet. Therefore, requesting this API with the corresponding tenant key of the application 4 should result
in an error:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:7bc1e66d003a3b2acfce1557cbda7320ec45057be0505fd7e9dec19e9fe74c194b109a48568f53449c1cc607a3cb23d70de86831a2ac4b87f1c0c5d57d19702a74ac22a64531185af11f75967f9ba54cb930149ed8a1384f924be9baa4ed5b0b" "http://127.0.0.1:4000/example03/testGet?lastName=Smith&firstName=Jack"
|
The response below validates that this application does not have access to the testGet API
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": false,"errors": {"codes":[159],"details":[{"code":159,"message":"System api access is restricted. api is not in provision."}]}} |
If we look at the terminal that is running the service "controller", we will see a more in-depth error message:
Code Block | ||
---|---|---|
| ||
(/opt/soajs/node_modules/soajs/servers/controller.js:415 in logErrors): System api access is restricted. api is not in provision. |
In conclusion, multitenancy is a powerful approach that allows the sharing of the resources while ensuring the integrity and security of each tenants resources.
The examples above elaborate how SOAJS implements this concept, allowing numerous tenants to use the same service.
Our documentation provides a detailed explanation for the concepts of multitenancy and productization.
User Level Access Control
The examples above clearly exploit multitenancy using SOAJS, on the tenant level. Indeed, SOAJS permits several tenants to share the same resources (i.e., application, service, etc..).
The ACLs provide permissions for each tenant, thus restricting each tenant's access to what is included in the permissions list.
Interestingly, SOAJS does not enforce access control on the the tenant level only. The framework goes one step further and enforces is on the users of the same tenant.
Consider the following example of a company, composed of two departments: The IT department, and the financial department. The company represents the tenant, and each department
represents a user of that tenant. The IT department should only have access to the IT resources. It must not have access to the resources of the financial department.
The same thing applies for the financial department as well. In this regard, multitenancy on the user level is also supported by SOAJS. What follows is a set of examples that highlight the user level access control.
...
The above table shows three users. Each user has the ability to override the permissions their tenant, and its attributed package.
The examples that follow aim to present how a user can override the ACL permissions of the tenant it belongs to AND/OR the package that the tenant is using.
In addition to that, the examples will show that the user also has the ability to change these configurations, which, in this case, is "tenant name".
User1 Tests
OAUTH Login
Before using the service APIs, a user must be authenticated to the service. Each of the three users has a password. The first step would be to login to OAUTH with a user, and receiving an access token. This access token must be attached to each request.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/oauth/authorization" |
The key in the request above is the tenant key.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":"Basic MTBkMmNiNWZjMDRjZTUxZTA2MDAwMDAxOnNoaGggdGhpcyBpcyBhIHNlY3JldA=="} |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X POST -H "Authorization:Basic MTBkMmNiNWZjMDRjZTUxZTA2MDAwMDAxOnNoaGggdGhpcyBpcyBhIHNlY3JldA==" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/oauth/token" -d "username=user1&password=123456&grant_type=password" |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"token_type":"bearer","access_token":"a188a7fcb411a05159aaf4c97e7321eb77fb0f66","expires_in":7200,"refresh_token":"9e67bd8055e953240eaf91daabe7ecdc206f941b"} |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key: 4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/urac/account/getUser?username=user1"
|
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":{"_id":"54ee1a511856706c23639308","username":"user1","firstName":"user","lastName":"one","email":"user1@domain.com","ts":1480679707835,"status":"active","profile":{},"groups":["gold"],"tenant":{"id":"54ee2150b7a669fc22b7f6b9","code":"TNT1"},"config":{},"groupsConfig":[]},"soajsauth":"Basic c29hanM6QzAzd1ZqdVMtT1ZVTjNCcFZzd2xoQXNKMDdnOG9KNzRqak8="} |
The response above contains the information of user1, followed by the soajs authentication key of that user.
This authentication must be attached to every request generated by user1.
buildName API with user1
The next request tries to use the "buildName" API with the tenant key, and the authentication key of user1. The table above clearly states that this user does not have access to this API. Therefore, the corresponding response must generate an error, stating that the user is forbidden from using the "buidName" API.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/buildName?lastName=Smith&access_token=a188a7fcb411a05159aaf4c97e7321eb77fb0f66" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" |
The response generated states that user1 is forbidden from using the "buildName" application
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":false,"errors":{"codes":[154],"details":[{"code":154,"message":"Access denied: The service is not available in your current package."}]}} |
If we look at the terminal that is running the service "controller", we will see a more in-depth error message:
Code Block | ||
---|---|---|
| ||
(/opt/soajs/node_modules/soajs/servers/controller.js:415 in logErrors): Access denied: The service is not available in your current package. |
User2 Tests
OAUTH Login
Similar to user1, the example below accesses the OAUTH service with the user2 account, in order to receive an access token.
Before using the service APIs, a user must be authenticated to the service. Each of the three users has a password. The first step would be to login to OAUTH with a user, and receiving an access token. This access token must be attached to each request.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/oauth/authorization" |
The key in the request above is the tenant key.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":"Basic MTBkMmNiNWZjMDRjZTUxZTA2MDAwMDAxOnNoaGggdGhpcyBpcyBhIHNlY3JldA=="} |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X POST -H "Authorization:Basic MTBkMmNiNWZjMDRjZTUxZTA2MDAwMDAxOnNoaGggdGhpcyBpcyBhIHNlY3JldA==" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/oauth/token" -d "username=user2&password=123456&grant_type=password" |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"token_type":"bearer","access_token":"a188a7fcb411a05159aaf4c97e7321eb77fb0f66","expires_in":7200,"refresh_token":"9e67bd8055e953240eaf91daabe7ecdc206f941b"} |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key: 4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/urac/account/getUser?username=user2"
|
The service replies with the corresponding authentication key
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":{"_id":"54ee46e7a8643c4d10a61ba3","username":"user2","firstName":"user","lastName":"two","email":"user2@domain.com","ts":1500998208596,"status":"active","profile":{},"groups":["silver"],"tenant":{"id":"54ee2150b7a669fc22b7f6b9","code":"TNT1"},"config":{"packages":{"PROD1_PCK1":{"acl":{"urac":{},"example03":{},"example04":{}}}},"keys":{"41eb3256ce660a891205d0a0eca19421":{"config":{"example03":{"tenantName":"Tenant name specific to user two"},"example04":{"tenantName":"Tenant name specific to user two"}}},"19c03e42c750467c3f8481fbe26f2fef":{}}}},"soajsauth":"Basic c29hanM6QzAyMmd5TTU0enplWW1oTHdXMjV5ZGdGb3B1VUthSWZ3b0s="} |
buildName API with user2
The next request tries to use the "buildName" API with the tenant key, and the authentication key of user2. The table above clearly states that this user does have access to this API. Therefore, the corresponding response must generate a response containing the appropriate answer for the user's query.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/buildName?lastName=Smith&access_token=a188a7fcb411a05159aaf4c97e7321eb77fb0f66" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" |
The response below shows that user2 was able to access the "buildName" API since the user overrides the ACL of package1. Moreover, we notice that the tenant name was changed.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":{"tenantName":"Client One","fullName":"John Smith"},"soajsauth":"Basic c29hanM6QzAxWWNjUzJaSEpYenhBd0J5MDAzZG5RZ1BOdXFFd0d4UmM="} |
testGet API with user2
Next, the request aims to use the "testGet" API with user2, that has access to the API, as shown in the table above.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/testGet?firstName=John&lastName=Smith&access_token=a188a7fcb411a05159aaf4c97e7321eb77fb0f66" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" |
The corresponding response prove the above statement. User2 overrode the package ACL and obtained full access to the service's APIs
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":{"firstName":"John","lastName":"Smith"},"soajsauth":"Basic c29hanM6QzAyWWNjQXdaSDBYSnhTMkJ5ejAzZG5RZ1BOdXFFd0d4UmM="} |
User3 Tests
OAUTH Login
The following request logs in to OAUTH using user3.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" "http://127.0.0.1:4000/oauth/authorization" |
The key in the request above is the tenant key.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":"Basic MTBkMmNiNWZjMDRjZTUxZTA2MDAwMDAxOnNoaGggdGhpcyBpcyBhIHNlY3JldA=="} |
...
language | bash |
---|---|
title | Get the access token using the authorization key |
linenumbers | true |
...
Introduction
...
In the Basic Service example, we learned to perform a heartbeat check on a service, in order to monitor its health.
Moreover, sample tests to expose the basic functionalities of a SOAJS service, and those of the IMFV.
In the oAuth Security example, one of the APIs from the Basic Service example will be secured with oAuth.
The example allowed the user to explain the integration of the oAuth service with a SOAJS service.
This example explores SOAJS' ability of multitenancy.
Multitenancy allows a collection of tenants/users to share the same set of resources (i.e., a database, service, etc) by allowing each tenant to access only the allowed portion of that resource, and prohibiting them from accessing resources of other tenants.
SOAJS allows different tenants to use the same service, each using their own settings, ACL and configurations.
This example also introduces the User Registration & Access Control (URAC) service, which holds records of all the tenants and its corresponding users.
Moreover, the example teaches how to benefit from multitenancy, and how to configure ACLs, in addition to securing the APIs using tenant keys.
Code Walkthrough
...
This page shows you how to interact with the example03 & URAC services after you install them and run them. It also demonstrates how SOAJS implements multitenancy.
The code walkthrough is located in a sub page and explained in depth. Click here to read the explanation.
Service Exploration
...
To turn on URAC in a development environment you just need to start the environment as follow
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
sudo soajs services start --env=example |
Info | ||
---|---|---|
| ||
To verify if oauth is running you need to login to soajs console and
|
Code Block | ||||
---|---|---|---|---|
| ||||
# go to examples/example03 and start the service
cd soajs.examples/example03/
# start the soajs example environment
sudo soajs services start --env=example
# export necessary environment variables to create local awareness
export SOAJS_ENV=EXAMPLE
export SOAJS_SRVPORT=4023
export SOAJS_DEPLOY_MANUAL=1
export SOAJS_REGISTRY_API=127.0.0.1:21000
# start service
node . |
The service is now running and listens on port 4023. Therefore, its maintenance port is 5023.
Next, a heartbeat request is sent to check the health of the service.
Code Block | ||||
---|---|---|---|---|
| ||||
curl -X GET "http://127.0.0.1:5023/heartbeat" |
A response similar to the one below indicates a healthy functioning of the service.
Code Block | ||||
---|---|---|---|---|
| ||||
{"result":true,"ts":1425372737466,"service": {"service":"example03","type":"rest","route":"/heartbeat"}} |
Tenant Level Access Control
...
Using the Service APIs
As mentioned previously, this example is multitenant. Therefore, this tutorial simulates several tenants, which will be used across the examples that follow.
Package Name | Access to Service | Access Type |
---|---|---|
Example | NO | N/A |
Example2 | YES | FULL |
Example3 | YES | "buildName" |
The table above lists three packages. each package represents a list of permissions.
Example does not have access to the service.
Example2 has full access to the service.
Example3 has access to only the buildName API of the service.
What we also did is we create an example tenant and we gave added 3 applications one per package under this tenant where each application has its own API key and
Tenant Name | Application Name | Access to Service | Access Type |
---|---|---|---|
Tenant example | EXAMP_BASIC | NO | NA |
Tenant example | EXAMP_3ZE08 | YES | FULL |
Tenant example | EXAMP_4H6CQ | YES | "buildName" |
An application is defined as the combination of a tenant and a package assigned to that tenant.
buildName using EXAMP_BASIC
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4ea5db4c70b6168aeede6a8a56cb4624efdb6cb2cf3c7b88cbc1f5d97080a44f18083fa195e20dcc0b42496ae268ea91c657dd9b252b72de14c862e64f8522a9dbdaa1ce0f48ba2d5ed5eff49b47d0f728bddb2080c8cbc7bde3771116192b51" "http://127.0.0.1:400020000/oauth/token" -d "username=user3&password=654321&grant_type=password"example03/buildName?lastName=Smith&access_token=valid_access_token" |
The key sent with the request is that generated for EXAMP_BASIC
The response to the request is shown below
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"token_type"result": false,"errors": {"bearercodes","access_token":"06ff4ec503f9ecd91af42cf8d324e65b5c780645","expires_in":7200,"refresh_token":"5479fa9d6fd049111c490229e7713e77e794ee41"}: [154],"details": [{"code": 154,"message": "Access denied: The service is not available in your current package."}]}} |
buildName using EXAMP_3ZE08
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d24ea5db4c70b6168aeede6a8a56cb46246ca38b1b4f801f090d5821bd76b339e34b8ddb9ac2cb7ffee220cf3e463ac9cdf3902e91720c8f56684d7d88287affc0092eeb37648e7bde4f565f509b1b384127022bc2c1c1581f4ba50e28564d1c5c" "http://127.0.0.1:400020000/uracexample03/account/getUserbuildName?usernamelastName=user3Smith" |
The response below contains the authentication key of user3.key sent with the request is that generated for EXAMP_3ZE08
Code Block | ||||||
---|---|---|---|---|---|---|
Code Block | ||||||
| ||||||
| ||||||
{"result":true,"data":{"_id":"54ee1bf91856706c2363930a","username":"user3","firstName":"user","lastName":"three","email":"user3@domain.com","ts":1500998208597,"status":"active","profile":{},"groups":["gold","silver","customer"],"tenant":{"id":"54ee2150b7a669fc22b7f6b9","code":"TNT1"},"config":{"packages":{"PROD1_PCK1":{"acl":{"urac":{},"example03":{},"example04":{}}}},"keys":{"19c03e42c750467c3f8481fbe26f2fef":{"config":{"example03":{"tenantName":"Tenant name specific to user three"},"example04":{"tenantName":"Tenant name specific to user three"}},"acl":{"urac":{},"example04":{},"example03":{"apisPermission":"restricted","apis":{"/buildName":{}}}}}}}},"soajsauth":"Basic c29hanM6QzAxNl9pUFltUUtkdnFsck5ZSmFoMG1mMmVEZzZ0SXkxaTU="} |
buildName API with user3
User3 overrides the tenant, and has access to the "buildName" API. as can be seen in the response below.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/buildName?lastName=Smith&access_token=06ff4ec503f9ecd91af42cf8d324e65b5c780645" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" |
User3 was also able to change the name of the tenant.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result":true,"data":{"tenantName":"Tenant name specific to user three","fullName":"John Smith"},"soajsauth":"Basic c29hanM6QzAxaV9KRk5ZYU5VbHZCcC1QOEVoWHFKVjIxdzNyNFlVWF8="} |
testGet API with user3
However, the ACL corresponding to this user prohibits it from using the "testGet" API.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/testGet?lastName=Smith&access_token=06ff4ec503f9ecd91af42cf8d324e65b5c780645" -H "key:4232477ed993d167ec13ccf8836c29c400fef7eb3d175b1f2192b82ebef6fb2d129cdd25fe23c04f856157184e11f7f57b65759191908cb5c664df136c7ad16a56a5917fdeabfc97c92a1f199e457e31f2450a810769ff1b29269bcb3f01e3d2" |
The response proves that user3 does not have access to the "testGet" API.
If we look at the terminal that is running the service "controller", we will see a more in-depth error message:
| ||
{"result": true,"data": {"tenantName": "Client One","fullName": "John Smith"}} |
Clearly, the response generated proves that the second application has access to the API, and the response came back with a positive result to the tenant's query.
More importantly, the response containts the name of the tenant that requested the query.
buildName using EXAMP_4H6CQ
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/buildName?lastName=Thomas" -H "key:4ea5db4c70b6168aeede6a8a56cb4624079ff72a87d5174f5d880d546f326077dd82b8131322c2a5dbc02edec9d5ad7bfbfcf3730c2205850ffe7644e259ad2ee20280d25a1cfecdb7a62992920d2155cb30edffb6e53d49c528cc2e1ae54a6e" |
As expected, the response below indicates a positive response, with a correct answer for the user's query.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": true,"data": {"tenantName": "Client Two","fullName": "John Thomas"}} |
testGet using EXAMP_3ZE08
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET "http://127.0.0.1:4000/example03/testGet?lastName=Smith&firstName=John" -H "key:4ea5db4c70b6168aeede6a8a56cb46246ca38b1b4f801f090d5821bd76b339e34b8ddb9ac2cb7ffee220cf3e463ac9cdf3902e91720c8f56684d7d88287affc0092eeb37648e7bde4f565f509b1b384127022bc2c1c1581f4ba50e28564d1c5c" |
The response below contains the answer to the user's query.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": true,"data": {"firstName": "John","lastName": "Smith"}} |
buildName using EXAMP_4H6CQ
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
curl -X GET -H "key:4ea5db4c70b6168aeede6a8a56cb4624079ff72a87d5174f5d880d546f326077dd82b8131322c2a5dbc02edec9d5ad7bfbfcf3730c2205850ffe7644e259ad2ee20280d25a1cfecdb7a62992920d2155cb30edffb6e53d49c528cc2e1ae54a6e" "http://127.0.0.1:4000/example03/buildName?lastName=Smith" |
The response to the request is shown below
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
{"result": false,"errors": {"codes":[159],"details":[{"code":159,"message":"System api access is restricted. api is not in provision."}]}} |
In conclusion, multitenancy is a powerful approach that allows the sharing of the resources while ensuring the integrity and security of each tenants resources.
The examples above elaborate how SOAJS implements this concept, allowing numerous tenants to use the same service.
Our documentation provides a detailed explanation for the concepts of multitenancy and productization.
User Level Access Control
...
The examples above clearly exploit multitenancy using SOAJS, on the tenant level. Indeed, SOAJS permits several tenants to share the same resources (i.e., application, service, etc..).
The ACLs provide permissions for each tenant, thus restricting each tenant's access to what is included in the permissions list.
Interestingly, SOAJS does not enforce access control on the the tenant level only. The framework goes one step further and enforces is on the users of the same tenant.
Consider the following example of a company, composed of two departments: The IT department, and the financial department. The company represents the tenant, and each department
represents a user of that tenant. The IT department should only have access to the IT resources. It must not have access to the resources of the financial department.
The same thing applies for the financial department as well. In this regard, multitenancy on the user level is also supported by SOAJS.
Conclusion
...
In conclusion, multitenancy, productization and urac are efficient concepts that allow the tenants and users to share the available resources, in an optimized way, while respecting the privacy of each tenant/user's data,
...
- The ACL is explained in depth in the Access Levels section.
- Products and packages are explained in depth in the Productization section.
- Tenants, and applications are explained in the Multitenancy section.
- Finally users, groups and ACL overriding are explain in the URAC section.