Implemention of Support for Mutiple User Store Configuration at Run Time (A touch on the Beauty of WSO2 Carbon Architecture)
As I have shared in the previous post, WSO2 IS 4.5.0 version is released with added support for dynamic configuration of multiple user stores. While implementing this piece of component, I could touch some beautiful areas of WSO2 Carbon architecture, which is known to be inherently dynamic and flexible. With this post I am to list those characteristics of Carbon platform that came handy in this implementation.The content of this post is,
- How dynamic User Store Configuration happens
- Carbon characteristics that facilitated rapid development
How dynamic User Store Configuration happens
Following figure highlights the flow of a new user store configuration.
- The super admin or tenant admin can add user stores through the UI, to own domain. We have allowed dynamic configurations only for secondary user stores and 'Primary' user store is not configurable at run time. This was because it is available for all tenants and allowing changes to it's configuration at run time can guide to instability of system. With this limitation we have been able to keep the design simple and avoid some crucial run time complexities that may have occurred. (eg: Primary user store keeps super admin data used to sign in and if super admin himself changes the configuration of Primary user store, the status of the system in between, is not stable.) So the Primary is treated as a static property in the implementation that is a basic requirement to run the system properly.
- These secondary user stores can be added in two ways, via the UI or directly dropping it in the corresponding location as shown in the figure. Anyway the recommended way is to use from the above is, using the UI, as it will mostly avoid us from putting wrong configuration files and guide us to do it correct. If we are providing it writing xml manually following factors needs to fulfilled.
- The domain name should match the file name (wso2.com --> wso2_com.xml)
- All mandatory fields required by the User Store Manager implementation should be provided as properties. (UI it self has guidance for this or we can refer the documentation of WSO2 IS.)
- If the configuration files are added though the UI, they will be saved in the locations given, according to the tenant. Now on, the deployer (an Axis2 custom deployers) will take care of it and update everything accordingly. The deployer is polling the 'userstores' folder to detect any changes and as soon as it is aware of an event, required update is called. The deployer will detect the changes with an upper limit of 15 seconds which means there will be a little delay to see the updates in the UI. Refreshing the page after this moment is wait will make the changes visible in the UI.
- According to the done modification(add/delete/enable/disable/edit), the deployer will identify the events(Using the details of the modified file and whether it's deploy or undeploy). Then it lets the deployement manager to update the User Store Manager chain according the modification. If it's an addition the new user store manager will be added at the end of the chain. If it's a delete, the chain will be broken at the point and tail part will be added to head. Other modification will be effective in the chain as it is, without any effect to the order.
- So when a user comes and submit his/her credentials the authenticator goes through the chain and check for a matching user in own chain of tenant. If it's found in the user chain with matching credentials then the assigned roles are checked for authorization, which allows users to perform permitted actions.
Carbon characteristics that facilitated rapid development
- Clear separation of Front end/Back end (SOA interfaces)
With this clear separation it was easy to re-use what has been already implemented that are also useful in this implementation. Also regarding this component, could see a clear separation of UI and back end that simplified the design. UI used the stub classes to talk to the backend component which talked to other back-end components and delivered the output to UI. So if we want to just consume the API at sometime, it is already available
- Out the box support for multi-tenancy
After writing the component for Super tenant there was no more significant effort to make it work in a multi-tenanted environment. Once it runs fine for super tenant, it is running fine in multi-tenant environment too. So this can be available be run anywhere, cloud or on-premise without a single modification.
How will this work in a cluster is our next question. So all these needed to be replicated in all the nodes. Then there is WSO2 Carbon feature that can be used to synchronize the nodes, 'Deployment Synchronizer' which has options to be based on SVN or registry. In the this implementation we used SVN based deployment synchronizer and target was achieved. Not a single line of code needed for this.
WSO2 Carbon is also called 'Eclipse for Servers' with it's high extendibility with the OSGI run time. This comes very useful regarding this component that after sometime if we wanted to add our own custom user store manager implementation like for Apache Cassandra it is also possible without any hassle. We just have to implement the provided UserStoreManager interface or extend the AbstractUserStoreManager class, write the customized code and pack it into a bundle (sample). Once this is dropped into CARBON_HOME/repository/components/dropins the run time will detect it at start-up and even show it in the UI for configurations.
Also when it was needed to detect the changes of configuration files, there was this custom deployer support inherited from Axis2 that made the life easier. We just had to extend the provided implementation pointing to the folder path to poll, write what we want do at new file addition(deploy)/file deletion(undeploy) and it was doing the job.
Finally, it was so nice to see that all these components inter-operate with each other to satisfy the requirement in the exact expected way.