UNPKG

mecano

Version:

Common functions for system deployment.

175 lines (168 loc) 7.71 kB
`ldap_acl([goptions], options, callback` ---------------------------------------- Create new ACLs for the OpenLDAP server. each = require 'each' ldap = require 'ldapjs' misc = require './misc' conditions = require './misc/conditions' child = require './misc/child' `options` Command options include: * `to` What to control access to as a string. * `by` Who to grant access to and the access to grant as an array (eg: `{..., by:["ssf=64 anonymous auth"]}`) * `url` Specify URI referring to the ldap server, alternative to providing an [ldapjs client] instance. * `binddn` Distinguished Name to bind to the LDAP directory, alternative to providing an [ldapjs client] instance. * `passwd` Password for simple authentication, alternative to providing an [ldapjs client] instance. * `ldap` Instance of an pldapjs client][ldapclt], alternative to providing the `url`, `binddn` and `passwd` connection properties. * `unbind` Close the ldap connection, default to false if connection is an [ldapjs client][ldapclt] instance. * `name` Distinguish name storing the "olcAccess" property, using the database adress (eg: "olcDatabase={2}bdb,cn=config"). * `overwrite` Overwrite existing "olcAccess", default is to merge. * `log` Function called with a log related messages. * `acl` In case of multiple acls, regroup "before", "to" and "by" as an array Resources: http://www.openldap.org/doc/admin24/access-control.html [ldapclt]: http://ldapjs.org/client.html module.exports = (goptions, options, callback) -> [goptions, options, callback] = misc.args arguments result = child() finish = (err, modified) -> callback err, modified if callback result.end err, modified misc.options options, (err, options) -> return finish err if err modified = 0 each( options ) .parallel(goptions.parallel) .on 'item', (options, next) -> options.acls ?= [{}] conditions.all options, next, -> updated = false each(options.acls) .parallel(false) .on 'item', (acl, next) -> acl.before ?= options.before acl.to ?= options.to acl.by ?= options.by client = null acl.to = acl.to.trim() for b, i in acl.by acl.by[i] = b.trim() connect = -> # if options.ldap instanceof ldap_client if options.ldap?.url?.protocol?.indexOf('ldap') is 0 client = options.ldap return search() options.log? 'Open and bind connection' client = ldap.createClient url: options.url client.bind options.binddn, options.passwd, (err) -> return end err if err search() search = -> options.log? 'Search attribute olcAccess' client.search options.name, scope: 'base' attributes: ['olcAccess'] , (err, search) -> return unbind err if err olcAccess = null search.on 'searchEntry', (entry) -> options.log? "Found #{JSON.stringify entry.object}" # typeof olcAccess may be undefined, array or string olcAccess = entry.object.olcAccess or [] olcAccess = [olcAccess] unless Array.isArray olcAccess search.on 'end', -> options.log? "Attribute olcAccess was #{JSON.stringify olcAccess}" parse olcAccess parse = (_olcAccess) -> olcAccess = [] for access, i in _olcAccess to = '' bys = [] buftype = 0 # 0: start, 1: to, 2:by buf = '' for c, i in access buf += c if buftype is 0 if /to$/.test buf buf = '' buftype = 1 if buftype is 1 if matches = /^(.*)by$/.exec buf to = matches[1].trim() buf = '' buftype = 2 if buftype is 2 if matches = /^(.*)by$/.exec buf bys.push matches[1].trim() buf = '' else if i+1 is access.length bys.push buf.trim() olcAccess.push to: to by: bys do_diff olcAccess do_diff = (olcAccess) -> toAlreadyExist = false for access, i in olcAccess continue unless acl.to is access.to toAlreadyExist = true fby = unless options.overwrite then access.by else [] for oby in acl.by found = false for aby in access.by if oby is aby found = true break unless found updated = true fby.push oby olcAccess[i].by = fby unless toAlreadyExist updated = true # place before if acl.before found = null for access, i in olcAccess found = i if access.to is acl.before # throw new Error 'Before does not match any "to" rule' unless found? olcAccess.splice found-1, 0, to: acl.to, by: acl.by # place after else if acl.after found = false for access, i in olcAccess found = i if access.to is options.after # throw new Error 'After does not match any "to" rule' olcAccess.splice found, 0, to: acl.to, by: acl.by # append else olcAccess.push to: acl.to, by: acl.by if updated then stringify(olcAccess) else unbind() stringify = (olcAccess) -> for access, i in olcAccess value = "{#{i}}to #{access.to}" for bie in access.by value += " by #{bie}" olcAccess[i] = value save olcAccess save = (olcAccess) -> change = new ldap.Change operation: 'replace' modification: olcAccess: olcAccess client.modify options.name, change, (err) -> unbind err unbind = (err) -> options.log? 'Unbind connection' # return end err if options.ldap instanceof ldap_client and not options.unbind return end err if options.ldap?.url?.protocol?.indexOf('ldap') is 0 and not options.unbind client.unbind (e) -> return next e if e end err end = (err) -> next err connect() .on 'both', (err) -> modified += 1 if updated and not err # finish err, modified next err .on 'both', (err) -> finish err, modified result