AOP in Meteor

Faiz Mohamed Haneef's Picture
February 17, 2017

There are multiple ways for entering the Meteor application
* Meteor Methods RPC
* Meteor Subscribe
* Meteor WebApp
* customization of meteor via Express / Restivus etc

Here I will be discussing a common problem that we face.
1. Authorization for each RPC and Subscribe
2. Whitelist of system is default in Meteor
3. Developer may miss on the Authorization
4. Code review is tougher to scan in multiple files for authorisation

The cross cutting concerns across the application calls for a single point of authentication as well as authorization. This can also be extended for
1. logging
2. performance monitoring
3. request sanitization etc

Extend Meteor Methods and Publish Framework

security.js

let authMethodConfig = {  
  'addEmployee' : ['director']
}
let authPublishConfig = {  
 'getEmployee' : ['director']
}

// get the user and check his role and permissions for RPC
function authCheckMethod(methodName, user) {  
  let role = user ? user.role : 'guest'
  if(!(_.contains(authMethodConfig[methodName], role))){
    throw new Meteor.Error("unauthorized", "The user is not authorized");
  }
}

// get the user and check his role and permissions then allow him subscribe
function authCheckPublish(publishName, userId) {  
  let user = Meteor.users.findOne({_id:userId}, {role: 1})
  let role = user ? user.role : 'guest'
  if(!(_.contains(authPublishCongig[publishName], role))){
    throw new Meteor.Error("unauthorized", "The user is not authorized");
  }
}


let oldMeteorMethods = Meteor.methods  
Meteor.methods = function(methods) {  
  _.each(methods, function(func, name) {
    let newfunc = function(...args) {
      let user = Meteor.user()
      authCheckMethod(name,user)
      return func.apply(this, arguments)
    }
    let obj = {}
    obj[name] = newfunc
    oldMeteorMethods(obj)
  })
}

let oldMeteorPublish = Meteor.publish  
Meteor.publish = function(name, handler, options) {  
  let newHandler = function(...args) {
    let userId = this.userId
    let self = this
    authCheckPublish(name,userId)
    return handler.apply(this, arguments)
  }
  oldMeteorPublish(name, newHandler, options)
}

With the above code, we have introduced an additional layer of security and each methods or publish information is blacklisted by default, unless we specify which role has access.

The above security.js should be part of Meteor startup folder (or one of the earliest loaded files)