Coder Social home page Coder Social logo

reactioncommerce / meteor-security Goto Github PK

View Code? Open in Web Editor NEW
258.0 33.0 21.0 66 KB

A Meteor package: Logical MongoDB security

Home Page: https://atmospherejs.com/ongoworks/security

License: MIT License

JavaScript 100.00%
meteor deny-rules collectionfs

meteor-security's Introduction

ongoworks:security

A Meteor package that provides a simple, logical, plain language API for defining write security on your MongoDB collections. Wraps the core allow/deny security.

SUMMARY OF CHANGES IN 2.0

  1. BREAKING: This package no longer automatically sets up allow and deny functions for you. This allows people to use it for the Security.can feature but not necessarily enable client-side write operations. To keep the old behavior when updating to 2.0, simply change all of your apply() to allowInClientCode(). Otherwise if you do not want it to set up allow and deny functions for you, remove the .apply() part of your chains.
  2. You can track simple read security now using Security.can(userId).read(doc).for(myCollection). For publications, though, it is usually a better idea to filter your queries rather than check security.
  3. When using defineMethod, we now recommend passing an allow function rather than a deny function because it is easier to reason about. However, the internal logic has not changed; client-side writes are still secured using deny functions if turned on. Also, deny functions in defineMethod continue to be supported for now.
  4. When using Security.can, you can now pass the id to update, remove, or read rather than the doc. It had been documented that you could pass that id, but that did not actually work. Now you can pass either the id or the doc and if you pass the id, the doc will be retrieved, fetching only the properties required by fetch.

Installation

$ meteor add ongoworks:security

How It Works

Call permit to begin a new rule chain. Then optionally call one or more restriction methods. Here are some examples:

/server/security.js:

// Anyone may insert, update, or remove a post without restriction
Posts.permit(['insert', 'update', 'remove']);

// No one may insert, update, or remove posts
Posts.permit(['insert', 'update', 'remove']).never();

// Users may insert posts only if they are logged in
Posts.permit('insert').ifLoggedIn();

// Users may remove posts only if they are logged in with an "admin" role
Posts.permit('remove').ifHasRole('admin');

// Admin users may update any properties of any post, but regular users may
// update posts only if they don't try to change the `author` or `date` properties
Posts.permit('update').ifHasRole('admin');
Posts.permit('update').ifLoggedIn().exceptProps(['author', 'date']);

Built-In Rule Chain Methods

  • never() - Prevents the database operations from untrusted code. Should be the same as not defining any rules, but it never hurts to be extra careful.
  • ifLoggedIn() - Allows the database operations from untrusted code only when there is a logged in user.
  • ifHasUserId(userId) - Allows the database operations from untrusted code only for the given user.
  • ifHasRole(role) - Allows the database operations from untrusted code only for users with the given role. Using this method requires adding the alanning:roles package to your app. If you use role groups, an alternative syntax is ifHasRole({role: role, group: group})
  • onlyProps(props) - Allows the database operations from untrusted code for the given top-level doc properties only. props can be a string or an array of strings.
  • exceptProps(props) - Allows the database operations from untrusted code for all top-level doc properties except those specified. props can be a string or an array of strings.

Checking Your Rules in a Method

Security.can allows you to check your rules in any server code.

Insert syntax:

if (Security.can(userId).insert(doc).for(MyCollection).check()) {}
// OR
Security.can(userId).insert(doc).for(MyCollection).throw();

If you pass additional arguments to insert, they will be in the arguments passed to the allow functions of the defined methods.

Update syntax:

if (Security.can(userId).update(id || currentDoc, modifier).for(MyCollection).check()) {}
// OR
Security.can(userId).update(id || currentDoc, modifier).for(MyCollection).throw();

If the first argument is an ID, the doc will be retrieved for you. If you already have the current document, pass that. If you pass additional arguments to insert, they will be in the arguments passed to the allow functions of the defined methods.

Remove syntax:

if (Security.can(userId).remove(id || currentDoc).for(MyCollection).check()) {}
// OR
Security.can(userId).remove(id || currentDoc).for(MyCollection).throw();

If the first argument is an ID, the doc will be retrieved for you. If you already have the current document, pass that. If you pass additional arguments to insert, they will be in the arguments passed to the allow functions of the defined methods.

Read syntax:

if (Security.can(userId).read(id || currentDoc).for(MyCollection).check()) {}
// OR
Security.can(userId).read(id || currentDoc).for(MyCollection).throw();

If the first argument is an ID, the doc will be retrieved for you. If you already have the current document, pass that. If you pass additional arguments to insert, they will be in the arguments passed to the allow functions of the defined methods.

For example, say you have a method that will insert a post and then increment a counter in the user's document. You do not want to do either unless both are allowed by your security rules.

Meteor.methods({
  insertPost: function (post) {
    check(post, Schemas.Post);

    Security.can(this.userId).insert(post).for(Post).throw();

    var userModifier = {
      $inc: {
        postsCount: 1
      }
    };
    Security.can(this.userId).update(this.userId, userModifier).for(Meteor.users).throw();

    var postId = Post.insert(post);

    Meteor.users.update(this.userId, userModifier);

    return postId;
  }
});

Applying Your Rules to Client-Side Writes

In Meteor, turning on client-side writes usually involves defining allow and/or deny functions. Instead, you can use your rules defined by this package as your allow and deny functions. To do so, add allowInClientCode() to the end of your chain:

Posts.permit('update').ifLoggedIn().exceptProps(['author', 'date']).allowInClientCode();

This will automatically define the proper allow/deny rules for you.

API

Note: This entire API and all rule methods are available only in server code. As a security best practice, you should not define your security rules in client code or in server code that is sent to clients. Meteor allow/deny functions are documented as server-only functions, although they are currently available in client code, too.

Security.permit(types)

If you want to apply the same rule to multiple collections at once, you can do

Security.permit(['insert', 'update']).collections([Collection1, Collection2])...ruleChainMethods();

which is equivalent to

Collection1.permit(['insert', 'update'])...ruleChainMethods();
Collection2.permit(['insert', 'update'])...ruleChainMethods();

Security.defineMethod(name, definition)

Call Security.defineMethod to define a method that may be used in the rule chain to restrict the current rule. Pass a definition argument, which must contain a deny property set to a deny function for that rule. The deny function is the same as the standard Meteor one, except that it receives a type string as its first argument and the second argument is whatever the user passes to your method when calling it. The full function signature for inserts and removes is (type, arg, userId, doc) and for updates is (type, arg, userId, doc, fields, modifier).

As an example, here is the definition for the built-in ifHasUserId method:

Security.defineMethod('ifHasUserId', {
  fetch: [],
  transform: null,
  allow(type, arg, userId) {
    return userId === arg;
  },
});

And here's an example of using the doc property to create a method that can be used with Meteor.users to check whether it's the current user's document:

Security.defineMethod('ifIsCurrentUser', {
  fetch: [],
  transform: null,
  allow(type, arg, userId, doc) {
    return userId === doc._id;
  },
});

Transformations

If a rule is applied to a collection and that collection has a transform function, the doc received by your rule's deny function will be transformed. In most cases, you will want to prevent this by adding transform: null to your rule definition. Alternatively, you can set transform to a function in your rule definition, and that transformation will be run before calling the deny function.

Fetch

It's good practice to include fetch: [] in your rule definition, listing any fields you need for your deny logic. However, the fetch option is not yet implemented. Currently all fields are fetched.

Security.Rule

An object of this type is returned throughout the rule chain.

Details

  • Simply adding this package to your app does not affect your app security in any way. Only calling apply on a rule chain for a collection will affect your app security.

  • If you have not defined any rules for a collection, nothing is allowed (assuming you have removed the insecure package).

  • It is fine and often necessary to apply more than one rule to the same collection. Each rule is evaluated separately, and at least one must pass.

  • You can mix 'n' match allowInClientCode rules with normal allow/deny functions, but keep in mind that your allow functions may have no effect if you've called Security apply for the same collection.

  • If you want to use this with the Meteor.users collections, use the Security.permit() syntax. Working example:

    Security.permit(['insert', 'update', 'remove']).collections([ Meteor.users ]).never().allowInClientCode();

Logic

Rules within the same chain combine with AND. Multiple chains for the same collection combine with OR. In other words, at least one chain of rules must pass for the collection-operation combination. They are evaluated in the order they are defined. As soon as one passes for the collection-operation, no more are tested.

For example:

// You can remove a post if you have admin role
Posts.permit('remove').ifHasRole('admin');
// OR You can remove a post if you are logged in AND you created it AND it is not a Friday
Posts.permit('remove').ifLoggedIn().ifCreated().ifNotFriday();
// If neither of the above are true, the default behavior is to deny removal

Examples

Example 1

Here's how you might make your own rule that ensures the ownerId property on a document is set to the current user.

Security.defineMethod('ownsDocument', {
  fetch: [],
  allow(type, field, userId, doc) {
    if (!field) field = 'userId';
    return userId === doc[field];
  }
});

And then you can use it like this:

Posts.permit(['insert', 'update']).ownsDocument('ownerId');

Which means:

  • "A user can insert a post from a client if they set themselves as the author"
  • "A user can update a post from a client if they are currently set as the author."

Using with CollectionFS

This package supports the special "download" allow/deny for the CollectionFS packages, but you must use the Security.permit syntax rather than myFSCollection.permit. For example:

Security.permit(['insert', 'update', 'remove']).collections([Photos]).ifHasRole('admin').allowInClientCode();
Security.permit(['download']).collections([Photos]).ifLoggedIn().allowInClientCode();

Client/Common Code

You can call this package API in common code if you need to. When running on the client, the functions are simple stubs that do not actually do anything.

Contributing

You are welcome to submit pull requests if you have ideas for fixing or improving the API. If you come up with generally useful security rules, you should publish your own package that depends on this one and document the rules it provides so that others can use them. You may then submit a pull request to add a link to your package documentation in this readme.

meteor-security's People

Contributors

aaronjudd avatar aldeed avatar dr-dimitru avatar jshimko avatar macsj200 avatar ubald avatar workflow avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

meteor-security's Issues

[feature request] onlyProps() Nested properties support

It would be great if onlyProps() supported nested properties. Let's say I have an object containing users data, but I want to publish only some of them for example nickname, avatar, but hide user ID and user email.

At the moment I use a workaround - I call this.unset() method in the simpleSchema autoValue() callback.

Defined method's doc is not fetched when using Security.can()

When using Security.can() inside a Meteor method and implementing a custom Security.defineMethod(), the deny's function doc argument is the id passed to Security.can(this.userId).update(id, modifier)...

Either this is the expected behavior and the documentation should reflect this or it should be implemented and is a bug.

Thanks!

Can Read?

Hi, I'm not sure if this needs to be an issue or if I'm missing something. Is there any way to set the permission of Collection.permit('read') and reference the permission in Security.can(userId).read(Collection)? Thanks.

The collections argument must be a Mongo.Collection instance or an array of them

When I do:

MyCollection = new Mongo.Collection('myCollection');
...
MyCollection.permit('insert').ifLoggedIn().apply();

I get:

Error: The collections argument must be a Mongo.Collection instance or an array of them
W20150218-11:27:35.768(-5)? (STDERR)     at SecurityRuleConstructor.Security.Rule.collections (packages/ongoworks:security/security-api.js:45:1)
W20150218-11:27:35.769(-5)? (STDERR)     at [object Object].Mongo.Collection.permit (packages/ongoworks:security/security-api.js:101:1)
W20150218-11:27:35.769(-5)? (STDERR)     at app/server/security/global.js:7:16
W20150218-11:27:35.769(-5)? (STDERR)     at /root/database/.meteor/local/build/programs/server/boot.js:212:5

This collection is instantiated inside a local package, with ongoworks:security as a dependency. Oddly enough when I do this following code in a server startup code:

Meteor.startup(function () {
  var test = new Mongo.Collection('wtfisgoingon');
  test.attachSchema(new SimpleSchema({
    wtf: {
      type: String
    }
  }));
  test.helpers({
    yo: function () {
      return 'waddup'
    }
  });
   test.permit('insert').ifLoggedIn().apply();
});

This works just fine.

Compatibility with CollectionFS

Images is an FS.Collection.

Images.permit(['insert']).apply() throws TypeError: Object #<EventEmitter> has no method 'permit'. No surprise since Images is not a Mongo.Collection.
Images.files.permit(['insert']).apply() seems to work.
Images.files.permit(['download']).apply() throws TypeError: Cannot convert null to object.

It would be great to be able to use these packages together in some fashion.

Security issue with update and remove

Let's say I follow Example 1 from the Readme:

Posts.permit(['insert', 'update']).ownsDocument('ownerId');

I want only user who created the post to be able to update it.

How would I check it in meteor's 'posts.update' method?

If I do:

'posts.update'(post) {
  Security.can(this.userId).update(post).for(Posts).throw();
  return Posts.update({ _id: post._id }, { $set: post });
}

This should work, right?
Except for the most malicious case when attacker sends this kind of post document:

Meteor.call('posts.update', {
  _id: 'someIdAttackerDoesNotOwn',
  ownerId: 'attackerId'
});

The above security check will pass and attacker will successfully change ownerId to his own id.

Same goes for remove check. It would pass and attacker would succeed to remove a record he doesn't own.

Let's say we want to fix this by always providing only post._id to update method.
This could work, but only if we allow users to modify all the post's fields (even fields like "visible", "createdAt", "featured", "commenterIds", etc.

The only solution, if we wanted to use onlyProps and ownsDocument would be to have two if checks:

'posts.update'(post) {
  // fetch post from db and check user can change it (he can't provide fake ownerId)
  !Security.can(this.userId).update(post._id).for(Posts).throw();
  // check user is authorized to update all fields he's trying to update
  !Security.can(this.userId).update(post).for(Posts).throw();
  return Posts.update({ _id: post._id }, { $set: post });
}

Am I missing something?

Should this be added as a warning to the documentation?

EDIT: If I'd have even more complicated case, even this wouldn't work.
Let's say I'm an attacker and I have an e-commerce website on Meteor SaaS e-commerce platform. Let's call it Meterify. Meterify has an order document model:

order: {
  paymentStatus: ['pending', 'paid', ...],
  shipmentStatus: ['pending', 'shipped', ...]
}

When I receive a new order, in administration panel, I can capture payment (which will, if everything goes well, charge customer and change the paymentStatus from 'pending' to 'paid').

Here are hypothetical Meterify's security rules:

Orders.permit('update').ifShopOwner().ifPaymentPending().onlyProps('paymentStatus');
// we want to prevent shop owners from reverting payment status to `'pending'`,
// to possibly capture payments multiple times, when they are updating shipment status:
Orders.permit('update').ifShopOwner().ifShipmentPending().onlyProps('shipmentStatus');

Let's say there's this order in the db:

order: {
  _id: '1234567890',
  paymentStatus: 'paid',
  shipmentStatus: 'pending'
}

I could still call 'orders.update' and revert payment status to 'pending' like this:

Meteor.call('posts.update', {
  _id: '1234567890',
  paymentStatus: 'pending'
}

Both of the above checks will pass and I'll be able to collect payment again.

This is just one example where user can modify certain document fields only at document's (or user's) certain state. Another possible example that comes to mind would be in an online game:

Fleet.permit('update').ifNotOnAMission().onlyProps('equipment');
Fleet.permit('update').ifOnAMission().onlyProps('directions');

Am I still making sense? :)

What do you suggest would be the easiest solution?
I think it would require to be able to do checks on the original db object:

Security.defineMethod('ifNotOnAMission', {
  fetch: [],
  transform: null,
  allow(type, arg, userId, doc, originalDoc) {
    return originalDoc.isOnAMission === false;
  },
});

Way to go about updating from a collection hook

Hello there, I am currently using Astronomy events (would be the same with collection2-hooks though) to handle my relations.

I have a collection Posts like that : { _id: string, user_id: string, content: string, comments_ids: array }
And a Comments collection : { _id: string, user_id: string, content: string }

In my Comments collection I have an afterInsert hook that updates the Posts#comments_ids. The issue here is that I have the following permissions:

// ...
 Collections.Posts.permit(['update']).ifLoggedIn().ifCurrentUserOwnsRessource().allowInClientCode();
 Collections.Comments.permit(['update']).ifLoggedIn().ifCurrentUserOwnsRessource().allowInClientCode();

Which works well except in this peculiar case because when the comment is inserted, it triggers the Posts update which doesn't have the same user_id thus ifCurrentUserOwnsRessource() fails and I can't update my post.

Any clue on how to solve this issue ?

Thanks a lot

PS: Basicaly got the same issue with my cascading removes, etc...

Not working with Meteor.users collection?

Hi,

first of all thx for this awesome package!

Not sure if I'm missing something here,
but it would seem that I cannot use it with the special Meteor.users collection.

Running

Meteor.users.permit(['insert', 'update', 'remove']).never().apply();

Results in

W20150201-19:01:07.771(1)? (STDERR) TypeError: Object [object Object] has no method 'permit'
W20150201-19:01:07.771(1)? (STDERR)     at app/server/security/users.js:2:14

Don't work, I base on `[email protected] + Vue`

I base on [email protected] + Vue:

<template>...... Form....... </template>
--------------
// imports/api/posts/methods
export const insertPost = new ValidatedMethod({
    name: 'posts.insert',
    mixins: [CallPromiseMixin],
    validate: null,
    run(doc) {
        if (!this.isSimulation) {
            return Posts.insert(doc);
        }
    }
});
------------
// server/security
Posts.permit('insert').never();

But I can insert posts.
Please help me.

'permit' is not defined in client code

I'm getting the same error as another user. I'm on Meteor 1.0.2:

Located in lib/collections/appointments.js

Appointments = new Mongo.Collection('appointments');

var Schemas = {};

Schemas.Appointment = new SimpleSchema({
  date: {
    type: Date,
    label: "Date",
    autoform: {
      value: new Date()
    }
  },
  patientId: {
    type: String,
    autoform: {
      type: "hidden",
      options: [
        {label: "", value: "Hello"}
      ]
    }
  },
  doctorId: {
    type: String,
    autoform: {
      type: "hidden"
    }
  },
  reason: {
    type: String,
    label: "Reason for Visit"
  },
  treatment: {
    type: String,
    label: "Treatment",
    optional: true,
    autoform: {
      rows: 10
    }
  },
  notes: {
    type: String,
    label: "Additional Notes",
    optional: true,
    autoform: {
      rows: 10
    }
  },
  price: {
    type: Number,
    label: "Price",
    optional: true
  },
  transactionId: {
    type: String,
    label: "Transaction ID",
    optional: true
  }
});

Appointments.attachSchema(Schemas.Appointment);

Appointments.permit(['update', 'remove']).apply();

I look into the Appointments object and permit isn't available.

This is my packages file:

mizzao:bootstrap-3
underscore
sacha:spin
accounts-password
ian:accounts-ui-bootstrap-3
audit-argument-checks
iron:router
standard-app-packages
aldeed:autoform
aldeed:collection2
email

ongoworks:security
alanning:roles
aldeed:simple-schema
cfs:standard-packages
cfs:s3
dbarrett:dropzonejs
aslagle:reactive-table

From meteor list

accounts-password            1.0.5  Password support for accounts
alanning:roles               1.2.13  Role-based authorization
aldeed:autoform              4.2.1  Easily create forms with automatic insert and update, and automatic reactive validation.
aldeed:collection2           2.3.0  Automatic validation of insert and update operations on the client and server.
aldeed:simple-schema         1.2.0  A simple schema validation object with reactivity. Used by collection2 and autoform.
aslagle:reactive-table       0.5.9  A reactive table designed for Meteor
audit-argument-checks        1.0.2  Try to detect inadequate input sanitization
cfs:s3                       0.1.1  Amazon Web Services S3 storage adapter for CollectionFS
cfs:standard-packages        0.5.3  Filesystem for Meteor, collectionFS
dbarrett:dropzonejs          3.10.3  Dropzone.js - an open source library that provides drag'n'drop file uploads with image previews
email                        1.0.5  Send email messages
ian:accounts-ui-bootstrap-3  1.2.5  Bootstrap-styled accounts-ui with multi-language support.
iron:router                  1.0.6  Routing specifically designed for Meteor
mizzao:bootstrap-3           3.3.1_1  HTML, CSS, and JS framework for developing responsive, mobile first projects on the web.
ongoworks:security           1.0.1  Logical security for client-originated MongoDB collection operations
sacha:spin                   2.0.4  Simple spinner package for Meteor
standard-app-packages        1.0.4  Moved to meteor-platform
underscore                   1.0.2  Collection of small helpers: _.map, _.each, ...

Thanks!

Object has no method 'permit' after adding package.

Added basic package. Used standard permit construct on existing collection in common.js code.
Did this after attachSchema to insure collection exists.
Permit method NOT added to collection.

terminal log attached

screen shot 2014-12-10 at 6 28 20 pm

-------- Common.js ------------

Trips = new Mongo.Collection("trip_db");

console.log("creating Customers collection");
Customers = new Mongo.Collection("customers_db");

SimpleSchema.debug = true;

var Schemas = {};

Schemas.Customer = new SimpleSchema({
organization: {
type: String,
label: "Organization",
max: 200
},
admin_email: {
type: String,
label: "Admin Email"
},
locations:
{
type: String,
label: "Location",
max: 40
}

});

console.log("my Customer Schemas " + Schemas.Customer);
Customers.attachSchema(Schemas.Customer);

// Use ongoworks/security Any client may insert, update, or remove a post without restriction
Customers.permit(['insert', 'update', 'remove']).apply();

// Use standard allow - always return true to start - NO user validation yet
Customers.allow ({
insert: function (userId, document) {
console.log (' Customers.allow (): userId: ', userId, '; document: ', document, ' created by ', document.createdBy);
return true;
}
});

Not working when trying to limiting subproperties modifications

When trying to prevent updates on several properties of an object, found that properties inside properties is not working like in the following example:

Security.permit(['update']).collections([Meteor.users]).exceptProps(['profile.wallet', 'roles']).apply()

'roles' works as expected but 'profile.wallet' does not work, if I try with 'profile' it just works fine, but I have the need of letting other properties of 'profile' to be permited to update but not 'profile.wallet'.

I'm doing something wrong?
Is there any workaround?
Juan.

1.3.0 not working with Meteor.roles

First of all, thanks for this package! ๐Ÿ˜ƒ
This line used to work before 1.3.0:

Security.permit(['insert', 'remove', 'update']).collections([Meteor.roles]).ifHasRole('admin').apply();

I think this line is responsible for the error and I think that this issue is related to #23

.allowInClientCode() unexpectedly applies to all rules of that type

I've just noticed that .allowInClientCode() applies to all the rules of that type instead of just the rule to which it was chained. So in the following example, somebody with the "user" role will also be able to insert or remove documents for Collection from the client-side, even though the .allowInClientCode() method was only called for the rule concerning the "administrator" role (he still cannot update though):

Collection
  .permit( [ "insert", "update", "remove" ] )
  .ifHasRole( {
    role: "administrator",
  } )
  .allowInClientCode();

Collection
  .permit( [ "insert", "remove" ] )
  .ifHasRole( {
    role: "user",
  } );

Is this by design? If so, maybe it should probably be made clear in the documentation because it definitely caught me by surprise.

Multiple CollectionFS`s support

I'm using cfs:[email protected] (installed it version via meteor add cfs:filesystem, also didn't test with 0.1.1 or ealrier) and having some problems:

(1) Images.files.permit(['download']).apply() returns next error:

W20150330-20:25:57.663(3)? (STDERR) Error: allow: Invalid key: download
W20150330-20:25:57.665(3)? (STDERR)     at packages/mongo/collection.js:723:1
W20150330-20:25:57.666(3)? (STDERR)     at Array.forEach (native)
W20150330-20:25:57.667(3)? (STDERR)     at Function._.each._.forEach (packages/underscore/underscore.js:105:1)
W20150330-20:25:57.668(3)? (STDERR)     at [object Object].addValidator (packages/mongo/collection.js:721:1)
W20150330-20:25:57.668(3)? (STDERR)     at [object Object].Mongo.Collection.allow (packages/mongo/collection.js:769:1)
W20150330-20:25:57.669(3)? (STDERR)     at packages/ongoworks:security/security-util.js:39:1
W20150330-20:25:57.671(3)? (STDERR)     at Array.forEach (native)
W20150330-20:25:57.672(3)? (STDERR)     at Function._.each._.forEach (packages/underscore/underscore.js:105:1)
W20150330-20:25:57.673(3)? (STDERR)     at addFuncForAll (packages/ongoworks:security/security-util.js:38:1)
W20150330-20:25:57.673(3)? (STDERR)     at packages/ongoworks:security/security-util.js:56:1

(2) Images.permit(['download']).apply() not working either

(3) Security.permit(['download']).collections([Images.files, Audios.files]).apply() fails with same error as (1)

(4) Security.permit(['download']).collections([Images, Audios]).apply() works, but actually set rules only for first collection in array (Images in example)

My temporary (cause I doubt I fixed it properly, but at least it works) solution to (4):

FSCollection object seems have no _name property, but have name. I mean, here c._name is undefined, and c.name is actual FSCollection (not mongo collection, which looks like cfs.filesystem.images and stored in Images.files._name property) name (i.e. 'images' or 'audio'). This leads to wrong assignment on 59th line (it creates object {undefined: true} cause c._name is undefined) and therefor in future not processing any collections except first one or whatever.

So, to fix it one can change c._name to c._name || c.name on lines 54 and 59 in security-util.js file.

Also I did suppose something like c.files && c.files._name || c._name || c.name should work too, but it changes nothing (haven't investigated why). it works when permitting 'download' like wrote in upd. section

upd.:
To make my "hack" work seems like .collections method should be called separately for each collection, i.e.:

Security.permit(['download']).collections([Images]).apply();
Security.permit(['download']).collections([Audios]).apply();

Again, have no idea why

Client-side Security....check() always returns true

Expected behaviour is that Security....check() returns false on client-side.

Code for server and client:

const Users = Meteor.users;
const permissions = ['read','insert','update','remove'];
const collections = [Users,Posts];

Security.permit(permissions).collections(collections).never().allowInClientCode();

Code for client:

console.log(Security.can(user._id).read().for(Users).check()) // logs: true

Tried a lot of different things, but somehow on the Client-side it always returns true.
Server-side it's returning false, as expected.

how to use dynamic role with security?

For example I have 2 user like:

// user 1
username: 'test1'
user.roles = ['post.insert']

// user 2
username: 'test2'
user.roles = ['post.insert', 'post.update']

So I need to pass dynamic variable to role on security via user log in.

// Check user role
var role = .........
Posts.permit('remove').ifHasRole({role: role}).apply();

How to solve?

Question - .ifLoggedIn()

The .ifLoggedIn() method this means that for example only the logged in user can create a post, so if I'm logged in I can create my own post or edit my own post no one else can is that correct?

Meteor-security for methods?

Hello,

Does something similar exist for methods?
E.g. something like:

permit('METHODNAME').ifLoggedIn().ifCreated().apply();

meaning that the method can only be called if it passes through these checks, each check would then probably need to have the methods parameters somewhere on the scope or on this...

Document is inserted then removed

This condition is true -> if( Security.can( this.userId ) .insert( Document ) .for( collection ).check() === true) For which the document is inserted but running collection.find().fetch() on the server the collection is empty it seems like it is deleted where am i goin wrong here

Question about more than one rule to the same collection

If I have the following rules setup and lets the first one pass but the second does not, does it stop the insert from happing? Or if just one passes it still runs?

Posts.permit('insert').ifLoggedIn().apply();
Posts.permit('insert').ifHasRole('admin').apply();

CollectionFS compatibility issue

Hi!
I'm using ongoworks:[email protected] and cfs:[email protected].
When i try to set security rules like this:

StickerImages.files.permit(['download']).ifLoggedIn().apply();

I got an error:

W20150512-17:38:11.681(3)? (STDERR) Error: allow: Invalid key: download
W20150512-17:38:11.682(3)? (STDERR)     at packages/mongo/collection.js:723:1
W20150512-17:38:11.682(3)? (STDERR)     at Array.forEach (native)
W20150512-17:38:11.682(3)? (STDERR)     at Function._.each._.forEach (packages/underscore/underscore.js:105:1)
W20150512-17:38:11.682(3)? (STDERR)     at [object Object].addValidator (packages/mongo/collection.js:721:1)
W20150512-17:38:11.682(3)? (STDERR)     at [object Object].Mongo.Collection.allow (packages/mongo/collection.js:769:1)
W20150512-17:38:11.683(3)? (STDERR)     at packages/ongoworks:security/security-util.js:39:1
W20150512-17:38:11.683(3)? (STDERR)     at Array.forEach (native)
W20150512-17:38:11.683(3)? (STDERR)     at Function._.each._.forEach (packages/underscore/underscore.js:105:1)
W20150512-17:38:11.683(3)? (STDERR)     at addFuncForAll (packages/ongoworks:security/security-util.js:38:1)
W20150512-17:38:11.683(3)? (STDERR)     at packages/ongoworks:security/security-util.js:56:1

But the following rule works great:

StickerImages.deny({
    download: function(userId, doc){
        return true;
    }
});

Is it a compatibility problem, or i'm doing something wrong?

How to unit test permit rules?

Hi, I wondered if anyone has had success in writing unit tests to confirm the behavior of the permit rules in their app.

I tried to follow the instructions here: http://stackoverflow.com/questions/28226969/testing-meteor-testing-allow-deny-with-a-unit-test-instead-of-integration-te
But it doesn't seem to work, I get undefined Docs._velocityAllow/Deny, and besides, I don't even know if that method is conceptually right for permit rules.
I should mention that I also use aldeed:collection2, which I think also adds its own allow rules.

Of course, I did manage to write integration tests for this, but by their nature they are very destructive (insert/update/remove actions...). They interfered with the other tests, so currently I just put them last in my test order.

So, does anyone know of a way to do this in unit or non-destructive integration tests?

Update for heroku platform

taken from heroku log
=> Errors while initializing project:

   While checking for ongoworks:[email protected]:
   error: No compatible binary build found for this package. Contact the package
   author and ask them to publish it for your platform.

Could i use meteor-security in meteor method?

Could i use meteor-security in meteor method like this:

Meteor.method({
   myMethod: function(roles) {
   Posts.permit('remove').ifHasRole({role: roles}).apply();
   }
});

And then we call it before insert or after submit.

Can rules be set in Meteor.startup funcion?

Hi,

Can rules be put inside Meteor.startup function, or it have to global namespace? I've got some problem with structuring my app, and I wonder if that would be OK.

Meteor.startup(function(){
    Posts.permit(['insert', 'update', 'remove']).apply();
});

Thanks,
Khrone

Conflict with matb33:meteor-collection-hooks prevents startup

When uninstalling either ongoworks:security or matb33:meteor-collection-hooks problem is solved and server starts up.
Funnily enough with msavin:mongol (unrelated!) installed the conflict goes unnoticed! Only once you deploy to production (mongol being debugonly) the conflict surfaces.

W20160312-16:23:21.509(1)? (STDERR) Error: The collections argument must be a Mongo.Collection instance or an array of them
W20160312-16:23:21.510(1)? (STDERR) at packages/ongoworks_security/lib/server/security-api.js:67:1

How to express this security setup?

ifMine() checks if the current user's id is in that field.

Here 'ownerId' is the user that created the document. 'subjectId' is who the document is about. Owners and Subjects can access different fields.

A user can create a doc about themselves, in which case they are Owner and Subject. I'm having trouble expressing security settings for that case.

This doesn't work, and I get 403's when saving a Subject+Expert doc.

// Tried adding this but still got 403's
Expertises.permit(['update'])
  .ifMine('ownerId')
  .ifMine('subjectId')
  .onlyProps(['justForOwners', 'justForSubjects'])
  .apply();
// Tried just these two first.  Didn't work.
Expertises.permit(['update'])
  .ifMine('ownerId')
  .onlyProps(['justForOwners'])
  .apply();
Expertises.permit(['update'])
  .ifMine('subjectId')
  .onlyProps(['justForSubjects'])
  .apply();

How would you express this?

Allow group argument in "ifHasRole" signature

The "alanning:roles" package allows to check permission by group since version 1.1.0.
It would be great to be able to use the "userIsInRole(user, roles, group)" signature from meteor-security.

e.g:

Posts.permit('remove').ifHasRole('admin', 'company1.com').apply();

or even in array syntax:

Posts.permit('remove').ifHasRole(['admin', 'posts-admin'], 'company1.com').apply();

vsivsi:file-collection compatibility

I use the file package https://atmospherejs.com/vsivsi/file-collection

For some reason using ongoworks security doesn't work with that collection.

@Files = new FileCollection 'files',
    resumable: true
    http: [
        method: 'get'
        path: '/:md5'
        lookup: (params, query) ->
            md5: params.md5
    ]

Files.permit(['insert']).apply()

generates the error

Error: [Unrecognized allow rule type 'transform'.]
at FileCollection.allow (packages/vsivsi:file-collection/src/gridFS_server.coffee:147:26)
at packages/ongoworks:security/security-util.js:39:1
...

It seems that avoiding to set transform: null would solve the issue.

How to get the userId of the current user

I don't understand how i can get the current user id (like in a meteor method) in order to use this method: ifHasUserId(userId)
In Allow/Deny rules you always have access to the changed document id and the set of changes to the document - does this work at the moment with this package ?
I would like to give a user the permission to only change specific fields of his profile. How would you handle this?

This should be default security in meteor!

Meteor is so easy in many ways, But allow/deny are not. So why don't meteor adapt this as the default security behavior have you guys tried proposing it? I think the logic created here is really top notch. This package is truly an art logic wise!

Provide client side stub for permit

I know that allow deny rules only work on the server but they can be written isomorphically without incurring an error on the client. The permit method here does throw in the client. Now and again I have experienced having to figure out why the permit method isn't working, thinking there was some kind of package conflict only to find out hours later that it's because it only works on the server.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.