Created
January 11, 2017 20:16
-
-
Save oleksmarkh/4f2420b634f1872274fbbf415642ae14 to your computer and use it in GitHub Desktop.
generic access control approach (user + resource [+ action])
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { has } from 'lodash'; | |
// "user" assumed to always represent currently authenticated user | |
// once this assumption isn't sufficient, the politic has to be extended | |
// with something like: | |
// * isCurrentUser(user, currentUser) | |
// * belongsToCurrentUser(user, currentUser, resource) | |
// a "resource" should at least have the "type" attribute for matching purposes | |
// "user" is one possible detalization of a "resource" (e.g. 'const user = {type: "admin", profileId: 1, email: "[email protected]", ...}'), | |
// "profile" is another one (e.g. 'const profile = {type: "profile", id: 1, firstName: "Kobe", ...}') | |
export const ADMIN_TYPE = 'admin'; | |
// export const NORMAL_USER_TYPE = 'normal user'; | |
// export const GUEST_USER_TYPE = 'guest user'; | |
export const PROFILE_TYPE = 'profile'; | |
// @todo: add more resource types | |
const CREATE_ACTION = 'create'; | |
const READ_ACTION = 'read'; | |
const EDIT_ACTION = 'edit'; | |
const REMOVE_ACTION = 'remove'; | |
// type agnostic condition - could be nearly everything | |
export function matchType(resource, type) { | |
return (resource && resource.type === type); | |
} | |
export function isAdmin(user) { | |
return matchType(user, ADMIN_TYPE); | |
} | |
// export function isNormalUser(user) { | |
// return matchType(user, NORMAL_USER_TYPE); | |
// } | |
// export function isGuestUser(user) { | |
// return matchType(user, GUEST_USER_TYPE); | |
// } | |
function isProfile(resource) { | |
return matchType(resource, PROFILE_TYPE); | |
} | |
// @todo: add more possible "is<resource type>(resource)" validators | |
function ownsProfile(user, resource) { | |
if (!isProfile(resource)) { | |
return false; | |
} | |
return (user.profileId === resource.id); | |
} | |
// @todo: add more possible "owns<resource type>(user, resource)" validators | |
// concerned with different resource types | |
export function owns(user, resource) { | |
if (ownsProfile(user, resource)) { | |
return true; | |
} | |
// @todo: extend with possible additional "owns<resource type>(user, resource)" checks | |
return false; | |
} | |
// concerned with different relation types, e.g. (in)direct ownership | |
export function belongsTo(user, resource) { | |
if (owns(user, resource)) { | |
return true; | |
} | |
// @todo: extend the aspect with business logic | |
return false; | |
} | |
// concerned with different action types, e.g. (non)destructive | |
export function hasAccessTo(user, resource, action) { | |
if (action === READ_ACTION) { | |
return true; | |
} | |
// @todo: extend the relation aspect with dangerous actions | |
// by injecting a state sensitive aspect check if needed, | |
// e.g. "isFrozen(resource)" | |
return false; | |
} | |
// authorization: pessimistic (untrusted) politic | |
export function isAllowed(user, resource, action = READ_ACTION) { | |
// authentication (token) isn't concerned here | |
if (!user) { | |
return false; | |
} | |
// god mode | |
if (isAdmin(user)) { | |
return true; | |
} | |
if (!resource) { | |
return false; | |
} | |
if (belongsTo(user, resource)) { | |
return true; | |
} | |
return hasAccessTo(user, resource, action); | |
} | |
export function canCreate(user, resource) { | |
return isAllowed(user, resource, CREATE_ACTION); | |
} | |
export function canRead(user, resource) { | |
return isAllowed(user, resource, READ_ACTION); | |
} | |
export function canEdit(user, resource) { | |
return isAllowed(user, resource, EDIT_ACTION); | |
} | |
export function canRemove(user, resource) { | |
return isAllowed(user, resource, REMOVE_ACTION); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment