- Notifications
You must be signed in to change notification settings - Fork1
Policy Machine for Role Based Access Control
License
ojkelly/wahn
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
Policy Machine for Role Based Access Control
Designed for use with theBunjil GraphQL server, Wahn is flexible policy based authorization engine. It is inpsired by other policy engines including AWS IAM.
yarn add wahn
npm install wahn
// Typescriptimport{Wahn,Policy,PolicyAction,PolicyOperator}from"wahn";// Define a policyconstpolicy:Policy={// This is a simple policy with only one resourceresources:["test::resource"],// You can either Allow or Deny accessaction:policyAction.Allow,// This policy is then attached to the role `authenticated user`roles:["authenticated user"],};// Now we create a Wahnconstwahn:Wahn=newWahn({policies:[policy],});
// javascriptimport{Wahn}from"wahn";// Define a policyconstpolicy={// This is a simple policy with only one resourceresources:["test::resource"],// You can either `Allow` or `Deny` accessaction:"Allow",// This policy is then attached to the role `authenticated user`roles:["authenticated user"],};// Now we create a Wahnconstwahn=newWahn({policies:[policy],});
Now you have anWahn
instance with policies, you can attempt to access something.
// typescriptimport{RequestContext}from"wahn";// In your request you will have information about the user, their roles,// and possibly other information about their session, like their// OS or IP// You pass these to `wahn` during your evaluateAccess check via the// context objectconstcontext:RequestContext={user:{id:"UserId",roles:["authenticated user"],},};// Now lets check if our user has access to our test resourceconsthasAccess:boolean=wahn.evaluateAccess({ context,resource:"test::resource",});// hasAccess === true// Now lets check if our user has access to a different resourceconsthasAccess:boolean=wahn.evaluateAccess({ context,resource:"AResourceTheUserCannotAccess",});// throws AuthorizationDeniedError
//javascriptimport{RequestContext}from"whan";// In your request you will have information about the user, their roles,// and possibly other information about their session, like their// OS or IP// You pass these to `wahn` during your evaluateAccess check via the// context objectconstcontext={user:{id:"UserId",roles:["authenticated user"],},};// Now lets check if our user has access to our test resourceconsthasAccess=wahn.evaluateAccess({ context,resource:"test::resource",});// hasAccess === true// Now lets check if our user has access to a different resourceconsthasAccess=wahn.evaluateAccess({ context,resource:"AResourceTheUserCannotAccess",});// throws AuthorizationDeniedError
You can view thePolicy
type detailed type information, below is the plain JSON version.
{// A action represents the object an action is being performed on.// In the example below we have two GraphQL paths.// The resource and verb are both combined here. actions:["query::User:*","query::Posts:*","mutation::createPost"]// There are only two types of effects on the policy Allow and Deny effect:"Allow",// Conditions allow futher refinement of the policy, and final outcome.conditions:[{// A dot path to the value on the context objectfield:"${user.id}",operator:"match",// or "notMatch"expected:["user.id"],}],// Resources are whats being actioned onresources:[// User and all it's fields"User:*",// Or a wildcard for everything"*"]// Roles are what the policy is attached to roles:["authenticated user","subscriber"]}
Conditions provide a powerful way to refine access on a Policy.wahn
makes no assumptions aboutyour implementation, and so the implementation of conditions is partially dependent on your impelmenation.
A condition scopes a Policy to values you provide in the context object.
When you define aCondition
there are 3 parameters:
field
: a dot path to the key on yourcontext
object.expected
: the value you expect to see (hard coded into the policy)expectedOnContext
: a dot path to the expected value on yourcontext
object.value on the context objectoperator
:match
,notMatch
,lessThan
,greaterThan
You can now add adenyType
string to your deny policy to provide information to your client,about how to resolve the deny.
The following simple example shows a policy denying with adenyType
ofmfa-required
whichcan instruct the client to prompt for a MFA token.
// Assemble our policyconstpolicy:Policy={id:"uuid",resources:["resource"],actions:["action"],effect:PolicyEffect.Deny,denyType:"mfa-required",conditions:[{field:"user.sessionAge",operator:PolicyOperator.greaterThan,expected:[600],},],roles:["authenticated user"],};
Useyarn tests
ornpm run tests
.
Tests are written withava
, and we would strongly like tests with any new functionality.
wahn
needs to be as performant as possible. We usewahn
to keep track of performancechanges. Any new functionality cannot increase the performance beyond resonable limits.
Wahn could either be integrated into your application, or setup as astandalone server.
Please readCONTRIBUTING.md for details on our code of conduct, and the process for submitting pull requests to us.
We useSemVer for versioning. For the versions available, see thetags on this repository.
- Owen Kelly -ojkelly
This project is licensed under the MIT License - see theLICENSE.md file for details
- Inspired in part by AWS IAM, NIST RBAC
- Behind the name
About
Policy Machine for Role Based Access Control