Skip to content

User management and privileges [v2]

Adrien Castex edited this page Apr 22, 2018 · 2 revisions

User management

The user management is not very defined because it is dependent to the authentication method. The Basic HTTP authentication method can check if a credential is valid by testing the username and the password, but the Digest HTTP authentication method needs to get the list of all users and test for each if the hashed credential is matching.

There are 3 interface and 1 implementations in the server, but you are free to create your own implementations.

interface IUserManager
{
    getDefaultUser(callback : (user : IUser) => void)
}
interface ITestableUserManager
{
    getDefaultUser(callback : (user : IUser) => void)
    getUserByNamePassword(name : string, password : string, callback : (error : Error, user ?: IUser) => void)
}
interface IListUserManager
{
    getUserByName(name : string, callback : (error : Error, user ?: IUser) => void)
    getDefaultUser(callback : (user : IUser) => void)
    getUsers(callback : (error : Error, users ?: IUser[]) => void)
}

class SimpleUserManager implements ITestableUserManager, IListUserManager
{
    constructor();

    getUserByName(name : string, callback : (error : Error, user ?: IUser) => void);
    getDefaultUser(callback : (user : IUser) => void);

    getUsers(callback : (error : Error, users : IUser[]) => void);
    getUserByNamePassword(name : string, password : string, callback : (error : Error, user ?: IUser) => void) : void;

    addUser(name : string, password : string, isAdmin : boolean = false) : IUser;
}

Because the users are stored locally, the SimpleUserManager implementation can be used for both Basic and Digest HTTP authentication methods.

A user

A user is materialized by the IUser interface :

interface IUser
{
    uid : string
    isAdministrator ?: boolean
    isDefaultUser ?: boolean
    username : string
    password ?: string
}

The uid property is the unique identifier of the user. It must never change. It will be used to uniquely identify a user when locking a resource.

The isAdministrator property gives full rights to the user, skipping the privilege checking.

The isDefaultUser property will discriminate the user when the requireAuthentification server's option is set to true.

Privileges

The privileges of a user upon a resource is defined by the instance of the class PrivilegeManager provided in the server's option privilegeManager. This object provides a list of methods to tell the server that a resource is accessible by a user or if it is not. By default, the PrivilegeManager returns true everytime, but you can implement your own privilege manager to check in a database, for instance. You can find a privilege manager implementation with the SimplePathPrivilegeManager which check if a user has the required rights based on the path.

Here is the class PrivilegeManager :

class PrivilegeManager
{
    can(fullPath : Path | string, resource : Resource, privilege : BasicPrivilege, callback : PrivilegeManagerCallback) : void
    can(fullPath : Path | string, resource : Resource, privilege : string, callback : PrivilegeManagerCallback) : void
    can(fullPath : Path | string, resource : Resource, privilege : BasicPrivilege[], callback : PrivilegeManagerCallback) : void
    can(fullPath : Path | string, resource : Resource, privilege : string[], callback : PrivilegeManagerCallback) : void
    protected _can?(fullPath : Path, user : IUser, resource : Resource, privilege : string, callback : PrivilegeManagerCallback) : void

    protected canWrite(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canWriteLocks(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canWriteContent(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canWriteContentTranslated(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canWriteContentSource(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canWriteProperties(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canRead(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canReadLocks(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canReadContent(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canReadContentTranslated(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canReadContentSource(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
    protected canReadProperties(fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) : void;
}

With :

export type PrivilegeManagerCallback = (error : Error, hasAccess : boolean) => void;
export type PrivilegeManagerMethod = (fullPath : Path, user : IUser, resource : Resource, callback : PrivilegeManagerCallback) => void

export type BasicPrivilege = 
      'canWrite'
        | 'canWriteLocks'
        | 'canWriteContent'
            | 'canWriteContentTranslated'
            | 'canWriteContentSource'
        | 'canWriteProperties'
    | 'canRead'
        | 'canReadLocks'
        | 'canReadContent'
            | 'canReadContentTranslated'
            | 'canReadContentSource'
        | 'canReadProperties'

You must not override the can(...) method, but the _can(...) method instead.

Example

// TypeScript
import { v2 as webdav } from 'webdav-server'
// Javascript
const webdav = require('webdav-server').v2;

// User manager (tells who are the users)
const userManager = new webdav.SimpleUserManager();
const user = userManager.addUser('username', 'password', false);

// Privilege manager (tells which users can access which files/folders)
const privilegeManager = new webdav.SimplePathPrivilegeManager();
privilegeManager.setRights(user, '/', [ 'all' ]);

const server = new webdav.WebDAVServer({
    // HTTP Digest authentication with the realm 'Default realm'
    httpAuthentication: new webdav.HTTPDigestAuthentication(userManager, 'Default realm'),
    privilegeManager: privilegeManager
});

server.start(() => console.log('READY'));
Clone this wiki locally