Access Control

Service’s accomplish access control by way of ACLs or Access Control Lists.

ACLs

Carbond provides a very generic and extensible ACL framework. In their most generic form, Acl objects map Users and Groups to a set of Permissions which govern access to some entity.

In practice you will use one of the pre-packaged ACL types to gate access to your Endpoint’s and their Operation’s.

Endpoint ACLs

All Endpoint’s can be configured with an EndpointAcl to govern which endpoint Operation’s can be accessed by users.

EndpointAcls defined the following permissions, one for each HTTP method:

  • get
  • post
  • put
  • patch
  • delete
  • head
  • options

All permissions default to false except the options permission which defaults to true.

Here is an example of a Service using an EndpointAcl:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
__(function() {
  module.exports = o.main({
    _type: carbon.carbond.Service,
    port: 8888,
    dbUri: 'mongodb://localhost:27017/mydb',
    authenticator: o({
      _type: carbon.carbond.security.MongoDBApiKeyAuthenticator,
      apiKeyParameterName: 'API_KEY',
      apiKeyLocation: 'header',
      userCollection: 'users',
      apiKeyField: 'apiKey'
    }),
    endpoints: {
      hello: o({
        _type: carbon.carbond.Endpoint,
        acl: o({
          _type: carbon.carbond.security.EndpointAcl,
          groupDefinitions: { // This ACL defined two groups, 'role' and 'title'.
            role: 'role', // We define a group called 'role' based on the user
                          // property named 'role'.
            title: function(user) { return user.title }
          },
          entries: [
            {
              user: { role: 'Admin' },
              permissions: {
                '*': true // '*' grants all permissions
              }
            },
            {
              user: { title: 'CFO' },
              permissions: { // We could have used '*' here but are being
                             // explicit.
                get: true,
                post: true
              }
            },
            {
              user: '10002', // User with _id '10002'
              permissions: {
                get: false,
                post: true
              }
            },
            {
              user: '*', // All other users
              permissions: {
                get: true,
                post: false
              }
            }
          ]
        }),

        get: function(req) {
          return { msg: 'Hello World!' }
        },

        post: function(req) {
          return { msg: 'Hello World! ' + JSON.stringify(req.body) }
        }

      })
    }
  })
})

Collection ACLs

CollectionAcls are similar to EndpointAcls except that they define a set of permissions that matches the Collection interface.

CollectionAcls define the following permissions:

  • insert
  • find
  • update
  • remove
  • saveObject
  • findObject
  • updateObject
  • removebject

All permissions default to false.

Here is an example of a Service using a CollectionAcl on a MongoDBCollection:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
__(function() {
  module.exports = o.main({
    _type: carbon.carbond.Service,
    port: 8888,
    dbUri: 'mongodb://localhost:27017/mydb',
    authenticator: o({
      _type: carbon.carbond.security.MongoDBApiKeyAuthenticator,
      apiKeyParameterName: 'API_KEY',
      apiKeyLocation: 'header',
      userCollection: 'users',
      apiKeyField: 'apiKey'
    }),
    endpoints: {
      hello: o({
        _type: carbon.carbond.mongodb.MongoDBCollection,
        collectionName: 'hello',
        enabled: {'*': true},
        acl: o({
          _type: carbon.carbond.security.CollectionAcl,
          groupDefinitions: { // This ACL defined two groups, 'role' and
                              // 'title'.
            role: 'role', // We define a group called 'role' based on the
                          // user property named 'role'.
            title: function(user) { return user.title }
          },
          entries: [
            {
              user: { role: 'Admin' },
              permissions: {
                '*': true // '*' grants all permissions
              }
            },
            {
              user: { title: 'CFO' },
              permissions: {
                find: true,
                findObject: true,
                '*': false // This is implied since the default value for
                           // all permissions is `false`.
              }
            },
            {
              user: '10002', // User with _id '10002'
              permissions: {
                insertObject: true,
                findObject: true
              }
            },
            {
              user: '*', // All other users
              permissions: {
                findObject: true
              }
            }
          ]
        })
      })
    }
  })
})

Re-using ACLs across multiple Endpoints

In some cases you may wish to re-use the same ACL across many Endpointss. To do this you can simply define your ACL as its own component and then reference it in your Endpoint.

Example

MyAcl.js:

1
2
3
4
5
6
7
8
9
var carbon = require('carbon-io')
var o  = carbon.atom.o(module)

module.exports = o({
  _type: carbon.carbond.security.CollectionAcl,
  /*
   * Your ACL definition
   */
})

Now you can reference this ACL from any Endpoint that wished to use that ACL:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
var carbon = require('carbon-io')
var __ = carbon.fibers.__(module)
var _o  = carbon.bond._o(module)
var o  = carbon.atom.o(module)

__(function() {
  module.exports = o.main({
    _type: carbon.carbond.Service,
    port: 8888,
    dbUri: 'mongodb://localhost:27017/mydb',
    authenticator: o({
      _type: carbon.carbond.security.MongoDBApiKeyAuthenticator,
      apiKeyParameterName: 'API_KEY',
      apiKeyLocation: 'header',
      userCollection: 'users',
      apiKeyField: 'apiKey'
    }),
    endpoints: {
      hello: o({
        _type: carbon.carbond.mongodb.MongoDBCollection,
        collectionName: 'hello',
        enabled: {'*': true},
        acl: _o('./MyAcl')
      })
    }
  })
})