Skip to content

macnod/rbac

Repository files navigation

RBAC System Reference Manual

Table of Contents

  • 1 Examples
  • 2 Introduction
  • 3 Current Limitations (Planned Fixes)
  • 4 Installation
  • 5 RBAC-PG Class
  • 6 Functions
  • 7 Special Variables
  • 8 Macros
  • 9 RBAC Development
[in package RBAC]

Simple Role-Based Access Control (RBAC) system implemented in Common Lisp. It provides an rbac-pg class and functions for managing users, roles, permissions, and resources.

1 Examples

Usage examples.

;;
;; WARNING: Use environment variables for real passwords, never hardcode them
;;

(require :rbac)
(defpackage :rbac-example (:use :cl :rbac))
(in-package :rbac-example)

;; Connect to the databse
(defparameter *rbac* (make-instance 'rbac-pg
                       :host "127.0.0.1"
                       :port "5432"
                       :user-name "rbac"
                       :password "rbac-password"))

;; Initialize the database. This will create the base users,
;; roles, and permissions. The password would normally come
;; from an environment variable.
(initialize-database *rbac* "admin-password-1")

;; Add a bogus permission
(add-permission *rbac* "bogus-permission")

;; Add some roles. The first role has the "read" permission only.
(add-role *rbac* "role-a" :permissions '("read"))

;; role-b has the default permissions, "create", "read", "update",
;; and "delete".
(add-role *rbac* "role-b")

;; role-c has the default permissions plus the "bogus-permission".
(add-role *rbac* "role-c"
  :permissions (cons "bogus-permission" *default-permissions*))

;; role-d has only the "bogus" permission only.
(add-role *rbac* "role-d"
  :permissions '("bogus-permission"))

;; Add a user with roles "role-a" and "role-b"
(add-user *rbac* "user-1" "user-1@example.com" "password-01"
    :roles '("role-a" "role-b"))

;; Add a resource that is accessible to the public
(add-resource *rbac* "test:resource-1"
    :roles '("public" "role-b"))

;; Should list 3 users: "admin", "guest", and the user we just
;; added, "user-1"
(list-user-names *rbac*)

;; Should list the default permissions
(list-permission-names *rbac*)

;; Lists the roles for user "user-1", including "role-a" and
;; "role-b", which we assigned, the user's exclusive role,
;; "user-1:exclusive", which the system assigned, and the
;; "logged-in" role, also assigned by the system.
(list-user-role-names *rbac* "user-1")

;; Lists the permissions that "user-1" has on resource
;; "test:resource-1", which should be all the permissions from
;; the roles that the user and the resource share, "public"
;; and "role-b". This amounts to all the default permissions.
(list-user-resource-permission-names *rbac* "user-1" "test:resource-1")

;; Returns T, because "read" is among the permissions that
;; the user has on the resource.
(user-allowed *rbac* "user-1" "read" "test:resource-1")

2 Introduction

This library provides functions and initial SQL for supporting Role-Based Access Control (RBAC).

The system provides users, roles, permissions, and resources. Users have roles. Roles have permissions. Resources also have roles. However, resources do not have users. To determine if user 'adam' has 'read' access to resource 'book', the user and the book must both have the same role and the role must have the 'read' permission.

A role can be exclusive, which means that it can be associated with only one user. Exclusive roles are managed by the system, so there's never any need to create or delete exclusive roles. However, you can manage the permission for an exclusive role. Whenever a user is created with the add-user function, the library creates the user's exclusive role. The user's exclusive role is also removed when the user is removed. Thus, the exclusive role represents that user only. In this way, it's possible to give a specific user access to the resource. All users have a corresponding exclusive role, except for the guest user. You can obtain the name of a user's exclusive role with the exclusive-role-for function.

All new users are created with default roles: 'logged-in', 'public', and the exclusive role for that user. If a resource has the 'logged-in' role, then every logged-in user (that is, every user except for 'guest') has access to the resource. If a resource has the 'public' role, then all users, including the guest user (not logged in), have access to the resource. The 'public' and 'logged-in' roles have 'read' permission by default.

Unless you specify specific permissions when creating a new role, its permission defaults to 'create', 'read', 'update', and 'delete'. These are general, default permissions, but you can add any permission you like to the system.

All new resources are created with the default role 'admin'.

3 Current Limitations (Planned Fixes)

Single-Threaded Design

RBAC operations span multiple transactions for maximum flexibility. Thus, this library will not work well with multi-threaded clients unless RBAC calls are serialized.

Status: Transaction wrappers planned for future release.

Password Hashing

Username salting prevents casual DB lookups, but doesn't provide optimal security.

Status: Argon2/PBKDF2 with iterations planned for future release.

4 Installation

Roswell

You'll need to install some dependencies first:

ros install postmodern
ros install fiveam
ros install cl-csv
ros install trivial-utf-8
ros install ironclad
ros install swank
ros install macnod/dc-dlist/v1.0
ros install macnod/dc-ds/v0.5
ros install macnod/dc-time/v0.5
ros install macnod/p-log/v0.9
ros install macnod/dc-eclectic/v0.51

Then, you can install rbac like this:

ros install macnod/rbac/vX.X

where X.X is the release. You can find the latest release in the repo.

GitHub

Clone the repo to a directory that Quicklisp or ASDF can see, such as ~/common-lisp. For example:

cd ~/common-lisp
git clone git@github.com:macnod/rbac.git
cd rbac

Then, install the macnod dependencies in a similar fashion. If use Quicklisp, then Quicklisp will take care of installing the other dependencies (non-macnod) when you do (ql:quickload :rbac).

Usage

One way to use the RBAC library is to create a project that includes the RBAC init.sql file. You might want to edit the init.sql file to change the database name, for example, or to add some tables.

Your project should start PostgreSQL, initialize the database with init.sql (if that hasn't already been done), and load the RBAC library.

Your project can then use the library via the RBAC API.

5 RBAC-PG Class

RBAC-PG Class and Accessors.

  • [class] RBAC-PG RBAC

    RBAC database class for PostgreSQL.

  • [accessor] DB-HOST RBAC-PG (:DB-HOST = "postgres")

    Host name for connecting to the RBAC database.

  • [accessor] DB-NAME RBAC-PG (:DB-NAME = "rbac")

    Name of the RBAC database.

  • [accessor] DB-PASSWORD RBAC-PG (:DB-PASSWORD = "")

    Password for connecting to the RBAC database.

  • [accessor] DB-PORT RBAC-PG (:DB-PORT = 5432)

    Port number for connecting to the RBAC database.

  • [accessor] DB-USER RBAC-PG (:DB-USER = "cl-user")

    User name for connecting to the RBAC database.

  • [accessor] EMAIL-LENGTH-MAX RBAC (:EMAIL-LENGTH-MAX = 128)

    Maximum length of an email address.

  • [accessor] EMAIL-REGEX RBAC (:EMAIL-REGEX = "^[a-zA-Z0-9][-a-zA-Z0-9._%+]+@([a-zA-Z0-9]+)(\\.?[-a-zA-Z0-9])+\\.[a-zA-Z]{2,}$|^no-email$")

    Regex for validation of email address strings.

  • [accessor] PASSWORD-LENGTH-MAX RBAC (:PASSWORD-LENGTH-MAX = 64)

    Maximum length of password string.

  • [accessor] PASSWORD-LENGTH-MIN RBAC (:PASSWORD-LENGTH-MIN = 6)

    Minimum length of password string.

  • [accessor] PASSWORD-REGEXES RBAC (:PASSWORD-REGEXES = (LIST "^[\\x00-\\x7f]+$" "[a-zA-Z]" "[-!@#$%^&*()+={}[]|:;<>,.?/~`]" "[0-9]"))

    List of regular expressions that a valid password must match. Every regex in the list must match.

  • [accessor] PERMISSION-LENGTH-MAX RBAC (:PERMISSION-LENGTH-MAX = 64)

    Maximum length of permission name string.

  • [accessor] PERMISSION-REGEX RBAC (:PERMISSION-REGEX = "^[a-z]([-a-z0-9_.+]*[a-z0-9])*(:[a-z]+)?$")

    Regex for validating permission name strings.

  • [accessor] RESOURCE-LENGTH-MAX RBAC (:RESOURCE-LENGTH-MAX = 512)

    Maximum length of resource name string.

  • [accessor] RESOURCE-REGEX RBAC (:RESOURCE-REGEX = "^[a-zA-Z][-a-zA-Z0-9]*:?[a-zA-Z0-9._/][-a-zA-Z0-9._ /]*$")

    Defaults to an absolute directory path string that ends with /

  • [accessor] ROLE-LENGTH-MAX RBAC (:ROLE-LENGTH-MAX = 64)

    Maximum length of role name string.

  • [accessor] ROLE-REGEX RBAC (:ROLE-REGEX = "^[a-z]([-a-z0-9_.+]*[a-z0-9])*(:[a-z]+)?$")

    Regex for validating role name strings.

  • [accessor] USER-NAME-LENGTH-MAX RBAC (:USER-NAME-LENGTH-MAX = 64)

    Maximum length of user name string.

  • [accessor] USER-NAME-REGEX RBAC (:USER-NAME-REGEX = "^[a-zA-Z][-a-zA-Z0-9_.+]*$")

    Regex for validating user name strings.

6 Functions

Accessors and methods for manipulating RBAC objects.

  • [generic-function] ADD-PERMISSION RBAC PERMISSION &KEY DESCRIPTION

    Add a new permission and returns the ID of the new entry. DESCRIPTION is optional and auto-generated if not provided.

  • [generic-function] ADD-RESOURCE RBAC RESOURCE &KEY DESCRIPTION ROLES

    Add a new resource and returns the ID of the new entry. The resource is automatically linked to the roles in default-resource-roles plus any additional ROLES provided. DESCRIPTION is optional and auto-generated if not provided.

  • [generic-function] ADD-RESOURCE-ROLE RBAC RESOURCE ROLE

    Add an existing role to an existing resource. Returns the ID of the new resource_roles row.

  • [generic-function] ADD-ROLE RBAC ROLE &KEY DESCRIPTION PERMISSIONS

    Add a new ROLE. Description is optional and auto-generated if not provided. If the role name ends with ':exclusive', the role is marked as exclusive, so the EXCLUSIVE parameter is optional. PERMISSIONS is a list of permission names to add to the role, defaulting to *DEFAULT-PERMISSIONS*. All PERMISSIONS must already exist. Returns the new role's ID.

  • [generic-function] ADD-ROLE-PERMISSION RBAC ROLE PERMISSION

    Add an existing permission to an existing role. Returns the ID of the new role_permissions row.

  • [generic-function] ADD-ROLE-USER RBAC ROLE USER

    Add an existing user to an existing role. Returns the ID of the new role_users row.

  • [generic-function] ADD-USER RBAC USER-NAME EMAIL PASSWORD &KEY ROLES

    Add a new user. This creates an exclusive role, which is for this user only, and adds the user to the public and logged-in roles (given by default-user-roles). Returns the new user's ID.

  • [generic-function] ADD-USER-ROLE RBAC USER ROLE

    Add an existing role to an existing user. Returns the ID of the new role_users row.

  • [function] EXCLUSIVE-ROLE-FOR USER-NAME

    Returns the exclusive role for USER-NAME.

  • [generic-function] GET-ID RBAC TABLE NAME

    Returns the ID associated with NAME in TABLE.

  • [generic-function] GET-VALUE RBAC TABLE FIELD &REST SEARCH

    Retrieves the value from FIELD in TABLE where SEARCH points to a unique row. TABLE and FIELD are strings, and SEARCH is a series of field names and values that identify the row uniquely. TABLE, FIELD, and the field names in SEARCH must exist in the database. If no row is found, this function returns NIL.

  • [generic-function] ID-EXISTS-P RBAC TABLE ID

    Returns T when ID exists in TABLE.

  • [generic-function] INITIALIZE-DATABASE RBAC ADMIN-PASSWORD

    Idempotent function that checks if the database, given by RBAC, has been initialized. If not, then this function initializes the database, which involves creating some base permissions, roles, and users. The base permissions are 'create', 'read', 'update', and 'delete'. The base roles are 'admin', 'admin:exclusive', 'logged-in', and 'public'. All of the roles have all the base permissions, except for the 'public' and 'logged-in' roles, which have the 'read' permission only. The base users are 'guest' and 'admin'. The 'guest' user is assigned the 'public' role and the 'admin' user is assigned all of the roles and created with the password ADMIN-PASSWORD. The 'guest' user doesn't need a password, so the bogus value 'guest-password-1' is used. The database is considered initialized the users table contains records, in which case this function does nothing.

  • [generic-function] LIST-PERMISSION-NAMES RBAC &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List of permission names (all permissions by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "permission_name").

  • [generic-function] LIST-PERMISSIONS RBAC &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about permissions (all permissions by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "permission_name").

  • [generic-function] LIST-RESOURCE-NAMES RBAC &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List of resource names (all resources by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "resource_name").

  • [generic-function] LIST-RESOURCE-ROLE-NAMES RBAC RESOURCE &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List names of roles associated with RESOURCE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "role_name").

  • [generic-function] LIST-RESOURCE-ROLES RBAC RESOURCE &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about roles associated with RESOURCE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "role_name").

  • [generic-function] LIST-RESOURCE-USER-NAMES RBAC RESOURCE PERMISSION &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List user names of resources where the user has PERMISSION on the resource. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "u.user_name").

  • [generic-function] LIST-RESOURCE-USERS RBAC RESOURCE PERMISSION &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about resource users where the user has PERMISSION on the resource. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "u.user_name").

  • [generic-function] LIST-RESOURCES RBAC &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about resources (all resources by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "resource_name").

  • [generic-function] LIST-ROLE-NAMES RBAC &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List of role names (all roles by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "role_name").

  • [generic-function] LIST-ROLE-PERMISSION-NAMES RBAC ROLE &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List names of permissions associated with ROLE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "permission_name").

  • [generic-function] LIST-ROLE-PERMISSIONS RBAC ROLE &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about permissions associated with ROLE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "permission_name").

  • [generic-function] LIST-ROLE-RESOURCE-NAMES RBAC ROLE &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List names of resources associated with ROLE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "resource_name").

  • [generic-function] LIST-ROLE-RESOURCES RBAC ROLE &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about resources associated with ROLE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "resource_name").

  • [generic-function] LIST-ROLE-USER-NAMES RBAC ROLE &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List names of users associated with ROLE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "user_name").

  • [generic-function] LIST-ROLE-USERS RBAC ROLE &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about users associated with ROLE. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "user_name").

  • [generic-function] LIST-ROLES RBAC &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about roles (all roles by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "role_name").

  • [generic-function] LIST-USER-NAMES RBAC &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List of user names (all users by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "user_name").

  • [generic-function] LIST-USER-RESOURCE-NAMES RBAC USER PERMISSION &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List resource names of users where the user has PERMISSION on the resource. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "s.resource_name").

  • [generic-function] LIST-USER-RESOURCE-NAMES-OF-TYPE RBAC USER-NAME RESOURCE-TYPE &KEY PERMISSIONS PAGE PAGE-SIZE

    List the names of the resources of type RESOURCE-TYPE that USER-NAME has access to. RESOURCE-TYPE is matched against the prefix of the resource name. Supports pagination via PAGE and PAGE-SIZE. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*.

  • [generic-function] LIST-USER-RESOURCE-PERMISSION-NAMES RBAC USER-NAME RESOURCE-NAME &KEY PAGE PAGE-SIZE

    List the names of the permissions that USER-NAME has on RESOURCE-NAME. Supports pagination via PAGE and PAGE-SIZE. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*

  • [generic-function] LIST-USER-RESOURCES RBAC USER PERMISSION &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about user resources where the user has PERMISSION on the resource. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "s.resource_name").

  • [generic-function] LIST-USER-ROLE-NAMES RBAC USER &KEY PAGE PAGE-SIZE FILTERS ORDER-BY

    List names of roles associated with USER. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "role_name").

  • [generic-function] LIST-USER-ROLES RBAC USER &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about roles associated with USER. Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "role_name").

  • [generic-function] LIST-USERS RBAC &KEY PAGE PAGE-SIZE FIELDS FILTERS ORDER-BY

    List information about users (all users by default). Pagination is supported via the PAGE and PAGE-SIZE parameters. PAGE defaults to 1 and PAGE-SIZE defaults to *DEFAULT-PAGE-SIZE*. The FIELDS parameter, a list of strings, can be used to limit which fields are included in the result. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "user_name").

  • [generic-function] LOGIN RBAC USER-NAME PASSWORD

    If USER-NAME exists and PASSWORD is correct, update last_login for USER-NAME and return the user ID. Otherwise, return NIL.

  • [function] PASSWORD-HASH USER-NAME PASSWORD

    Returns the hash of PASSWORD, using USER-NAME as the salt. This is how RBAC stores the password in the database.

  • [function] PASSWORD-HASH USER-NAME PASSWORD

    Returns the hash of PASSWORD, using USER-NAME as the salt. This is how RBAC stores the password in the database.

  • [generic-function] PERMISSION-COUNT RBAC &KEY FILTERS

    Count the number of permissions (all permissions by default). The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false.

  • [function] RBAC-QUERY SQL-TEMPLATE-AND-PARAMETERS &OPTIONAL (RESULT-TYPE :PLISTS)

    Converts SQL-TEMPLATE-AND-PARAMETERS into a query that returns a list of rows, and executes that query. SQL-TEMPLATE-AND-PARAMETERS is a list where the first element is an SQL string (optionally with placeholders) and the rest of the elements are values that are used to replace the placeholders in the SQL string. This function needs to be called inside of a with-rbac block. Each row in the result is a plist, where the keys represent the field names.

  • [function] RBAC-QUERY-SINGLE SQL-TEMPLATE-AND-PARAMETERS

    Converts SQL-TEMPLATE-AND-PARAMETERS into a query that returns a single value, and executes that query. SQL-TEMPLATE-AND-PARAMETERS is a list where the first element is an SQL string (optionally with placeholders) and the rest of the elements are the values that are used to replace the placeholders in the SQL string. This function needs to be called inside a with-rbac block.

  • [generic-function] REMOVE-PERMISSION RBAC PERMISSION

    Remove PERMISSION from the database. Returns the ID of the removed permission.

  • [generic-function] REMOVE-RESOURCE RBAC RESOURCE

    Remove RESOURCE from the database. Returns the ID of the removed resource.

  • [generic-function] REMOVE-RESOURCE-ROLE RBAC RESOURCE ROLE

    Remove a role from a resource. Returns the ID of the removed resource role.

  • [generic-function] REMOVE-ROLE RBAC ROLE

    Remove a role from the database. Returns the ID of the removed role.

  • [generic-function] REMOVE-ROLE-PERMISSION RBAC ROLE PERMISSION

    Remove a permission from a role. Returns the ID of the removed role-permission.

  • [generic-function] REMOVE-ROLE-USER RBAC ROLE USER

    Remove a user from a role. Returns the ID of the removed role user.

  • [generic-function] REMOVE-USER RBAC USER-NAME

    Remove USER-NAME from the database.

  • [generic-function] REMOVE-USER-ROLE RBAC USER ROLE

    Remove a role from a user. Returns the ID of the removed user role.

  • [generic-function] RESOURCE-COUNT RBAC &KEY FILTERS

    Count the number of resources (all resources by default). The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] RESOURCE-ROLE-COUNT RBAC RESOURCE &KEY FILTERS

    Count the number of roles associated with RESOURCE. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] RESOURCE-USER-COUNT RBAC RESOURCE PERMISSION &KEY FILTERS

    Count the number of resource users where the user has PERMISSION on the resource. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "u.user_name").

  • [generic-function] ROLE-COUNT RBAC &KEY FILTERS

    Count the number of roles (all roles by default). The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] ROLE-PERMISSION-COUNT RBAC ROLE &KEY FILTERS

    Count the number of permissions associated with ROLE. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] ROLE-RESOURCE-COUNT RBAC ROLE &KEY FILTERS

    Count the number of resources associated with ROLE. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] ROLE-USER-COUNT RBAC ROLE &KEY FILTERS

    Count the number of users associated with ROLE. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] USER-ALLOWED RBAC USER-NAME PERMISSION RESOURCE

    Returns T if USER-NAME has PERMISSION on RESOURCE, NIL otherwise. Note that this permission may exist via more than one role.

  • [generic-function] USER-COUNT RBAC &KEY FILTERS

    Count the number of users (all users by default). The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] USER-HAS-ROLE RBAC USER-NAME &REST ROLE

    Returns T if USER-NAME has any of the specified ROLE(s).

  • [generic-function] USER-RESOURCE-COUNT RBAC USER PERMISSION &KEY FILTERS

    Count the number of user resources where the user has PERMISSION on the resource. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, or ilike. Value is a string, number, :null, :true, or :false. The ORDER-BY parameter is a list of strings that represent field names and are used to order the results. It defaults to (list "s.resource_name").

  • [generic-function] USER-ROLE-COUNT RBAC USER &KEY FILTERS

    Count the number of roles associated with USER. The FILTERS parameter can be used to filter the results. It consists of a list of filters, where each filter is a list of three elements: field name, operator, and value. Operator, a string, can be one of =, <>, <, >, <=, >=, is, is not, like, ilike. Value is a string, number, :null, :true, or :false.

  • [generic-function] VALID-DESCRIPTION-P RBAC DESCRIPTION

    Validates new DESCRIPTION string.

  • [generic-function] VALID-EMAIL-P RBAC EMAIL

    Validates new EMAIL string. The string must look like an email address, with a proper domain name, and it must have a length that doesn't exceed 128 characters.

  • [generic-function] VALID-PASSWORD-P RBAC PASSWORD

    Validates new PASSWORD string. PASSWORD must have

    • at least password-length-min characters
    • at least one letter
    • at least one digit
    • at least one common punctuation character
    • at most password-length-max characters

  • [generic-function] VALID-PERMISSION-P RBAC PERMISSION

    Validates new PERMISSION string. PMERISSION must:

    • start with a letter
    • consist of letters, digits, and hyphens
    • optionally have a colon that is not at the beginning or the end
    • contain at most permission-length-max characters

  • [generic-function] VALID-RESOURCE-P RBAC RESOURCE

    Validates new RESOURCE string.

  • [generic-function] VALID-ROLE-P RBAC ROLE

    Validates new ROLE string. ROLE must:

    • start with a letter
    • consist of letters, digits, and hyphens
    • have at most role-length-max characters
    • optionally have a colon that is not at the beginning or the end

  • [generic-function] VALID-USER-NAME-P RBAC USER-NAME

    Validates new USERNANME string. USER-NAME must:

    • Have at least 1 character
    • Have at most user-name-length-max characters
    • Start with a letter
    • Contain only ASCII characters for
      • letters (any case)
      • digits
      • underscores
      • dashes
      • periods
      • plus sign (+)

7 Special Variables

Exported special variables.

  • [variable] *ADMIN* "admin"

    Administrator user name.

  • [variable] *GUEST* "guest"

    Guest user name.

  • [variable] *DEFAULT-PAGE-SIZE* 1000

    Default page size. Used in functions that accept a :page-size parameter when the parameter is not specified.

  • [variable] *DEFAULT-PERMISSIONS* ("create" "delete" "read" "update")

    Default permissions for a new role when no value is provided for the :roles parameter

  • [variable] *DEFAULT-RESOURCE-ROLES* ("admin")

    A list of roles to be used when a resource is created without specifying a value for the :roles parameter.

  • [variable] *DEFAULT-USER-ROLES* ("logged-in" "public")

    A list of roles to be used when a user is first created. These roles are appended to whatever the caller specifies for the :roles parameter.

8 Macros

Exported macros.

  • [macro] WITH-RBAC (RBAC) &BODY BODY

    Opens a connection (pooled) to the rbac database to execute BODY. There's no global connection, so this macro must be used wherever a connection is needed. The connection is closed after BODY is executed.

9 RBAC Development

This section describes tools to improve the efficiency and accuracy of the development of this software.

Tests

The tests are located in rbac-tests.lisp.

Running all the tests

make test

This will start PostreSQL as a Docker container, initialize the database, run all the tests, then stop the database container.

Running a swank server

make test-repl

This will start PostgreSQL as a Docker container, initialize the database, load the RBAC and RBAC-TEST packages, and wait for you to connect with a client such as Slime. This enables you modify the library's code and the tests in a REPL environment. Go Common Lisp!

The tests are in the :rbac-test package. You can run a specific test like this:

(in-package :rbac-test)
(run! 'name-of-test)

The database is cleared at the beginning of each test. Therefore, any changes that the tests makes to the database are available to you after you run the test. For example, if the test adds a user, then after the test ends, you'll find the user among the results of calling (list-user-names *rbac*). The :rbac-tests package uses the :rbac package, so in these types of situation, you don't have to switch to the :rbac package to call list-user-names.

Compiling a function, auto-completion, and so forth all work in the usual way. If you want, you can switch to the :rbac package first. That way, you don't have to worry about some not-yet-exported function being available in the :rbac-test package.

(in-package :rbac)
(list-user-names *rbac*)

When you quit the REPL environment, the PostgreSQL container stops.

GitHub Actions

This project contains a GitHub Action to run tests. It uses make test-ci. The repo is configured to run tests whenever code is pushed to the repo.

Exports

The exported functions are listed in the usual fashion in the package file, rbac-package.lisp, in alphabetical order.

Generating Documentation

This README is generated. The code to generate the README is in rbac-docs.lisp. The MGL-PAX library fetches the documentation strings from the variables, functions, accessors, and macros in the code, and uses them to help build the README.

You can generate the README from the command line with make docs, or by starting a REPL (see "Running a swank server" above) and then calling (generate-readme).

When adding a documentation string to a variable, function, class accessor, or macro, it's important to start the documentation string with ":public:" or ":private:", to indicate if the symbol should be exported. The generate-readme function removes these strings (and the space that follows the string) from the documentation when generating the README.

There's a lot of macro business going on in rbac-docs.lisp. If you don't see some new text you edited appearing in the README after calling generate-readme, simply evaluate the whole buffer. In Emacs, you can do that with M-x slime-eval-buffer, for example.

Exports and documentation checks

When you remove a function from the library, it can be easy to forget to update the documentation or the exports section of the package file. This project provides functions to help ensure that nothing is out of sync. Those functions are in the exports.lisp file. The most important function in that file is check-exports.

The check-exports function returns a plist with the following keys:

  • :missing-in-exports A list of the variables, functions, class accessors, and macros in the :rbac package that have a documentation string that starts with ":public:" and that don't appear in the :exports section of the rbac-package.lisp file.

  • :stale-exports A list of symbols that appear in the :exports section of the rbac-package.lisp file that are not defined in the package, or that no longer have a documentation string that starts with ":public:".

  • :missing-in-docs A list of the symbols that have a documentation string that starts with ":public:" and that do not appear in the rbac-docs.lisp file.

  • :stale-docs A list of the symbols in rbac-docs.lisp that no longer exist or that no longer have a documentation string that starts with ":public:".

Thus, you can easily determine if something is missing from the documentation or the exports.

Summary of make targets

make test

Runs the tests. Run from command line.

make test-ci

Runs the tests. Run from GitHub Actions. (See .github/workflows/ci.yaml.)

make repl

Start a Swank server so that you can connect to RBAC and to the RBAC tests with a REPL. Please note the Swank port number, which this command prints when the server is ready.

make docs

Generate the README.md file.

About

Simple RBAC Libarary in Common Lisp

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors