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.
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.
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.
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:
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: /email@example.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
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.
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
### 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
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
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.
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 firstname.lastname@example.org. We're happy to hear from you.