• This repository has been archived on 05/May/2020
  • Stars
    star
    258
  • Rank 158,189 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 10 years ago
  • Updated over 7 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

A Meteor package: Logical MongoDB security

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.

More Repositories

1

reaction

Mailchimp Open Commerce is an API-first, headless commerce platform built using Node.js, React, GraphQL. Deployed via Docker and Kubernetes.
JavaScript
12,320
star
2

example-storefront

Example Storefront is Reaction Commerce’s headless ecommerce storefront - Next.js, GraphQL, React. Built using Apollo Client and the commerce-focused React UI components provided in the Storefront Component Library (reactioncommerce/reaction-component-library). It connects with Reaction backend with the GraphQL API.
JavaScript
606
star
3

reaction-development-platform

Reaction Platform is the quickest way to run Reaction (reactioncommerce/reaction) and dependent servicesβ€”Reaction Admin (reactioncommerce/reaction-admin) and Example Storefront (reactioncommerce/example-storefront)
Makefile
228
star
4

reaction-component-library

Example Storefront Component Library: A set of React components for the Example Storefront
JavaScript
97
star
5

reaction-admin

Reaction Admin
JavaScript
88
star
6

reaction-docs

Documentation for Reaction, Reaction Platform, Example Storefront, and other supporting services.
CSS
68
star
7

mongo-rep-set

A Dockerized MongoDB for creating a three node replica set across separate hosts.
Shell
56
star
8

meteor-google-spreadsheets

Google Spreadsheets for Meteor
JavaScript
53
star
9

reaction-swag-shop

JavaScript
38
star
10

proxy-traefik

A reverse proxy powered by Traefik for deploying the Reaction Platform on Digital Ocean
35
star
11

reaction-cli

A command line tool for working with Reaction Commerce.
JavaScript
33
star
12

meteor-ddp-login

Meteor DDP login package
JavaScript
27
star
13

reaction-example-plugin

Example files to accompany the "Creating a Plugin" tutorial in the Customization Guide
JavaScript
22
star
14

reaction-devtools

Developer tools for Reaction
JavaScript
21
star
15

reaction-api-base

ARCHIVED: Demo GraphQL API server.
JavaScript
21
star
16

redoc

redoc - generate documentation from multiple project repos.
CSS
20
star
17

reaction-file-collections

Reaction File Collection packages
JavaScript
19
star
18

base

A base Docker image for Reaction Commerce (https://hub.docker.com/r/reactioncommerce/base)
Dockerfile
19
star
19

reaction-example-theme

Reaction Commerce example theme package
JavaScript
15
star
20

reaction-hydra

OAuth2 token server. Integrated with the Reaction development platform.
Shell
14
star
21

reaction-feature-requests

Reaction Feature Requests
14
star
22

spiderable

Docker + Ports friendly Meteor Spiderable
JavaScript
14
star
23

data-factory

Mock data factory util for Reaction Commerce
JavaScript
13
star
24

api-core

This NPM package provides the `ReactionAPICore` class. Use this to build a NodeJS microservice that is compatible with the Reaction Commerce platform, or to build your main Reaction Commerce API if you don't want to start by forking the https://github.com/reactioncommerce/reaction project.
JavaScript
10
star
25

components-context

A system for injecting React components into other React components from a central components context
JavaScript
9
star
26

reaction-styleguide

A plugin for Reaction, transforming it into a style guide and UI component playground.
JavaScript
9
star
27

random

A drop-in replacement for the "random" Meteor package
JavaScript
8
star
28

reaction-main-street-theme

A theme for Reaction Commerce based on bootstrap 4
CSS
8
star
29

catalyst

Catalyst Design System: A design system built by Reaction Commerce for Reaction Admin.
JavaScript
8
star
30

ci-scripts

Scripts supporting our Continuous Integration (CI)
Shell
8
star
31

reaction-identity

JavaScript
8
star
32

kinetic

Kinetic introduces a suite of opinionated admin tools that internal teams can use to manage and run their stores on Open Commerce.
TypeScript
7
star
33

reaction-sample-data

A collection of different datasets for testing and evaluating
7
star
34

pricewatch

Watch prices for change notifications.
Clojure
6
star
35

api-utils

Utility functions for the Reaction API.
JavaScript
6
star
36

federated-gateway

An access aware federated GraphQL API gateway for the Reaction Commerce ecosystem
JavaScript
6
star
37

cli

A command line tool for creating, developing and deploying Open Commerce projects
JavaScript
5
star
38

generator-reaction

Project generator for Reaction NodeJS projects. Built with Yeoman.
JavaScript
5
star
39

reaction-eslint-config

Reaction Eslint Configuration
JavaScript
5
star
40

mongo-s3-backup

A Docker container to backup a MongoDB deployment to S3 and list or restore those backups.
Shell
5
star
41

schemas

The collection schemas API for Reaction Commerce
JavaScript
4
star
42

migrator

Command line interface for migrating MongoDB databases
JavaScript
4
star
43

api-plugin-pricing-simple

Simple Pricing plugin for the Reaction API
JavaScript
4
star
44

reaction-health-check

A package to create a health-check route
JavaScript
4
star
45

api-plugin-example

Boilerplate Example Plugin for moving internal plugins to their own NPM packages for the Reaction API
JavaScript
4
star
46

api-migrations

This project tracks current desired versions for all tracks used by the default Reaction Platform.
JavaScript
4
star
47

docs

4
star
48

nodemailer

Send e-mails with Node.JS
JavaScript
4
star
49

docker-base

Dockerfile
4
star
50

admin-core

JavaScript
4
star
51

micro-frontend-admin

JavaScript
3
star
52

design

Board for design issues
3
star
53

reaction-job-queue

Reaction job queue collection
JavaScript
3
star
54

api-plugin-shops

Shops plugin for the Reaction API
JavaScript
3
star
55

api-plugin-products

Products plugin for the Reaction API
JavaScript
3
star
56

api-plugin-inventory

Inventory service for the Reaction API
JavaScript
3
star
57

mailchimp-open-commerce-helm-chart

Helm chart for deploying Mailchimp Open Commerce ontop of Kubernetes/Openshift.
Mustache
3
star
58

reekwire

Workaround for using CommonJS named exports in ES modules.
JavaScript
3
star
59

api-plugin-payments-stripe

Stripe Payments plugin for the Reaction API
JavaScript
3
star
60

hydra-token

Command line interface that makes it quick and easy to get a valid access token for a Reaction GraphQL API
JavaScript
3
star
61

api-plugin-payments-example

Example Payments plugin for the Reaction API
JavaScript
2
star
62

api-plugin-i18n

i18n plugin for the Reaction API
JavaScript
2
star
63

api-plugin-authentication

Authentication plugin for the Reaction API
JavaScript
2
star
64

api-plugin-files

Files plugin for the Reaction API
JavaScript
2
star
65

api-plugin-taxes

Taxes plugin for the Reaction API
JavaScript
2
star
66

api-plugin-sitemap-generator

Sitemap Generator plugin for the Reaction API
JavaScript
2
star
67

api-plugin-email-smtp

Email SMTP plugin for the Reaction API
JavaScript
2
star
68

logger

Reaction Commerce application logging API.
JavaScript
2
star
69

api-plugin-email-templates

Email Templates plugin for the Reaction API
JavaScript
2
star
70

api-plugin-email

Email plugin for the Reaction API
JavaScript
2
star
71

admin

TypeScript
2
star
72

hooks

The event hooks API for Reaction Commerce
JavaScript
2
star
73

api-plugin-accounts

Accounts plugin for the Reaction API
JavaScript
2
star
74

api-plugin-job-queue

Job Queue plugin for the Reaction API
JavaScript
2
star
75

reaction-error

Reaction error messaging
JavaScript
2
star
76

api-plugin-payments-stripe-sca

Stripe payments using the Payments Intents API
JavaScript
2
star
77

reaction-questions

Ask us questions about Reaction
1
star
78

api-plugin-navigation

Navigation plugin for the Reaction API
JavaScript
1
star
79

kube-helm

A lightweight Docker image with various CLI tooling for working with Kubernetes.
Shell
1
star
80

api-plugin-payments

Payments plugin for the Reaction API
JavaScript
1
star
81

api-plugin-shipments-flat-rate

Shipping Rates plugin for the Reaction API
JavaScript
1
star
82

babel-remove-es-create-require

JavaScript
1
star
83

admin-plugin-products

JavaScript
1
star
84

example-payments-plugin

An example payments plugin for Reaction Commerce
JavaScript
1
star
85

api-plugin-translations

Translations plugin for the Reaction API
JavaScript
1
star
86

api-plugin-address-validation-test

Address Validation Test plugin for the Reaction API
JavaScript
1
star
87

api-plugin-surcharges

Surcharges plugin for the Reaction API
JavaScript
1
star
88

api-plugin-orders

Orders plugin for the Reaction API
JavaScript
1
star
89

api-plugin-authorization-simple

Simple Authorization plugin for the Reaction API
JavaScript
1
star
90

api-plugin-carts

Carts plugin for the Reaction API
JavaScript
1
star
91

db-version-check

Data version checker function compatible with @reactioncommerce/migrator
JavaScript
1
star
92

api-plugin-discounts-codes

Discount Codes plugin for the Reaction API
JavaScript
1
star
93

admin-plugin-example

Example Reaction Admin plugin
JavaScript
1
star
94

api-plugin-address-validation

Address Validation plugin for the Reaction API
JavaScript
1
star
95

api-plugin-taxes-flat-rate

Tax Rates plugin for the Reaction API
JavaScript
1
star
96

api-plugin-discounts

Discounts plugin for the Reaction API
JavaScript
1
star
97

api-plugin-settings

Settings plugin for the Reaction API
JavaScript
1
star
98

api-plugin-simple-schema

Simple Schema plugin for the Reaction API
JavaScript
1
star
99

api-plugin-system-information

System Information plugin for the Reaction API
JavaScript
1
star
100

api-plugin-tags

Tags plugin for the Reaction API
JavaScript
1
star