User Management

This document describes how to create and manage users and configure user access privileges.

API concepts

The NuoDB Control Plane REST API exposes access to resources in a hierarchical structure.

  • An organization contains several projects and users.
  • A user is an entity that authenticates itself and issues requests to resources that it has been granted access to.
  • A project contains several databases and enables both logical and physical separation between databases. Databases belonging to the same project share resources associated with the project (i.e. a NuoDB domain), while databases in different projects do not share these resources and are more isolated from each other.

The /users resource

The /users resource of the Control Plane REST API has the following request methods.

  • GET /users/<organization> lists all of the users within an organization.
  • GET /users/<organization>/<user> returns a specific user.
  • PUT /users/<organization>/<user> creates a new user, or updates an existing one if the resourceVersion field is specified in the request payload.
  • PATCH /users/<organization>/<user> updates an existing user by applying the JSONPatch operations specified.
  • DELETE /users/<organization>/<user> deletes an existing user.

Note

Similar conventions are also followed for the /projects and /databases resources.

The specification of a user has the following format:

{
  "organization": "...",
  "name": "...",
  "password": "...",
  "accessRule": { ... },
  "resourceVersion": "..."
}

As with the /projects/<organization>/<project> and /databases/<organization>/<project>/<database> resources, the resourceVersion is an opaque value generated by the system and appearing in GET response payloads. When the user specifies it in a PUT request payload, an update of the existing resource is performed.

Note

An update will fail with status code 409 Conflict if a concurrent update caused the resourceVersion to change.

The password field does not appear in the response payload for GET /users/<organization>/<user> and is only required when creating a new user or updating the password of an existing user. The password is not retained by the system. It is used to compute a verifier that is stored persistently and used to verify authentication credentials on future requests by the user.

The fields organization and name are redundant with the path parameters in the users/<organization>/<user> resource, so they can be omitted from PUT request payloads.

Specifying access rules

The value of the accessRule field has the following format:

{
  "allow": [
    "<verb>:<resource specifier>[:<SLA>]",
    ...
  ],
  "deny": [
    "<verb>:<resource specifier>",
    ...
  ]
}

The allow and deny fields accept arrays of access rule entries that grant and deny access, respectively. An access rule entry has the format <verb>:<resource specifier>[:<SLA>].

Verb

A verb is one of the following and is associated with one or more HTTP methods.

verbHTTP methods
readGET
writePUT, PATCH
deleteDELETE
allGET, PUT, PATCH, DELETE

Resource specifier

A resource specifier takes one of two forms:

  • If a resource specifier starts with /, then it is interpreted as an absolute resource path. The first component of the path must be one of /projects, /databases/, /users, and /healthz.
  • Otherwise, it is interpreted as a scope, which has the format <organization>/<project>/<database>, <organization>/<project>, or <organization>. A scope binds to a specific object in the hierarchy of DBaaS objects (organizations, projects, databases) and expands to the set of resource paths associated with that object. For example, the scope acme expands to the resource paths /projects/acme/*, /databases/acme/*, and /users/acme/*, while acme/messaging expands to /projects/acme/messaging/* and /databases/acme/messaging/*.

SLA

An optional third component of the access rule entry limits access to only projects that have matching SLA values and databases within projects that have matching SLA values. For example, write:acme:dev would grant write access to all projects within the acme organization with SLA dev and all of their databases.

Only allow entries accept an SLA value.

Example: Full access

To grant full access to all resources, the wildcard resource can be specified.

{
  "allow": "all:*"
}

Note

Either (or both) of the allow and deny fields in the access rule can be omitted or supplied with a string value, which expands to a single element array.

Example: Read and write access at different levels

To grant read access at the organization level and write access at the project level, the following can be specified.

{
  "allow": [
    "read:acme",
    "write:acme/messaging"
  ]
}

The rule above allows projects, databases, and users to be listed for the organization acme and allows the specific project acme/messaging to be written, as well as any database within acme/messaging.

Example: Access to specific resource paths

Access can be granted to specific resource paths as follows:

{
  "allow": [
    "all:acme/messaging/demo",
    "all:/users/acme/dbuser"
  ]
}

In the example above, the resource /users/acme/dbuser is specified to grant full access to that specific user. This would allow a user to change its own password without having access to all resources at the organization level.

Example: Denying access to resource paths

Access to specific resource paths can also be explicitly denied using the deny field.

{
  "allow": "all:acme",
  "deny": "all:/users/*"
}

In the example above, full access is granted for all resources in the acme organization, except users. Note that this is equivalent to the following access rule, assuming that the set of root resources expanded by an organization scope is /projects, /databases, and /users:

{
  "allow": [
    "all:/projects/acme/*",
    "all:/databases/acme/*"
  ]
}

Although the two access rules are equivalent for the current version of the Control Plane REST API, they would behave differently if changes are made to the API. The former would grant access to any organization-scoped resources that are added to the API, while the latter would not. It is up to the administrator to decide which approach is best.

Example: Access to multiple organizations

Even though each user belongs to a specific organization, it is possible to grant users access to multiple organizations, as shown below:

{
  "allow": [
    "all:acme",
    "read:notacme"
  ]
}

Note

Adding access outside of a user’s organization requires specifying the query parameter allowCrossOrganizationAccess=true, which is accepted by both PUT and PATCH requests on the user resource.

Example: Access constrained by SLA

To grant access to only the projects and databases within a scope that have a particular SLA value, an SLA constraint can be specified:

{
  "allow": [
    "all:acme:dev",
    "read:acme:qa",
    "write:acme/messaging"
  ]
}

In the example above, full access is granted to all projects and databases in acme that have SLA dev, read access is granted to projects and databases in acme that have SLA qa, and write access is granted to the specific project acme/messaging.

Authentication

The authentication method supported by the Control Plane REST API is HTTP basic authentication. The user name is supplied in the format <organization>/<user> along with the password.

To authenticate using curl:

curl -u "acme/dbuser:$PASS" ...

To authenticate using the httpclient subcommand of the nuodb-cp tool:

nuodb-cp httpclient -u acme/dbuser -p "$PASS" ...

If the REST server property com.nuodb.controlplane.server.bypassLocalAuthentication is set to true, then authentication and access control can be bypassed by issuing requests from a client on the same host as the REST server.

Creating users

Assuming that we are logged into the same host as a REST server configured with com.nuodb.controlplane.server.bypassLocalAuthentication=true, a user with organization level access can be created as follows:

nuodb-cp httpclient PUT users/acme/orgadmin -d '{"password": "orgS3cr3t", "accessRule": {"allow": "all:acme"}}'

Users can be created with more restrictive access rules as follows:

nuodb-cp httpclient -u acme/orgadmin -p 'orgS3cr3t' PUT users/acme/projadmin -d '{
  "password": "projS3cr3t",
  "accessRule": {
    "allow": [
      "all:acme/messaging"
    ]
  }
}'

nuodb-cp httpclient -u acme/orgadmin -p 'orgS3cr3t' PUT users/acme/dbadmin -d '{
  "password": "dbS3cr3t",
  "accessRule": {
    "allow": [
      "read:acme/messaging",
      "all:acme/messaging/demo"
    ]
  }
}'

The example above creates two users as the newly-created organization admin, one to manage a project and another to manage a database.

Verifying access

The expected access privileges can be verified by issuing requests as the created users. The commands below create a project as the project admin and a database as the database admin, which verifies write access.

nuodb-cp httpclient -u acme/projadmin -p 'projS3cr3t' PUT projects/acme/messaging -d '{"tier": "n0.nano", "sla": "dev"}'
nuodb-cp httpclient -u acme/dbadmin -p 'dbS3cr3t' PUT databases/acme/messaging/demo -d '{"dbaPassword": "thePassword"}'

To verify read access, issue various read requests:

$ nuodb-cp httpclient -u acme/projadmin -p 'projS3cr3t' GET projects/acme/messaging
{"organization":"acme","name":"messaging","sla":"dev","tier":"n0.nano","resourceVersion":"10","status":{"caPem":"-----BEGIN CERTIFICATE-----\nMIICwz...\n-----END CERTIFICATE-----","ready":false,"shutdown":false,"message":""}}

$ nuodb-cp httpclient -u acme/projadmin -p 'projS3cr3t' GET databases/acme/messaging
{"items":["demo"]}

$ nuodb-cp httpclient -u acme/dbadmin -p 'dbS3cr3t' GET databases/acme/messaging/demo
{"organization":"acme","project":"messaging","name":"demo","tier":"n0.nano","properties":{},"resourceVersion":"12","status":{"sqlEndpoint":"messaging-9706b842cb31.it.nuodb.local","caPem":"-----BEGIN CERTIFICATE-----\nMIICwz...\n-----END CERTIFICATE-----","ready":false,"shutdown":false,"message":""}}

To verify expected access limits, issue various requests outside of granted scopes, which should fail with status code 403 Forbidden:

$ nuodb-cp httpclient -u acme/orgadmin -p 'orgS3cr3t' GET healthz
{"code":"HTTP_ERROR","status":"HTTP 403 Forbidden","detail":"User 'acme/orgadmin' not authorized for 'GET healthz'"}

$ nuodb-cp httpclient -u acme/dbadmin -p 'dbS3cr3t' GET databases/acme/notmessaging
{"code":"HTTP_ERROR","status":"HTTP 403 Forbidden","detail":"User 'acme/dbadmin' not authorized for 'GET databases/acme/notmessaging'"}

$ nuodb-cp httpclient -u acme/projadmin -p 'projS3cr3t' GET users/acme/projadmin
{"code":"HTTP_ERROR","status":"HTTP 403 Forbidden","detail":"User 'acme/projadmin' not authorized for 'GET users/acme/projadmin'"}

Updating users

Users can be updated to change their access privileges or change their password.

To demonstrate updating of access privileges, first read the user resource:

$ nuodb-cp httpclient -u acme/orgadmin -p 'orgS3cr3t' GET users/acme/projadmin --pretty-print
{
  "organization":"acme",
  "name":"projadmin",
  "accessRule":{
    "allow":[ "all:acme/messaging" ],
    "deny":[ ]
  },
  "resourceVersion":"12317"
}

Next, use the PATCH method to add an entry to the allow array of the access rule:

nuodb-cp httpclient -u acme/orgadmin -p 'orgS3cr3t' PATCH users/acme/projadmin -d '[
  {
    "op": "add",
    "path": "/accessRule/allow/-",
    "value": "all:/users/acme/projadmin"
  }
]'

Note

The suffix - for the path indicates that the value should be appended to the specified array.

To verify that the change was made, read the user resource again, this time as the affected user (projadmin), which was previously unable to access its own user resource:

$ nuodb-cp httpclient -u acme/projadmin -p 'projS3cr3t' GET users/acme/projadmin --pretty-print
{
  "organization":"acme",
  "name":"projadmin",
  "accessRule":{
    "allow":[ "all:acme/messaging", "all:/users/acme/projadmin" ],
    "deny":[ ]
  },
  "resourceVersion":"12323"
}

The PATCH method can also be used to update a user’s password as follows:

nuodb-cp httpclient -u acme/projadmin -p 'projS3cr3t' PATCH users/acme/projadmin -d '[
  {
    "op": "add",
    "path": "/password",
    "value": "newprojS3cr3t"
  }
]'

Deleting users

Finally, a user can be deleted as follows:

nuodb-cp httpclient -u acme/projadmin -p 'newprojS3cr3t' DELETE users/acme/projadmin

Note

The request above actually deletes the user resource for the user issuing the request, which is legal.