- Introduction
- Steps
- 1. Configure RESTHeart to use the DbIdentityManager
- 2. Configure the mandatory security.yml file
- 3. Create the Javascript file
- 4. Create all the users via mongo shell
- 5. Check the database and collection
- 6. Start RESTHeart
- 7. Check the admin’s roles
- 8. Replace the temporary password
- 9. GET the final document
- 10. Create another user
- 11. Check the new user
Users provisioning how-to
Introduction
RESTHeart offers a couple of options for authenticating users:
- The
SimpleFileIdentityManager
authenticates users defined in the default yaml configuration file. - The
DbIdentityManager
authenticates users defined in a MongoDB collection.
Option # 1 is static, as the configuration file is read at startup and
can’t be changed. In real applications it’s often mandatory to switch to
option # 2 and manage users dynamically into the database. However, if
RESTheart is started with the DbIdentityManager
configuration then it
needs at least one user already present in the database or it aborts
immediately. The way to achieve this is to seed the database in advance,
provisioning the very first administrative user in the right MongoDB
collection so that RESTHeart can start-up properly.
Steps
1. Configure RESTHeart to use the DbIdentityManager
Edit the usual restheart.yml
file (below is a fragment):
restheart.yml (fragment)
...
idm:
implementation-class: org.restheart.security.impl.DbIdentityManager
conf-file: ./etc/security.yml
access-manager:
implementation-class: org.restheart.security.impl.SimpleAccessManager
conf-file: ./etc/security.yml
...
2. Configure the mandatory security.yml
file
Create some roles as needed. In this case users will be stored under the
users
collection of the auth
database, but names are arbitrary.
security.yml
## RESTHeart example security configuration file.
---
## Configuration for db based Identity Manager
dbim:
- db: auth
coll: users
cache-enabled: false
cache-size: 1000
cache-ttl: 60000
cache-expire-policy: AFTER_WRITE
# Users with role 'ADMIN' can do anything
permissions:
- role: ADMIN
predicate: path-prefix[path="/"]
- role: OPERATOR
predicate: path-prefix[path="/myapp"]
- role: USER
predicate: path-prefix[path="/myapp"]
# Not authenticated user can only GET any resource under the /public URI
- role: $unauthenticated
predicate: path-prefix[path="/public"] and method[value="GET"]
3. Create the Javascript file
This is necessary to insert the administrative user into MongoDB. Let’s call it “admin”
The first line tells MongoDB to use the same database name as it was
configured in the dbim
section of the above configuration file, in
this case the db is called “auth”:
dbim:
- db: auth
...
Start the mongo shell and insert the administrative user by hand or edit a file if you want to create multiple users at ht e same time:
users.js
use auth;
db.users.insert({ _id: "admin", password: "temp", roles: ['ADMIN'] });
...
Pay attention to the roles
array in the above Javascript statement:
its content must exactly match the role names in the permissions
section of the yaml configuration file or it won’t work.
4. Create all the users via mongo shell
In this example MongoDB runs at IP 192.168.99.100 (it’s a Docker
container). You might want to replace the address with localhost
or
whatever.
The command below creates the auth
database and the admin
user in
one shot.
$ mongo 192.168.99.100:27017/auth users.js
MongoDB shell version: 3.0.7
connecting to: 192.168.99.100:27017/auth
5. Check the database and collection
For example with the following two shell commands it’s possible to check database names and list the users collection of the auth database:
$ mongo --host 192.168.99.100 --eval "printjson(db.adminCommand('listDatabases'))"
{
"databases" : [
{
"name" : "auth",
"sizeOnDisk" : 65536,
"empty" : false
},
{
"name" : "local",
"sizeOnDisk" : 32768,
"empty" : false
}
],
"totalSize" : 98304,
"ok" : 1
}
$ mongo auth --host 192.168.99.100 --eval "db.users.find();"
MongoDB shell version: 3.2.1
connecting to: auth
{ "_id" : "admin", "password" : "temp", "roles" : [ "ADMIN" ] }
...
6. Start RESTHeart
Start RESTHeart as you would usually do. Logs must be clean, like below:
16:31:10.242 [main] INFO org.restheart.Bootstrapper - Starting RESTHeart
16:31:10.255 [main] INFO org.restheart.Bootstrapper - version 1.1.3
16:31:10.270 [main] INFO org.restheart.Bootstrapper - Logging to console with level INFO
16:31:10.580 [main] INFO org.restheart.Bootstrapper - MongoDB connection pool initialized
16:31:10.580 [main] INFO org.restheart.Bootstrapper - MongoDB version 3.2.0
16:31:10.856 [main] INFO org.restheart.Bootstrapper - Token based authentication enabled with token TTL 15 minutes
16:31:11.130 [main] INFO org.restheart.Bootstrapper - HTTPS listener bound at 0.0.0.0:4443
16:31:11.134 [main] INFO org.restheart.Bootstrapper - HTTP listener bound at 0.0.0.0:8080
16:31:11.138 [main] INFO org.restheart.Bootstrapper - Local cache for db and collection properties enabled
16:31:11.203 [main] INFO org.restheart.Bootstrapper - URL / bound to MongoDB resource *
16:31:11.372 [main] INFO org.restheart.Bootstrapper - Embedded static resources browser extracted in /tmp/restheart-5012079845495337850
16:31:11.395 [main] INFO org.restheart.Bootstrapper - URL /browser bound to static resources browser. access manager: false
16:31:11.398 [main] INFO org.restheart.Bootstrapper - URL /_logic/ping bound to application logic handler org.restheart.handlers.applicationlogic.PingHandler. access manager: false
16:31:11.402 [main] INFO org.restheart.Bootstrapper - URL /_logic/roles bound to application logic handler org.restheart.handlers.applicationlogic.GetRoleHandler. access manager: false
16:31:11.727 [main] INFO org.restheart.Bootstrapper - Pid file /var/run/restheart--1441246088.pid
16:31:11.731 [main] INFO org.restheart.Bootstrapper - RESTHeart started
7. Check the admin’s roles
For example with the httpie client, get
the /_logic/roles/admin
resource which shows user’s roles
$ http -a admin:temp 192.168.99.100/_logic/roles/admin
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ETag, Auth-Token, Auth-Token-Valid-Until, Auth-Token-Location, X-Powered-By
Auth-Token: ee46be56-fdd1-48e6-afa2-934f114ab882
Auth-Token-Location: /_authtokens/admin
Auth-Token-Valid-Until: 2016-01-07T16:49:29.194Z
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 108
Content-Type: application/hal+json
Date: Thu, 07 Jan 2016 16:34:29 GMT
X-Powered-By: restheart.org
{
"_links": {
"self": {
"href": "/_logic/roles/admin"
}
},
"authenticated": true,
"roles": [
"ADMIN"
]
}
8. Replace the temporary password
The “temp” password in the users.js file is really temporary, just set a better one. Say for example “12345”, which is actually not much better, but it’s an example :)
$ http -a admin:temp -j PATCH 192.168.99.100/auth/users/admin password=12345
HTTP/1.1 409 Conflict
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ETag, Auth-Token, Auth-Token-Valid-Until, Auth-Token-Location, X-Powered-By
Auth-Token: ee46be56-fdd1-48e6-afa2-934f114ab882
Auth-Token-Location: /_authtokens/admin
Auth-Token-Valid-Until: 2016-01-07T16:52:57.209Z
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 167
Content-Type: application/hal+json
Date: Thu, 07 Jan 2016 16:37:57 GMT
ETag: 568e9465c9e77c000646e830
X-Powered-By: restheart.org
{
"_links": {
"self": {
"href": "/auth/users/admin"
}
},
"http status code": 409,
"http status description": "Conflict",
"message": "The document's ETag must be provided using the 'If-Match' header"
}
9. GET the final document
Don’t forget to authenticate now using the new password! Check that the output is similar to below and you have a proper ETag (“_etag” key)
$ http -a admin:12345 192.168.99.100/auth/users/admin
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ETag, Auth-Token, Auth-Token-Valid-Until, Auth-Token-Location, X-Powered-By
Auth-Token: df20de0a-f9ba-40dc-a659-86031f501509
Auth-Token-Location: /_authtokens/admin
Auth-Token-Valid-Until: 2016-01-07T18:18:18.526Z
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 154
Content-Type: application/hal+json
Date: Thu, 07 Jan 2016 18:03:18 GMT
ETag: 568e9465c9e77c000646e830
X-Powered-By: restheart.org
{
"_etag": {
"$oid": "568e9465c9e77c000646e830"
},
"_id": "admin",
"_links": {
"curies": [],
"self": {
"href": "/auth/users/admin"
}
},
"password": "12345",
"roles": [
"ADMIN"
]
}
10. Create another user
Now RESTHeart is ready to be fully managed by the admin
user. For
example, to add more users for the DbIdentityManager it’s enough to use
the following API call.
Let’s create a new user with id “johnsmith”, password ”Qer432” and role “USER”
$ http -a admin:12345 -j POST 192.168.99.100/auth/users _id="johnsmith" password="Qer432" roles:='["USER"]'
HTTP/1.1 201 Created
...
11. Check the new user
Get the /auth/users/johnsmith
resource
$ http -a admin:temp 192.168.99.100/auth/users/johnsmith
HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: *
Access-Control-Expose-Headers: Location, ETag, Auth-Token, Auth-Token-Valid-Until, Auth-Token-Location, X-Powered-By
Auth-Token: df20de0a-f9ba-40dc-a659-86031f501509
Auth-Token-Location: /_authtokens/admin
Auth-Token-Valid-Until: 2016-01-07T18:32:43.687Z
Connection: keep-alive
Content-Encoding: gzip
Content-Length: 160
Content-Type: application/hal+json
Date: Thu, 07 Jan 2016 18:17:43 GMT
ETag: 568eab70c9e77c000646e831
X-Powered-By: restheart.org
{
"_etag": {
"$oid": "568eab70c9e77c000646e831"
},
"_id": "johnsmith",
"_links": {
"curies": [],
"self": {
"href": "/auth/users/johnsmith"
}
},
"password": "Qer432",
"roles": [
"USER"
]
}