Difference between revisions of "Permissions"

From BaseX Documentation
Jump to navigation Jump to search
Line 1: Line 1:
 
This page presents the web application permission layer of BaseX, which can be used along with [[RESTXQ]].
 
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.
+
Non-trivial web applications require a user management: Users need to log in to a web site in order to get access to protected pages. Depending on their status (role, user group, …), they can be offered different views.
  
With {{Version|9.0}} of BaseX, a light-weight permission layer has been added:
+
With {{Version|9.0}} of BaseX, a light-weight permission layer has been added that simplifies permission checks a lot:
  
* Functions can be annotated with permission strings, and
+
* RESTXQ functions can be annotated with flexible permission strings, and
* Global permission functions can be written to ensure that the current user has sufficient permissions.
+
* permission functions ensure that access will only be granted if a client has sufficient permissions.
  
 
=Preliminaries=
 
=Preliminaries=

Revision as of 18:45, 18 January 2018

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 to a web site in order to get access to protected pages. Depending on their status (role, user group, …), they can be offered different views.

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

  • RESTXQ functions can be annotated with flexible permission strings, and
  • permission functions ensure that access will only be granted if a client has sufficient permissions.

Preliminaries

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

Annotations

Permission Strings

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

(:~ Login page (visible to everyone). :)
declare
  %rest:path("/")
  %output:method("html")
function local:login() {
  <html>
    Please log in:
    <form action="/login-check" method="post">
      <input name="name"/>
      <input type="password" name="pass"/>
      <input type="submit"/>
    </form>
  </html>
};

(:~ Main page (restricted to logged in users). :)
declare
  %rest:path("/main")
  %output:method("html")
function local:main() {
  <html>
    Welcome to the main page:
    <a href='/main/admin'>admin area</a>,
    <a href='/logout'>log out</a>.
  </html>
};

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

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

Checking Permissions

Functions that are marked with %perm:check are so-called Security Functions. These functions will be invoked before the actually requested function will be evaluated. Two arguments can be specified with the annotation:

  • A path argument can be specified with the first argument. The security function will only be called if the request path starts with the given path. In contrast to RESTXQ, all subordinate paths will be accepted as well. If no path argument is specified, / is assigned instead.
  • With the second argument, various permission-specific information can be bound to a map.

An example:

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

(:~
 : Global permission checks.
 : Rejects any usage of the HTTP DELETE method.
 :)
declare %perm:check %rest:DELETE function local:check() {
  error((), 'Access denied to DELETE 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')
};

Some notes:

  • 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.
  • As shown in the first function, the %perm:check annotation can be combined with other RESTXQ annotations (excluding %rest:path and %rest:error).
  • In the example, it is assumed that a logged in user is bound to a session variable (see further below)

The map, which can be bound to a variable (in this example $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, …)

The permission layer was designed to provide as much flexibility as possible to the web application developer. Some extreme cases:

  • It is possible to completely work without permission strings, and realize all access checks based on the request information (path, method, and properties returned by the Request Module).
  • Each RESTXQ function can be accompanied by its individual security function.

The bare minimum is a single %perm:check function. Without this function, existing %perm:allow annotations will be ignored.

Authentication

There are numerous ways how users can be authenticated in a web application (OAuth). The approach demonstrated in this article is very straight-forward:

  • A login HTML page allows you to enter your credentials (user name, password).
  • A login check function checks if the typed in data matches one of the database users. If the input is valid, a session id will be set, and the user will be redirected to the main page. Otherwise, the redirection points back to the login page.
  • A logout page deletes the session id.

The following lines of code complete the image:

declare
  %rest:path("/login-check")
  %rest:query-param("name", "{$name}")
  %rest:query-param("pass", "{$pass}")
function local:login($name, $pass) {
  try {
    user:check($name, $pass),
    Session:set('id', $name),
    web:redirect("/main")
  } catch user:* {
    web:redirect("/")
  }
};

declare
  %rest:path("/logout")
function local:logout() {
  Session:delete('id'),
  web:redirect("/")
};

For a full round trip, check out the source code of the DBA that is bundled with BaseX.

Changelog

The Module was introduced with Version 9.0.