diff --git a/TODO.text b/TODO.text index f518a19..dcb2d4a 100644 --- a/TODO.text +++ b/TODO.text @@ -11,7 +11,6 @@ - e.g. after insert perform action - e.g. after update perform action, &c. - IAM manage user API scopes -- Eliminate LDAP group model, make LDAP server use standard auth group - OAuth2 -> support refresh tokens - Traps -> support session traps; convert MFA challenge to use session trap - Allow setting user trap from web UI diff --git a/app/ldap/controllers/Groups.controller.js b/app/ldap/controllers/Groups.controller.js index 42c8efc..5b2df21 100644 --- a/app/ldap/controllers/Groups.controller.js +++ b/app/ldap/controllers/Groups.controller.js @@ -14,7 +14,7 @@ class GroupsController extends LDAPController { constructor() { super() - this.Group = this.models.get('ldap:Group') + this.Group = this.models.get('auth:Group') } // TODO flitter-orm chunk query @@ -106,7 +106,7 @@ class GroupsController extends LDAPController { async get_resource_from_dn(dn) { const cn = this.get_cn_from_dn(dn) if ( cn ) { - return this.Group.findOne({name: cn, ldap_visible: true}) + return this.Group.findOne({name: cn, ldap_visible: true, active: true}) } } } diff --git a/app/ldap/controllers/Users.controller.js b/app/ldap/controllers/Users.controller.js index cd8de9c..991027f 100644 --- a/app/ldap/controllers/Users.controller.js +++ b/app/ldap/controllers/Users.controller.js @@ -22,7 +22,13 @@ class UsersController extends LDAPController { // Might need to override compare to support special handling for userPassword // TODO generalize some of the addition logic + // TODO rework some of the registration and validation logic async add_people(req, res, next) { + const Setting = this.models.get('Setting') + if ( !(await Setting.get('auth.allow_registration')) ) { + return next(new LDAP.InsufficientAccessRightsError('Operation not enabled.')) + } + if ( !req.user.can('ldap:add:users') ) { return next(new LDAP.InsufficientAccessRightsError()) } @@ -87,6 +93,7 @@ class UsersController extends LDAPController { } // TODO generalize some of the modification logic + // TODO rework validation async modify_people(req, res, next) { if ( !req.user.can('ldap:modify:users') ) { return next(new LDAP.InsufficientAccessRightsError()) diff --git a/app/ldap/routes/groups.routes.js b/app/ldap/routes/groups.routes.js index 885b708..de3c002 100644 --- a/app/ldap/routes/groups.routes.js +++ b/app/ldap/routes/groups.routes.js @@ -13,37 +13,15 @@ const groups_routes = { ], }, - /*bind: { - 'ou=groups': ['ldap_controller::Users.bind'], - },*/ + bind: {}, - /*add: { - 'ou=groups': [ - 'ldap_middleware::BindUser', - 'ldap_controller::Groups.add_group', - ], - }, + add: {}, - del: { - 'ou=people': [ - 'ldap_middleware::BindUser', - 'ldap_controller::Users.delete', - ], - }, + del: {}, - modify: { - 'ou=people': [ - 'ldap_middleware::BindUser', - 'ldap_controller::Users.modify_people', - ], - }, + modify: {}, - compare: { - 'ou=people': [ - 'ldap_middleware::BindUser', - 'ldap_controller::Users.compare', - ], - },*/ + compare: {}, } diff --git a/app/models/auth/Group.model.js b/app/models/auth/Group.model.js index 7145f9e..133ce08 100644 --- a/app/models/auth/Group.model.js +++ b/app/models/auth/Group.model.js @@ -1,9 +1,10 @@ const { Model } = require('flitter-orm') +const LDAP = require('ldapjs') // For organizational purposes only. class GroupModel extends Model { static get services() { - return [...super.services, 'models'] + return [...super.services, 'models', 'ldap_server', 'configs'] } static get schema() { @@ -11,6 +12,7 @@ class GroupModel extends Model { name: String, user_ids: [String], active: { type: Boolean, default: true }, + ldap_visible: { type: Boolean, default: true }, } } @@ -18,16 +20,35 @@ class GroupModel extends Model { return this.name.toLowerCase().replace(/\s/g, '_') } + get dn() { + return LDAP.parseDN(`cn=${this.name},${this.ldap_server.group_dn().format(this.configs.get('ldap:server.format'))}`) + } + async users() { const User = this.models.get('auth:User') return await User.find({ _id: { $in: this.user_ids.map(x => this.constructor.to_object_id(x)) } }) } + async to_ldap() { + const users = await this.users() + return { + cn: this.name, + dn: this.dn.format(this.configs.get('ldap:server.format')), + objectClass: 'groupOfNames', + member: users.map(x => x.dn.format(this.configs.get('ldap:server.format'))), + } + } + + static async ldap_directory() { + return this.find({ ldap_visible: true, active: true }) + } + async to_api() { return { id: this.id, name: this.name, user_ids: this.user_ids, + ldap_visible: this.ldap_visible, } } } diff --git a/app/models/auth/User.model.js b/app/models/auth/User.model.js index 3340b0a..c2a62db 100644 --- a/app/models/auth/User.model.js +++ b/app/models/auth/User.model.js @@ -153,16 +153,6 @@ class User extends AuthUser { return Group.find({ active: true, user_ids: this.id }) } - async ldap_groups() { - const Group = this.models.get('ldap:Group') - return await Group.find({ - $or: [ - { user_ids: this.id }, - { role: { $in: this.roles } }, - ], - }) - } - async to_ldap() { const ldap_data = { uid: this.uid, @@ -182,10 +172,11 @@ class User extends AuthUser { ldap_data[`data${key.substr(4)}`] = `${addl_data[key]}` } - const ldap_groups = await this.ldap_groups() - if ( ldap_groups.length > 0 ) { - ldap_data.memberOf = ldap_groups.map(x => x.dn.format(this.configs.get('ldap:server.format'))) - ldap_data.memberof = ldap_groups.map(x => x.dn.format(this.configs.get('ldap:server.format'))) + const groups = await this.groups() + if ( groups.length > 0 ) { + const group_data = groups.map(x => x.dn.format(this.configs.get('ldap:server.format'))) + ldap_data.memberOf = group_data + ldap_data.memberof = group_data } return ldap_data diff --git a/app/models/ldap/Group.model.js b/app/models/ldap/Group.model.js deleted file mode 100644 index a5f08fd..0000000 --- a/app/models/ldap/Group.model.js +++ /dev/null @@ -1,54 +0,0 @@ -const LDAPBase = require('../LDAPBase') -const LDAP = require('ldapjs') - -class GroupModel extends LDAPBase { - static get services() { - return [...super.services, 'configs', 'ldap_server', 'models'] - } - - static get schema() { - return { - role: String, - user_ids: [String], - name: String, - active: {type: Boolean, default: true}, - ldap_visible: {type: Boolean, default: true}, - } - } - - async to_api() { - return { - id: this.id, - role: this.role, - user_ids: this.user_ids, - name: this.name, - ldap_visible: this.ldap_visible, - } - } - - get dn() { - return LDAP.parseDN(`cn=${this.name},${this.ldap_server.group_dn().format(this.configs.get('ldap:server.format'))}`) - } - - async users() { - const User = this.models.get('auth:User') - return User.find({ - $or: [ - { _id: { $in: this.user_ids.map(x => this.constructor.to_object_id(x)) } }, - { roles: this.role }, - ], - }) - } - - async to_ldap() { - const users = await this.users() - return { - cn: this.name, - dn: this.dn.format(this.configs.get('ldap:server.format')), - objectClass: 'groupOfNames', - member: users.map(x => x.dn.format(this.configs.get('ldap:server.format'))) - } - } -} - -module.exports = exports = GroupModel