Thursday, May 12, 2016

Multi-tenancy

Multi-tenancy and Security.  In reviewing the needs of the learning app I am developing with JHipster, I stumbled on a somewhat large-ish disconnect in terms of security.  JHipster integrates Spring Secirity which offers role based authorization (authz) and a variety of social sign on options.  Its pretty complete right out of the box (that JHipster generates). This is all good, but my app is being built as a multi-tenant app.  When a user logs in, I not only need to make sure they have the right roles, but I also have to determine their association with a "tenant".

Multi-tenancy Model.  For my application I have chose a multi-tenancy model where the application and database are shared by ALL tenants.  It will be up to the code to ensure that I don't co-mingle a particular tenant's data.  In my example from prior articles, I used an Employee - Department set of entities to discuss relationships.  Imagine now that I need to restrict users of my learning app to a single company.  The Company entity is now the driving entity as to what makes up a tenant.  All other non-system entities that are part of the app (Employee, Department) have to relate to the Company such that when a user logs in, they only see the data for their company.  Found a cool tool to do diagramming:



In reviewing how JHipster manages authorizations, I found that the code generated will lock down the back end access at the Rest api level by adding authorization checks at the Rest url level within the SecurityConfiguration class.  I really like this approach.  It frees the remainder of the app from checking roles at each step.  I will still likely include spring security annotations @Pre and @Post Authorize in my high level service methods on my custom services where appropriate.  I went ahead and set ALL the generated Rest apis to ROLE_ADMIN to lock them down.  I really want to dig into the Spring Security expression based access control.  It looks to have some pretty compelling features that might come in handy when locking down data for multi-tenancy.

Data vs. Role Security.  In addition to the Role based auths however, I still have to ensure that my Rest api does not allow data from one tenant (Company) be seen by the user associated with another tenant.   I went ahead and implemented my own version of UserDetails by extending User and populated it in my custom UserDetailsService.  I included the notion of the Tenant in my UserDetails class such that when a user logs in and Spring calls the UserDetailsService, I load the user's default tenant (company) from the database into the UserDetails class.  For now I will rely on passing the UserDetails via parameters to the Service and Repository layers to restrict data for a given user.  I may refactor to use a ThreadLocal but there are many documented disadvantages to this.

JHipster and Groovy.  As I begin to lay in new code, I wanted to start using Groovy.  My plan is to leave the generated Java code AS Java (rather than convert to Groovy), but  any new classes will be Groovy.  One very minor snag is that the Groovy compiler wants all sources, Java and Groovy to be in src/main/groovy.  Added these two lines to the Gradle build to fix:

sourceSets.main.java.srcDirs = []
sourceSets.main.groovy.srcDirs += ["src/main/java"]
Put these lines in, wrote some simple Groovy classes and simple Spock tests, and the compile works fine, both from Gradle and from Intellij Idea.

No comments: