Looking for Cloud Services or Professional Support? Check restheart.com

Edit Page

Authentication and Authorization tutorial

This tutorial aims to provide a thorough understanding of securing RESTHeart applications. RESTHeart offers robust security features, with Authentication and Authorization being central to these. This guide will explore the basic authentication. We’ll also delve into authorization, focusing on Access Control Lists (ACLs) and their role in defining permissions.

By the end of this tutorial, you’ll have a solid foundation in securing RESTHeart applications, ensuring data security and controlled access.

What you need

  1. Docker: For running RESTHeart.

  2. HTTPie: A user-friendly command-line HTTP client. Download at httpie.io/cli.

Starting RESTHeart and MongoDB

To begin, create a directory for RESTHeart and use Docker Compose to start both RESTHeart and MongoDB:

$ mkdir restheart && cd restheart
$ curl https://raw.githubusercontent.com/SoftInstigate/restheart/master/docker-compose.yml --output docker-compose.yml
$ docker compose up --attach restheart

The Admin User

Upon first launch, mongoRealmAuthenticator creates an admin user with default password secret and the admin role. This role is configured as the root role in mongoAclAuthorizer, granting full permissions.

Warning
Always change the admin user’s password to maintain security.

To change the admin password:

$ http -a admin:secret PATCH :8080/users/admin password="my-strong-password"

Creating Collection /secrets

Using admin, create the /secrets collection:

$ http -a admin:secret PUT :8080/secrets

Creating Users alice and bob

Next, create two users, alice and bob, each with the user role:

$ http -a admin:secret POST :8080/users _id=alice password=secret roles:='["user"]'
$ http -a admin:secret POST :8080/users _id=bob password=secret roles:='["user"]'

Understanding Status Codes

The /users/{id} endpoint can verify credentials. For example, using incorrect credentials for alice:

$ http -a alice:wrong GET :8080/secrets
HTTP/1.1 401 Unauthorized
Important
A 401 Unauthorized response indicates failed authentication due to incorrect credentials. RESTHeart blocks requests to secure services without proper authentication.

Attempting access with correct credentials:

$ http -a alice:secret GET :8080/secrets
HTTP/1.1 403 Forbidden
Important
A 403 Forbidden response means authentication succeeded, but the client lacks permission to access the resource.

RESTHeart’s default authorizer, mongoAclAuthorizer, enforces permissions based on user roles and ACL configurations.

Configuring Access for user Role on /secrets

We aim to allow user role to create and access their own documents in /secrets, and to modify only their documents.

1) Allow GET on /secrets:

Users can only access documents they created.

{
    "_id": "userCanAccessOwnSecret",
    "roles": [ "user" ],
    "predicate": "method(GET) and path('/secrets')",
    "priority": 100,
    "mongo": { "readFilter": "{ author: @user._id }" }
}

2) Allow POST on /secrets:

Users can create new documents, setting the author to their _id.

{
    "_id": "userCanCreateOwnSecret",
    "roles": [ "user" ],
    "predicate": "method(POST) and path('/secrets')",
    "priority": 100,
    "mongo": { "mergeRequest": { "author": "@user._id" } }
}

3) Allow PATCH on /secrets/{id}:

Users can modify only their documents.

{
    "_id": "userCanModifyOwnSecret",
    "roles": [ "user" ],
    "predicate": "method(PATCH) and path-template('/secrets/{id}')",
    "priority": 100,
    "mongo": { "writeFilter": { "author": "@user._id" } }
}

To create these permissions, use the following commands:

$ http -a admin:secret POST :8080/acl _id=userCanAccessOwnSecret roles:='["user"]' priority:=100 predicate="method(GET) and path('/secrets')" mongo.readFilter:='{ "author": "@user._id" }'
$ http -a admin:secret POST :8080/acl _id=userCanCreateOwnSecret roles:='["user"]' priority:=100 predicate="method(POST) and path('/secrets')" mongo.mergeRequest:='{ "author": "@user._id" }'
$ http -a admin:secret POST :8080/acl _id=userCanModifyOwnSecret roles:='["user"]' priority:=100 predicate="method(PATCH) and path-template('/secrets/{id}')" mongo.writeFilter:='{ "author": "@user._id" }'

Creating Secret Documents

Let’s have alice and bob create their secrets:

$ http -a bob:secret POST :8080/secrets message="Bob loves Alice"
$ http -a alice:secret POST :8080/secrets message="Alice loves Bob"

Reading Secret Documents

Viewing with admin:

$ http -a admin:secret -b GET :8080/secrets
# Output includes both Alice's and Bob's messages
Note
The author property is correctly set for each document.

Accessing /secrets as alice:

$ http -a alice:secret -b GET :8080/secrets
# Output includes only Alice's message

Similarly, accessing as bob:

$ http -a bob:secret -b GET :8080/secrets
# Output includes only Bob's message

Let’s take a moment to acknowledge the story of Alice and Bob. These two characters are entwined in an 'impossible love' story that symbolizes the challenges of secure communication in the digital age. And RESTHeart is no exception keeping their love hidden in the /secrets collection.