Skip to content

Commit 3d6737e

Browse files
author
Christoph Proeschel
authored
Merge pull request #6 from devcolor/makinde/redo
Substantial Refactor
2 parents ccd5a2a + 7a5f967 commit 3d6737e

13 files changed

Lines changed: 9520 additions & 416 deletions

.eslintrc.json

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "airbnb-base",
3+
"rules": {
4+
"no-underscore-dangle": ["error", { "allow": ["_conditions", "_fields", "_update", "_doc", "_id"] }],
5+
"no-param-reassign": ["error", { "props": false }]
6+
}
7+
}

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ language: node_js
22
services:
33
- mongodb
44
node_js:
5-
- "6.11"
5+
- "8.2.1"
66
before_script:
77
- sleep 15
88
script: npm test

README.md

Lines changed: 105 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -4,29 +4,17 @@
44

55
This plugin allows you to define a custom authorization scheme on your mongoose models.
66

7-
`npm install -S mongoose-authorization`
7+
`npm install --save mongoose-authorization`
88

99

1010
## Getting Started
1111

12-
First you need to add your permissions to your schema.
13-
14-
#### example model
15-
16-
###### *NOTE: It is important you do this before compiling your model*
17-
1812
```javascript
1913
'use strict';
2014
var mongoose = require('mongoose');
21-
var uuid = require('uuid');
15+
var authz = require('mongoose-authorization');
2216

2317
var userSchema = new mongoose.Schema({
24-
user_id: {
25-
type: String,
26-
required: true,
27-
unique : true,
28-
default: uuid.v4()
29-
},
3018
email: {
3119
type: String,
3220
required: true,
@@ -40,11 +28,6 @@ var userSchema = new mongoose.Schema({
4028
type: String,
4129
required: true
4230
},
43-
password: String,
44-
login_attempts: {
45-
type: Number,
46-
default: 0
47-
},
4831
avatar: {
4932
type: String
5033
},
@@ -63,12 +46,12 @@ var userSchema = new mongoose.Schema({
6346
*/
6447
userSchema.permissions = {
6548
defaults: {
66-
read: ['user_id', 'email', 'first_name', 'last_name', 'avatar']
49+
read: [email', 'first_name', 'last_name', 'avatar']
6750
},
6851
admin: {
6952
read: ['status'],
7053
write: ['status'],
71-
save: true
54+
create: true
7255
},
7356
owner: {
7457
read: ['status'],
@@ -77,66 +60,117 @@ userSchema.permissions = {
7760
}
7861
};
7962
80-
userSchema.plugin(require('mongoose-authorization'));
63+
userSchema.plugin(authz);
8164
82-
/*
83-
* Compile model
84-
*/
85-
var users = mongoose.model('users', userSchema);
86-
87-
module.exports = users;
65+
module.exports = mongoose.model('users', userSchema);
8866
```
8967
9068
In the example above we extended the **userSchema** by adding a *permissions* object. This will not persist to your documents.
9169
92-
The permissions object consists or properties that represent your authorization levels (or groups). For each group, there are 4 permissions you can configure.
93-
* `save` (create) - Boolean
70+
The permissions object consists of properties that represent your authorization levels (or groups). For each group, there are 4 permissions you can configure.
71+
* `create` - Boolean
9472
* `remove` - Boolean
95-
* `write` - [array of fields] *NOTE: if `upsert: true`, the group will need to have `save` permissions too*
96-
* `read` (find) - [array of fields]
73+
* `write` - [array of fields] *NOTE: if `upsert: true`, the group will need to have `create` permissions too*
74+
* `read` - [array of fields]
9775
9876
You can also specify a `defaults` group, which represents permissions that are available to all groups.
9977
100-
#### Example Uses
78+
If you need the document in order to determine the correct authorization level for an action, you can place a static `getAuthLevel` function directly in your schema. For applicable actions, this function will be called with a specific document and a payload of data specified in the query. This is useful when the authorization level depends on matching properties of a user with properties of a specific document to determine if *that* user can modify *that* document.
10179
102-
###### *NOTE: If you do not add the authLevel option to your request, the plugin will not attempt to authorize it. This makes it possible for you to handle requests that may not be initiated by a user (eg. system call, batch job, etc.)*
80+
###### *NOTE: The `getAuthLevel` approach does not work for update or remove queries since the document is not loaded into memory.*
10381
104-
***example update***
82+
```javascript
83+
var mongoose = require('mongoose');
10584
106-
You can also specify an array of authentication levels. This would merge the settings of each auth level.
85+
var carSchema = new mongoose.Schema({
86+
make: {
87+
type: String,
88+
required: true,
89+
unique: true
90+
},
91+
model: {
92+
type: String,
93+
required: true
94+
},
95+
year: {
96+
type: Number
97+
},
98+
plate: {
99+
type: String
100+
}
101+
});
107102
108-
```javascript
109-
users.update({user_id: userUpdate.user_id}, userUpdate, {
110-
authLevel: 'admin'
111-
}, function(err, doc) {
112-
if (err) {
113-
//handle error
114-
} else {
115-
//success
116-
}
117-
});
103+
/*
104+
* Make sure you add this before compiling your model
105+
*/
106+
carSchema.permissions = {
107+
defaults: {
108+
read: ['_id', 'make', 'model', 'year']
109+
},
110+
maker: {
111+
write: ['make', 'model', 'year'],
112+
remove: true
113+
},
114+
dealer: {
115+
read: ['plate'],
116+
write: ['plate']
117+
}
118+
};
119+
120+
carSchema.getAuthLevel = function (payload, doc) {
121+
if (payload && doc && payload.companyName === doc.make) {
122+
return 'maker';
123+
}
124+
125+
return 'dealer';
126+
}
118127
```
119128
120-
***example findOneAndUpdate using the newer promise syntax***
129+
In you application code, you could then do the following:
130+
131+
```javascript
132+
Car.find({}, null, { authPayload: { companyName: 'Toyota' } }).exec(...);
133+
134+
// or
135+
136+
myCar.save({ authPayload: { companyName: 'Honda' } });
137+
```
121138
122-
###### *NOTE: the return document will be sanitized based on the group's permissions for `read`*
139+
You can also have the permissions for a specific document injected into the document when returned from a find query using the `permissions` option on the query. The permissions will be inserted into the object using the key `permissions` unless you specify the desired key name as the permissions option.
123140
124141
```javascript
125-
users.findOneAndUpdate({user_id: userUpdate.user_id}, userUpdate)
126-
.exec()
127-
.then(function(doc) {
128-
//success
129-
})
130-
.catch(function(err) {
131-
// handle error
132-
})
142+
const user = await User.find().setOptions({ authLevel: 'admin': permissions: true }).exec();
143+
144+
console.log(user.permissions);
145+
// Outputs:
146+
// {
147+
// read: [...],
148+
// write: [...],
149+
// remove: [boolean]
150+
// }
151+
152+
// OR
153+
const user = await User.find().setOptions({ authLevel: 'admin': permissions: 'foo' }).exec();
154+
155+
console.log(user.foo);
156+
// Outputs:
157+
// {
158+
// read: [...],
159+
// write: [...],
160+
// remove: [boolean]
161+
// }
133162
```
134163
164+
#### Example Uses
135165
136-
***example find***
166+
###### NOTE: If no authLevel is able to be determined, permission to perform the action will be denied. If you would like to circumvent authorization, pass `false` as the authLevel (e.g. `myModel.find().setAuhtLevel(false).exec();`, which will disable authorization for that specific query).
167+
168+
***example update***
169+
170+
You can also specify an array of authentication levels. This would merge the settings of each auth level.
137171
138172
```javascript
139-
users.find({user_id: userUpdate.user_id}, null, {
173+
users.update({user_id: userUpdate.user_id}, userUpdate, {
140174
authLevel: 'admin'
141175
}, function(err, doc) {
142176
if (err) {
@@ -147,32 +181,24 @@ users.find({user_id: userUpdate.user_id}, null, {
147181
});
148182
```
149183
150-
***example findOne***
184+
185+
###### *NOTE: When using `findOneAndUpdate`, the return document will be sanitized based on the group's permissions for `read`*
151186

152187
```javascript
153-
users.findOne({user_id: userUpdate.user_id}, null, {
154-
authLevel: 'admin'
155-
}, function(err, doc) {
156-
if (err) {
157-
//handle error
158-
} else {
159-
//success
160-
}
161-
});
188+
await users.findOneAndUpdate(
189+
{ user_id: userUpdate.user_id },
190+
userUpdate,
191+
{ authLevel: 'admin'}
192+
);
162193
```
163194

164-
***example findOneAndRemove***
165195

166-
###### *NOTE: doc.remove is not supported yet*
196+
***example find***
167197

168198
```javascript
169-
users.findOneAndRemove({user_id: userUpdate.user_id}, {
170-
authLevel: 'admin'
171-
}, function(err) {
172-
if (err) {
173-
//handle error
174-
} else {
175-
//success
176-
}
177-
});
199+
await users.find(
200+
{ user_id: userUpdate.user_id },
201+
null,
202+
{ authLevel: 'admin' }
203+
);
178204
```

0 commit comments

Comments
 (0)