Building Custom Multi Tenant and Multi Factor Authentication and Authorization Platform

Here is my approach on how to build a custom Authentication and Authorization platform

before i go into the approach and solution, a generic definition of authentication and authorization. suppose there is a floor with 10 rooms - 3 rooms for meetings, 3 rooms for training, 2 rooms for finance(say cash is stored here), 2 rooms for IT(say hardware is stored here). if the user can successfully go through security checks at the floor(like card access, thumb, face recognition or voice), its called authentication. lets say he clears the security checks at the floor level, what are the rooms can he enter? this is governed by roles and access. a normal person can enter into meeting, training rooms but not into finance and IT rooms. whereas a finance analyst might have access to enter the finance room but not have access to cash box which only a finance admin can. finance admin can enter into all the rooms and have access to cash box but will not have access to IT room. this constitutes authorization as roles and privileges govern this

1) Tech Stack

  • Netflix Zuul
  • Netflix Eureka
  • Netflix Ribbon
  • Hazelcast
  • Spring Boot
  • MySQL
  • Apache NiFi

2) Multi Tenant and Multi Factor Authentication Platform

lets say you have the following auth modes applicable for all the tenants as a SaaS offering. tenants can opt for one or more of the following auth modes(we can also have other modes like facial recognition, thumb etc but confining to the following)

  1. verify user name and password
  2. verify OTP via email
  3. verify OTP via sms
  4. verify verification code from google
  5. verify security questions

during tenant onboarding, each tenant can say what are the modes they would want to have and in what order. say for example one tenant might say, they would want to have user name and password first and email OTP second whereas another tenant might say, they would want to have user name and password first, google verification code second and verify security question as third mode. for a UI based authentication platform, we would configure second level domain and sub domain(for various environments) per tenant or a generic domain applicable for all the tenants

the UI will get the order of authentication modes for a given domain and will render the pages in that order

we will delay constructing the authentication data till the last mode is arrived at. for example, if a tenant wants user name and password, OTP email, OTP SMS authentication in this order, we will verify user name and password credentials in "verify user name and password API" Email OTP in "verify OTP via email API", SMS OTP in "verify OTP via sms API" and after this , we will do actual authentication in verify OTP via sms API since OTP SMS is the last mode preferred.


??????? ?????????? ????????????? ?????????????,? ??????? ????????????? ??????????????????? ??????????????????????????????????????????? ????????????

we will be using Hazelcast for storing data

  1. use the already initialized tokenMap. the tokenMap will be initialized during server startup with TTL of the Hazelcast map as 30 minutes(new entry will have TTL as 30 minutes)
  2. the Hazelcast key with be a SHA512 (email+current timestamp). the reason being, a person can login from n number of browsers and from various systems using the same email id. the value of Hazelcast Map entry will be the user object
  3. this Hazelcast key will have TTL of 30 minutes and will be sent back in the response. in addition to this, another auth token will be generated using Math. Random(8 digit value) . This will change for every request. this will be added as fnVal attribute in the user object
  4. subsequent to this, the client has to pass 2 tokens in the header - inVal(the value of SHA512 (email+current timestamp)) and fnVal(Math. Random(8 digit value))
  5. Authorization data for that user will be passed as well(please look at ??????????????????? ???????????????? ??????????????????????????????????????? section)

????????????????????????????????????? ???????????????? ?????????? ???????????????? ????????????? ??????? ??????????????????? ?????????? ???????????????? ?????????????????????? ?????????? ????????????? ??????? ?????????? ???????????????????????????

  1. inVal and fnVal will be passed in the header. verify inVal by doing tokenMap.containsKey(inVal) , then get the value of tokenMap.get(inVal) and compare fnVal with tokenMap.get(inVal).getfnVal. if both the tokens does not match, then auth is denied, if it matches, then generate new value for fnVal by doing Math. Random(8 digit value), set it to fnVal attribute in the user object and send it back in the response

with this, we have 2 tokens for Authentication - one token for 30 minutes and another token for every request

??????????????????? ?????????? ???????????????? ????????????? ??????? ??????????????????? ????????????

  1. logout button is clicked
  2. when browser window is closed(event notification)

the above 2 points will remove the key(inVal) from the hazelcast map and successive calls passing the same key(inVal) will return access denied.

in addition to the above, the key(inVal) will be automatically removed from the Hazelcast map after 30 minutes as the expiration is set as 30 minutes for the tokenMap object

????????????? ??????? ?????????????????????? ?????????????????????????????????? ?????????? ?????????????????????????????????? ???????????????????????

yes, it addresses distributed problem as Hazelcast is a very good solution for storing and accessing data in a distributed environment. the keys added to hazelcast map is replicated synchronously across the cluster guaranteeing strong consistency. for a get, any node can receive the request but only the primary node will return the data

yes, Hazelcast addresses concurrency problem. however, if you want to have distributed lock across the cluster, then we can leverage Hazelcast lock by doing the following

HazelcastInstance hazelcastInstance = Hazelcast.newHazelcastInstance() (can be configured to add to the cluster by configuring cluster settings)

Lock lock = hazelcastInstance.getLock( "myLock" );

try {

// insert into Hazelcast map

} finally {

lock.unlock();

}

the above code will acquired distributed lock on the Auth cluster for the critical region that will be used to add auth data

so for authentication, there will be 2 tokens that need to be passed in the header - inVal and fnVal for every request

3) Authorization Platform

Authorization can happen at screen level and at API level

??????????????????? ???????????????? ???????????????????????????????????????

In the Admin console

  1. The root admin(common for all tenants) can add new screens definitions and remove existing screen definitions. screens applicable to all the tenants can be added by the root admin one by one or by doing a bulk upload. this will eventually be available to all the tenants accessed by respective tenant admin
  2. Tenant level admin can create/edit roles for their tenant. Tenant admin would be onboarded after tenant onboarding is done
  3. Tenant admin can do screen to role mapping. for example, through the UI he can perform - role finance analyst can view screen payroll but not accounts receivable screen. role finance admin can have access to both the screens
  4. user is mapped to a role. ?????? ?????????? ????????????? ?????????????,? ??????? ????????????? ??????????????????? ??????????????????????????????????????????? ???????????? section, authorization data will be constructed and will be returned back to the client. the data will be constructed by doing a join of user, screen, access tables
  5. further to point 4, once authorization data is returned back to the client(UI), depending on the access , hiding/showing of screens , READ/ACCESS of html attributes will be performed thereby handling screen access, html attribute access per user/role. this way, everything related to screen access and html attributes access are configured via UI and nothing is hard coded

?????????? ???????????????? ???????????????????????????????????????

  1. there will be a default root token. this default root token will be used to onboard a service. a service will be onboarded by passing necessary data like service id, name, description as well as default root token. this will eventually generate service token
  2. given a root token and service id we will get service details including service token
  3. from the combination of root token and service token, we can create multiple roles and each role will generate a token. this shall be called service_role_token. API level access will be provisioned in terms of what roles can access what API's
  4. Each service will register with Eureka. for example if there are 2 services, service A and service B both will register with Eureka. if service A wants to interact with service B, it will discover with Eureka. but before that it has to register with Service B. how it will do is - it will pass the root token and service id of B(destination), service id of A(source) the end point of B it wants to access. in return it will get service_role_token for that end point. this needs to be passed in the header when service A wants to call a particular end point of Service B
  5. If UI interacts with a service, same thing like the previous step has to be done. in this case, since UI is not a service, it has to register as a service(UI like service) which will assign a service id for that UI app and this service id needs to be passed as source service id to get service_role_token of the downstream service
  6. the necessary tokens can be rotated once a day by using NiFi

so for authorization, there will be 1 token that need to be passed in the header - service_role_token for every request

4) Tables Involved

I am highlighting the core tables that will be involved

  1. tenant - has tenant data and its configurations. the tenant configuration can have authentication modes stored in json format. each tenant will have tenant token that will be SHA512 (current timestamp+Math.Random(8 digit value))
  2. role - roles and its definition for each of the tenant
  3. user - has user data. it will have tenant_id and role_id as well. it will also have authentication data
  4. screen - list of predefined screens
  5. screen_html_attributes - what are the html elements that will have access restrictions against, for example, screen Create Accounts Payable might have button called Create. so there will be one entry here that will have id:AP1, name:Create, description: Create Accounts Payable. you will set access against this
  6. access - what are the screens a particular user can access and what are the html buttons that he can see or perform. it will have user_id, screen_id, screen_access(yes/no), html_attributes_access(for example id:AP1, name:Create, description: Create Accounts Payable, access:READ/WRITE)
  7. service - has data like service name, service id, service description, service_token
  8. service_role - has data like service_id, role name, role id, role description, role_token
  9. service_role_api - has data like service_role_id, url. basically what are the end points that a particular service role can access
  10. service_service_api - has data like source_service_id, destination_service_id, destination_service_role_token

Shankaran E R

Principal Java Full Stack Engineer

7 个月

Good one ??

Manohar Veera

Product & Analytics @ Tekion | CRM, B2B SaaS, Finance

8 个月

Yet again you are keeping things simple. Good Bhargav Maddikera Why do we need to use 2 token for auth?

Manish Sharma

Sr. Engineering Manager | Mobile Architect | Digital Transformation Leader | Problem Solver | Proud Father | Driving Innovation in Software Development

8 个月

Insightful Bhargav Maddikera

要查看或添加评论,请登录

Bhargav Maddikera的更多文章

社区洞察

其他会员也浏览了