This FAQ provides general information about the term "Access Control" but most definitions are specific to AccessControl.js - how the library is implemented.
In information security, Access Control is selective restriction of access to a resource.
AccessControl.js ...
- defines act of accessing by "actions".
- provides an abstract layer between the application logic and the requested resource and action.
AccessControl.js defines "accessing" by CRUD actions (create
, read
, update
, delete
). It does not specify how an action is performed on the resource. But rather, decides whether the action can be performed by the accessing party: role.
Below is a typical match of AC actions to actual HTTP and database operations:
AccessControl.js | REST/HTTP | Database |
---|---|---|
CREATE |
POST |
INSERT |
READ |
GET |
SELECT |
UPDATE |
PUT or PATCH |
UPDATE |
DELETE |
DELETE |
DELETE |
Most of the time this might be the case; but depending on the context or resource; you could map these actions to completely different operations.
- a
CREATE
might mean sending an SMS to a user. - a
READ
might mean downloading a file. - a
DELETE
in AccessControl logic might mean anUPDATE
in database.
e.g. setting a table field, namedisDeleted
to1
(soft-delete).
and so on...
A resource identifies a unique thing (noun) that's named/referenced and being accessed. This is typically an abstract definition. What the resource actually is; and how that resource is implemented is a design decision, the developer makes.
Depending on the context; a resource can be a document, a database record, an apple, the relationship of two people, fear of dark, a cat breed, a cat, etc...
When defining a resource for AccessControl, the developer should decide whether that "thing"...
- is semantically unique (different than other defined resources),
- requires a distinguished control of access.
For example:
- We have a database table called
accounts
. - The
accounts
table has fields such asfirstName
,lastName
,email
andpwd
. - In our application context, a user can modify
firstName
andlastName
freely. But we'll have a separate page for changing the password and/or email address; which will prompt for current password.
In this scenario, we may have two resources: account
and credentials
ac.grant('user')
.createAny('account') // create new account with all attributes
.updateOwn('account', ['*', '!pwd', '!email']) // update own account except password and email
.updateOwn('credentials') // update own credentials (password and email)
In AccessControl.js, a resource is defined whenever a permission is granted or denied for the first time, for that resource.
ac.can('monkey').createOwn('banana').granted // false
ac.hasResource('banana'); // false
ac.grant('monkey').createOwn('banana'); // resource is defined for the first time
ac.hasResource('banana'); // true
ac.can('monkey').createOwn('banana').granted // true
(MySQL, PostgreSQL, MongoDB, etc..)
AccessControl.js is not coupled with any kind of database system. Actually it's unrelated. It only grants or denies access to a resource. The rest depends on your application's logic and decisions you (the developer) make.
Here is a scenario;
-
Application logic: "Users can assign folders to users."
In the backend, this is done by creating a record in a relational table:folderUsers
-
So, we have 3 tables in our database:
users
,folders
andfolderUsers
-
The relation is established by two fields, in
folderUsers
table:folderId
( foreign-key:folders.id
)userId
( foreign-key:users.id
)
-
In AccessControl, we'll represent this resource as
"fu-relation"
.
And we'll restrict access forcreate
actions performed on this resource.
In this case, we have 4 options.
By creating a fu-relation
resource, a user of this role, can assign...
# | Permission | covers |
---|---|---|
1 | ... own folder to itself (own user ) |
|
2 | ... any folder to itself (own user ) |
1 |
3 | ... own folder to any user |
1 |
4 | ... any folder to any user |
1, 2, 3 |
When you grant or check for a permission via .createOwn()
, you (the developer) should decide what own stands for. So I will make the following decision as the developer.
In this context:
- own
fu-relation
means "ownfolder
to anyuser
" (option # 3) - any
fu-relation
means "anyfolder
to anyuser
" (option #4)
With this decision:
- I don't need to check whether the assigned-user is current (own) user.
- I need to check whether the assigned-folder is own
folder
(implied resource) of the current user.
First I'll define 2 roles; user
and admin
; and grant access permissions accordingly:
ac.grant('user').createOwn('fu-relation')
.grant('admin').createAny('fu-relation');
So when the resource is accessed, I'll check these permissions, and restrict or allow the request:
// psuedo (sync) code
var role = session.role; // role of the requesting user: 'user' or 'admin'
var userIdToBeAssigned = request.params.userId; // can be any user id
var folderId = request.params.folderId;
// First check if current role can create "ANY" fu-relation. (ANY > OWN)
var permission = ac.can(role).createAny('fu-relation');
// if not granted, check if current role can create "OWN" fu-relation:
if (permission.granted === false) {
// Determine whether the implied resource (folder) is "owned"
// by the current user. This is app's responsibility, not AC's.
if (session.userId === getFolder(folderId).userId) {
// We made sure that the implied resource is "owned" by this user.
// Now we can ask AccessControl permission for performing
// the action on the target resource:
permission = ac.can(role).createOwn('fu-relation');
}
}
// Finally, execute the operation if allowed:
if (permission.granted) {
// whatever app-logic here.. e.g.:
db.insert({
table: folderUsers,
row: {
folderId: request.params.folderId,
userId: userIdToBeAssigned
}
});
} else {
// forbidden
console.log('Access Denied!');
}
Granting permissions for valuable resources and managing access levels for user roles... This is a highly sensitive context; in which mostly, any failure or exception becomes critical. So in any case, an AccessControlError
is thrown right away. No silent errors!
In Development:
Hard-test your application with all or most possible use cases, in terms of access management and control. If you see any AccessControlError
thrown you should definitely fix it immediately. Because this typically indicates that your grants model either has a logical or technical flaw.
In Production:
You did all your tests in development but still, if a caught exception is an instance of AccessControlError
, I highly recommend the host application should be gracefully shut down when in production.
For details on errors thrown, see AccessControl Errors section.