Permissions

From BaseX Documentation
Jump to navigation Jump to search

This page presents the web application permission layer of BaseX, which can be used along with RESTXQ.

Non-trivial web applications require a user management: Users need to log in too get access to protected parts of a web site, and depending on their status (role, user group, …), they can be offered different views. One popular way to realize this is to start each RESTXQ function body with a call to a security function. This function raises an exception if a user is not logged in, or has not enough permissions to call the requested REST endpoint.

With Version 9.0 of BaseX, a light-weight permission layer has been added:

  • Functions can be annotated with permission strings, and
  • Global permission functions can be written to ensure that the current user has sufficient permissions.

Introduction

Preliminaries

All permission annotations are assigned to the http://basex.org/modules/perm namespace, which is statically bound to the perm prefix.

Attaching permissions

With the %perm:allow annotation, one or more permission strings can be attached to a RESTXQ function:

(:~ Public login page. :)
declare %rest:path("/") function local:admin() {
  <html>Please log in...</html>
};

(:~ Restricted page. :)
declare %rest:path("/main") function local:admin() {
  <html>Welcome to the main page!</html>
};

(:~ Admin page. :)
declare %rest:path("/main/admin") %perm:allow("admin") function local:admin() {
  <html>Welcome to the privileged administrator page.</html>
};

It is completely up to the user which permission strings are used in an application. The strings may denote ids, users, user groups, or any other realms.

Checking permissions

Functions that are marked with %perm:check will be invoked before the actual target function will be evaluated. Two arguments can be specified with the annotation:

  • The first path argument ensures that the function will only be called if the request path starts with the given string.
  • The second argument binds the permission strings of the invoked function, and some other request information, to a variable.

An example:

import module namespace Session = 'http://basex.org/modules/session';

(:~
 : Global permission checks.
 :)
declare function local:check() {
  let $method := Request:method()
  where $method != 'GET'
  return error((), 'Access is restricted to GET method.')
};
(:~
 : Permission check: Area for logged-in users.
 : Checks if a session id exists for the current user; if not, redirects to the login page.
 :)
declare %perm:check('/main') function local:check-app() {
  let $user := Session:get('id')
  where empty($user)
  return web:redirect('/')
};

(:~
 : Permissions: Admin area.
 : Checks if the current user is admin; if not, redirects to the main page.
 : @param $perm  map with permission data
 :)
declare %perm:check('/main/admin', '{$perm}') function local:check-admin($perm) {
  let $user := Session:get('id')
  where not(user:list-details($user)/@permission = $perm?allow)
  return web:redirect('/main')
};

If several permission functions are available that match the user request, all of them will be called one by one. The function with the shorted path argument will be called first. Accordingly, in the example, if the /main/admin URL is requested, all three security functions will be run.

If a security function raises an error or returns any result (which can be a redirection or any other XQuery value), no other functions will be invoked. This means that the actually invoked function will only be evaluated if all security functions yield no result or error.

The map bound to $perm has the following keys:

Key Description
allow Permission strings attached to the requested function.
path Original path of the client request.
method Method of the client request (GET, POST, …)