Update 5/12/2016: Building multi-tenancy with Spring Boot? Learn how to integrate OAuth with our OZorkAuth game!
Java introduced the idea of “Write Once, Run Anywhere”. In this post, you will learn how to “Write Once, Run Any Tenant”. With a single application and some configuration in Stormpath’s Admin Console, your application will be able to support multiple Organizations of users. This is great for SaaS applications who need to securely partition their Customer organizations; each Organization will have no knowledge of or access to the others.
What Is Multi-Tenancy?
Imagine a self-storage company. There’s a large building. Inside the building, there are multiple storage units, each with a lock on the door that only the renter of that unit has access to.
One of the reasons self-storage works so well is that it is easy to repeat. Each storage unit is basically the same as the others. Adding a new tenant does not require a whole new large building. It simply requires that a storage unit be allocated to that tenant. It also ensures that each tenant has a protected storage unit, unique to them and that only they can access.
It’s the same idea for a multi-tenant application. You have one application that can support distinct collections of users. Setting up a new tenant is reduced to a little configuration in an admin console. There’s no need to deploy your application to a new server.
A Multi-Tenant Sample for Spring Boot
Building all this multi-tenant infrastructure yourself from scratch is a royal pain, but multi-tenancy is native to and easily configurable in the Stormpath user model. In this post, we’ll show you how to use it in a Spring Boot app.
We’re going to follow along with a made-up company in this post to demonstrate multi-tenancy. It’s called the Imperial Xchange – your one-stop shop for all your evil apparel needs! In this scenario, we want to keep the Sith Lords separate from the Stormtroopers.
The goal is to deploy the Application once, to allow both Sith Lords and Stormtroopers to login to their respective tenants while also ensuring that they can’t login to each other’s tenants. Finally, we will add another Organization into the mix without any code changes or even the need to restart the application.
Getting Ready for A Multi-Tenant User Store
The first step to multi-tenant bliss is to get Stormpath setup. While there are few steps along the way, you’ll see that it’s pretty easy.
There are a number of ways to accomplish authentication in a multi-tenant enabled Application:
- Add a field to the login form for users to type in their Tenant name
- Select Tenant after login
- Automatically set Tenant by subdomain
The most advanced version of this – and the easiest on users – is the subdomain approach. That is the approach we will be configuring in the examples that follow.
For more information on the various approaches, check out our Multi-Tenancy Guide
Create a Stormpath Account
Point your browser over to https://api.stormpath.com and signup for a Stormpath account. Fill out the form, verify your account, create an API key pair and you’re good to go.
For more detailed information on setting up your free Stormpath account, refer to the Product Guide.
Setup the Organizations
Organizations are the key to our subdomain-based configuration. A Stormpath Organization is a type of Account Store. That is, a container for Accounts. The important part here is that you specify an Organization Name Key that matches your subdomain.
In this case, we will use sith
and stormtrooper
Organization names to match the subdomains we setup below.
Follow these steps:
Setup the Organizations
- Browse to your Stormpath Admin Console
- Click the
Organizations
tab at the top of the page - Click the
Create Organization
button
- Enter
Sith
for the Name andsith
for Name Key and click theCreate Organization
button - Repeat steps 2 – 4 using
Stormtrooper
for the Namestormtrooper
for the Name Key
Setup the Directories
Stormpath Directories contain the Accounts that we will use for a particular Tenant.
- Click the
Directories
tab at the top of the page - Click the
Create Directory
button
- Enter
Sith Directory
for the Name and click theCreate Directory
button - Repeat steps 2 – 3 using
Stormtrooper Directory
for the Name
Setup the Accounts
We’re going to create two Accounts – one in each Directory.
First, a Sith Account:
- Click
Accounts
tab at the top of the page - Click the
Create Account
button
- Choose the
Sith Directory
option forAccount Location
- Enter
dvader
forUsername
- Enter
Darth
forFirst Name
- Enter
Vader
forLast Name
- Enter
[email protected]
forEmail
- Enter a password of your choosing for
Password
and re-enter it forConfirm Password
- Click the
Create
button
Next, a Stormtrooper Account:
- Click
Accounts
tab at the top of the page - Click the
Create Account
button
- Choose the
Stormtrooper Directory
option forAccount Location
- Enter
tk421
forUsername
- Enter
TK
forFirst Name
- Enter
421
forLast Name
- Enter
[email protected]
forEmail
- Enter a password of your choosing for
Password
and re-enter it forConfirm Password
- Click the
Create
button
Setup the Application
The Stormpath Application is where we point the Spring Boot application to for authentication and authorization.
Follow these steps to create an Application:
- Click the
Applications
tab at the top of the page - Click the
Create Application
button - Enter
Imperial Xchange
for the Name - Uncheck the
Create new Directory
checkbox (we will associate theOrganizations
we created with the Application below) - Click the
Create
button
Tying it all Together
The last steps in this section are to add the Directories
we’ve created as Account Store Mappings
in the Organizations
and to associate the Organizations
with the Application
Account Store Mappings:
- Click the
Organizations
tab again - Click the
Sith
link - Click the
Account Stores
link - Click the
Add Account Stores
link - On the
Directories
tab, click the checkbox next toSith Directory
- Click the
Create Mappings
button
- Click the
Organizations
tab again - Click the
Stormtrooper
link - Click the
Account Stores
link - Click the
Add Account Stores
link - On the
Directories
tab, click the checkbox next toStormtrooper Directory
- Click the
Create Mappings
button
Application Account Stores:
- Click the
Applications
tab again - Click the
Imperial Xchange
link - Click the
Account Stores
link
- Click the
Add Account Store
button - Choose the
Organizations
tab and select theSith
andStormtrooper
checkboxes
- Click the
Create Mappings
button
Phew! Your Application is now completely setup for multi-tenancy. Hooray!
Configure ID Site
ID Site is Stormpath’s hosted and pre-built user interface screens that take care of the most common authentication workflows, including the login and register functions (among others) of your Application.
We’re using it here as it automatically supports the subdomain approach to multi-tenancy.
For more information on ID Site, check out the product guide here.
When you authenticate to an Application backed by ID Site, you will be automatically redirected to the hosted login page and then redirected back to your Application. For security purposes, you must specify the allowed origin
and redirect
urls.
For the purposes of our example app, we are going to use a locally defined domain: ix.localhost
.
Specifically, we’ll be using sith.ix.localhost
and stormtrooper.ix.localhost
.
ID Site supports the notion of wildcard domains. This means that you don’t have to specify every subdomain you want to support for a given domain. You use the wildcard character *
as you’ll see below.
Follow these steps for configuring ID Site:
- Click the
ID Site
tab at the top of the page - Scroll down to the
Authorized Javascript Origin URLs
section and enterhttp://*.ix.localhost:8080
- Click into the
Authorized Redirect URLs
section and enterhttp://*.ix.localhost:8080/
andhttp://*.ix.localhost:8080/idSiteResult
- Scroll to the bottom of the page and click the
Save
button.
/idSiteResult
is the default callback URI used in Spring Boot applications.
Configure Your Local Environment
Rounding out our configuration journey is setting up your local environment to support the local domains we are using for this example.
On Macs and Linux machines, you edit the /etc/hosts
file. On Windows machines, you edit the %SystemRoot%\System32\drivers\etc\hosts
file. Update the following line:
1 2 |
127.0.0.1 localhost stormtrooper.ix.localhost sith.ix.localhost |
When we run the Spring Boot application below on the standard port, 8080
, this configuration allows you to browse to http://sith.ix.localhost:8080
and http://stormtrooper.ix.localhost:8080
Spring Boot Application
The code for the example application can be found here.
This application simply demonstrates the subdomain based multi-tenant capability that we configured in the previous section.
So, how do we go about enabling ID Site for our application? What about displaying the Organization field on the login form? This is done as a configuration in the application.properties
file:
1 2 3 |
stormpath.web.idSite.enabled = true stormpath.web.idSite.showOrganizationField = true |
That’s it!
The application consists of two controllers and a couple of templates. The HomeController
shows the home
template. The homepage /
is completely unprotected. The RestrictedController
shows the restricted
template. You must be logged in to go to /restricted
.
You can fire up the app as follows:
1 2 3 4 5 6 |
mvn clean package STORMPATH_API_KEY_FILE= \ STORMPATH_APPLICATION_HREF= \ mvn spring-boot:run |
Let’s see the multi-tenancy partitioning in action:
- Browse to:
http://sith.ix.localhost:8080/
- Click the green button
- Enter in the Darth Vader account information we created earlier
Notice that the tenant, extracted from the subdomain, is shown in the read-only Organization
field on the page. This is a result of the application.properties
configuration we did above. We could choose to not show the Organization field at all since it is taken from the subdomain automatically.
- Click the
Login
button and you will be redirected back to the/restricted
page
So, what? What’s the big deal? Here it is: Logout and then try to login again using the Stormtrooper account we setup earlier:
Stormtroopers are not allowed to log into the sith
Tenant.
Now, try to login with the Stormtrooper Account using the correct URL: http://stormtrooper.ix.localhost:8080/
There it is! Remember, we have a single instance of our Spring Boot application running. We’ve achieved the goal of partitioning the Sith Lord’s from the Stormtroopers. This was accomplished mainly through the Organizations and the ID Site configurations in the Admin Console.
Wanna add another tenant to your Application? All you need to do is create another Organization with mapped Directory and then add that Organization to the Account Store Mappings of your Application. You can then immediately browse to the new subdomain – no need to even restart the application! If you added an Organization with name key officer
, you could immediately browse to: http://officer.ix.localhost:8080
(you’d still need to add officer.ix.localhost
to your /etc/hosts
file).
I hope you’re as excited as I am about how powerful and useful the automatic multi-tenant by subdomain feature of Stormpath is.