Building Secure Instant API's with RESTHeart and Compose

Published

When you need to turn your Mongo database into a RESTFul API, RESTHeart can get you up-and-running quickly and securely. Following up on our previous article on using RESTHeart to expose a RESTFUL API directly from a Mongo database on Compose, in this article, we'll show you how to secure your RESTHeart API by adding authentication and role-base access control, as well as enabling SSL encryption.

When we explored how to create instant RESTFul API's on Compose with RESTHeart, we left out one key important feature: Securing those API's. By default, RESTHeart exposes your API's via HTTP with authentication turned off. Now it's time to make our Instant API's more production-ready by adding authentication and SSL encryption to our RESTHeart API endpoints.

Setup

We'll pick up where we left off in the previous article, and in particular, you'll want to have RESTHeart already connected to Compose MongoDB running in a Docker container. You should also have a folder at the root of your project called etc and inside that etc folder you should have a restheart.yml starter file with a mongo-uri key that points to your Compose MongoDB database.

Authentication

The first step to securing our RESTHeart application is to require a username and password to access the API. RESTHeart uses a pluggable identity management system that allows users to authenticate using a variety of authentication mechanisms. We'll start out by storing our credentials in a file and cover database-stored credentials in a future article.

File-based Authentication

The easiest way to get started is to store your users' credentials in a file and use the built-in file-based identity manager to authenticate your users. To set this up, first, create a new file in the etc directory of your project (NOT your system /etc folder) called security.yml. Next, open restheart.yml and add the following line of code to the Identity Management section:

idm:  
    implementation-class: org.restheart.security.impl.SimpleFileIdentityManager
    conf-file: ./etc/security.yml

Then, open the ./etc/security.yml file and add your users' credentials:

users:  
 - userid: admin
   password: changeme
 - userid: client
   password: changeme

This provides us with 2 users, an admin user and a client user. Obviously, this SimpleFileIdentityManager is less than ideal as it stores our users' passwords in plain text in a file rather than using industry-standard encryption in a database. Fortunately, the Identity Management system in RESTHeart is pluggable and in a future article, we'll prepare RESTHeart for production by creating a more secure custom Identity Manager to address th.

RESTHeart uses Basic Authentication, a web standard which generates a token from user credentials. If you visit the URL for RESTHeart in your browser, you'll be prompted to enter your username and password automatically. Once you've successfully authenticated, an authentication token is added to the header of each subsequent call.

If you're attempting to generate access tokens programmatically, rather than through your web browser, you'll need to perform the Basic Authentication steps. First, the initial credentials are sent via an Authorization: header of the request, along with the word BASIC and the username and password separated by a colon (:) encoded using base64 encoding like the following:

base64("admin:changeme")

The final result would look like the following:

Authorization: Basic YWRtaW46Y2hhbmdlbWUK

If the authorization request is successful, an auth token will be returned in the response headers of the call you made. They look something like the following:

Auth-Token: 6a81d622-5e24-4d9e-adc0-e3f7f2d93ac7  
Auth-Token-Location: /_authtokens/user@si.com  
Auth-Token-Valid-Until: 2017-04-30T11:13:45.031Z  

Once you have the auth token, simply include it in the request headers for every subsequent call. They will work until the expiration date in the Auth-Token-Valid-Until header.

You can use the CURL command to automatically generate the token and include it with every subsequent CURL request by using the following command:

curl -i --user admin:changeme http://localhost/restheart  

For other methods, you may have to store the auth header value and include it manually for each request.

Access Management

So far we've looked at authenticating users in RESTHeart, but sometimes we need different users to have access to different parts of the system. Like the authentication system, RESTHeart has a pluggable access management system as well. This will allow us to define multiple roles and allow or deny access to specified routes and methods for those role types.

We'll try this out by using the File-based Access management system. First, open the ./etc/restheart.yml file and add the following to the security section:

access-manager:  
    implementation-class: org.restheart.security.impl.SimpleAccessManager
    conf-file: ./etc/security.yml

The SimpleAccessManager reads users and roles from a file. Let's open up our ./etc/security.yml file again and add the following:

permissions:  
 - role: admins
   predicate: path-prefix[path="/"]
 - role: $unauthenticated
   predicate: path-prefix[path="/public/"] and method[value="GET"]
 - role: users
   predicate: path-prefix[path="/public/"]

These settings create two roles, admins and users, as well as a built-in default role of $unauthenticated. Access is granted using predicates, and the predicates are define per-role, meaning predicates that affect one role type will not affect the others.

Our first predicate grants users with the role of admin access to any route using any method. The second grants any unauthenticated user permission to access any route with the prefix of /public, but only using the GET HTTP method. Finally, the last rule defines a users role that has access to any route prefixed with /public but using any HTTP method.

Next, we'll update our users to specify roles for each one:

users:  
 - userid: admin
   password: changeme
   roles: [admins]
 - userid: client
   password: changeme
   roles: [users]

Note that roles is an array, meaning we can add any user type to multiple different roles. This allows us to create granular roles that define specific behavior, and allows us to create a robust role-based authentication scheme.

Now that we've covered authentication and authorization, there's one more security issue that we need to address: connection encryption.

SSL using Embedded Self-Signed Certificates

Using RESTHeart without SSL exposes your database to serious security risks, including Man-in-the-Middle attacks which can compromise the integrity and security of your database. To solve that problem, let's take a look at how we can set up RESTHeart to use HTTPS and SSL.

RESTHeart comes with an embedded set of self-signed certificates, so adding SSL support can be as simple as enabling these embedded self-signed certificates. To enable SSL, change the following configuration setting in the restheart.yml file:

### listeners
https-listener: true  
https-host: 0.0.0.0  
https-port: 443  

This enables the HTTPS listener in the RESTHeart service on port 443 (the default for HTTPS). We'll also need to tell RESTHeart which certificates to use for the connection. To use the embedded self-signed certificates that come with RESTHeart use the use-embedded-keystore configuration option in your restheart.yml file like the following:

#### SSL configuration

use-embedded-keystore: true

#keystore-file: /path/to/keystore/file
#keystore-password: password
#certpassword: password

Notice that, for now, we have the keystore-file, keystore-password, and certpassword commented out. We'll see how we can use those in a moment.

When we run our container, we'll want to expose port 443 in our RESTHeart docker container and map it to our hosts' 443 port using the -p command:

docker run -d -p 443:443 --name restheart -v $PWD/etc:/opt/restheart/etc:ro softinstigate/restheart:3.0.0  

You can now access RESTHeart by going to https://localhost . However, you may notice that visiting the site in a web browser will give you a security warning, and using CURL --insecure flag. This is because the built-in self-signed certificates are not recognized as being valid certificates, and this will be an issue in production as well. In a future article, we'll explore how we can use authoritative certificates, and in particular, we'll look at using LetsEncrypt to generate automatically-renewing authority-signed certificates.

Wrapping up

In this article, we took a look at how we can add SSL and authentication mechanisms to our RESTHeart APIs and this gets us closer to running RESTHeart in production. In a future article, we'll complete the cycle and create a production-quality Custom Identity Manager in Java with hashed passwords, show how to use production-ready certificates using LetsEncrypt, and deploy our RESTHeart API to the public using the IBM Bluemix Container Service.


If you have any feedback about this or any other Compose article, drop the Compose Articles team a line at articles@compose.com. We're happy to hear from you.

Image by Pixabay User Der_Typ_von_Nebenan
John O'Connor
John O'Connor is a code junky, educator, and amateur dad that loves letting the smoke out of gadgets, turning caffeine into code, and writing about it all. Love this article? Head over to John O'Connor’s author page and keep reading.