Add basic LDAP bind functionality
This commit is contained in:
59
app/ldap/controllers/Users.controller.js
Normal file
59
app/ldap/controllers/Users.controller.js
Normal file
@@ -0,0 +1,59 @@
|
||||
const LDAPController = require('./LDAPController')
|
||||
const LDAP = require('ldapjs')
|
||||
|
||||
class UsersController extends LDAPController {
|
||||
static get services() {
|
||||
return [...super.services, 'output', 'ldap_server', 'models']
|
||||
}
|
||||
|
||||
async search_people(req, res, next) {
|
||||
global.ireq = req
|
||||
}
|
||||
|
||||
async bind(req, res, next) {
|
||||
const auth_dn = this.ldap_server.auth_dn()
|
||||
|
||||
// Make sure the DN is valid
|
||||
if ( !req.dn.childOf(auth_dn) ) {
|
||||
return next(new LDAP.InvalidCredentialsError())
|
||||
}
|
||||
|
||||
// Get the user
|
||||
const user = await this.get_user_from_dn(req.dn)
|
||||
if ( !user ) {
|
||||
return next(new LDAP.InvalidCredentialsError())
|
||||
}
|
||||
|
||||
// Make sure the password matches the user record
|
||||
if ( !await user.check_password(req.credentials) ) {
|
||||
return next(new LDAP.InvalidCredentialsError())
|
||||
}
|
||||
|
||||
// Make sure the user has permission to bind
|
||||
if ( !user.can('ldap:bind') ) {
|
||||
return next(new LDAP.InsufficientAccessRightsError())
|
||||
}
|
||||
|
||||
this.output.success(`Successfully bound user ${user.uid} as DN: ${req.dn.format({skipSpace: true})}.`)
|
||||
return res.end()
|
||||
}
|
||||
|
||||
get_uid_from_dn(dn) {
|
||||
const uid_field = this.ldap_server.config.schema.auth.user_id
|
||||
|
||||
try {
|
||||
if ( typeof dn === 'string' ) dn = LDAP.parseDN(dn)
|
||||
return dn.rdns[0].attrs[uid_field].value
|
||||
} catch (e) {}
|
||||
}
|
||||
|
||||
async get_user_from_dn(dn) {
|
||||
const uid = this.get_uid_from_dn(dn)
|
||||
if ( uid ) {
|
||||
const User = this.models.get('auth:User')
|
||||
return User.findOne({uid})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = UsersController
|
||||
33
app/ldap/middleware/BindUser.middleware.js
Normal file
33
app/ldap/middleware/BindUser.middleware.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const LDAPMiddleware = require('./LDAPMiddleware')
|
||||
const LDAP = require('ldapjs')
|
||||
|
||||
class BindUserMiddleware extends LDAPMiddleware {
|
||||
static get services() {
|
||||
return [...super.services, 'canon', 'output', 'ldap_server']
|
||||
}
|
||||
|
||||
async test(req, res, next) {
|
||||
const bind_dn = req.connection.ldap.bindDN
|
||||
|
||||
if ( bind_dn.equals(this.ldap_server.anonymous()) ) {
|
||||
this.output.warn(`Blocked anonymous LDAP request on user-protected route.`)
|
||||
return next(new LDAP.InsufficientAccessRightsError())
|
||||
}
|
||||
|
||||
const user = this.user_controller().get_uid_from_dn(bind_dn)
|
||||
if ( !user || !user.can('ldap:bind') ) {
|
||||
return next(new LDAP.InvalidCredentialsError())
|
||||
}
|
||||
|
||||
req.user = user
|
||||
req.bindDN = bind_dn
|
||||
|
||||
return next()
|
||||
}
|
||||
|
||||
user_controller() {
|
||||
return this.canon.get('ldap_controller::Users')
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = BindUserMiddleware
|
||||
15
app/ldap/middleware/Logger.middleware.js
Normal file
15
app/ldap/middleware/Logger.middleware.js
Normal file
@@ -0,0 +1,15 @@
|
||||
const LDAPMiddleware = require('./LDAPMiddleware')
|
||||
|
||||
class LDAPLoggerMiddleware extends LDAPMiddleware {
|
||||
static get services() {
|
||||
return [...super.services, 'app', 'output']
|
||||
}
|
||||
|
||||
async test(req, res, next) {
|
||||
let bind_dn = req.connection.ldap.bindDN
|
||||
this.output.info(`${req.json.protocolOp} - as ${bind_dn ? bind_dn.format({skipSpace: true}) : 'N/A'} - target ${req.dn.format({skipSpace: true})}`)
|
||||
return next()
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = exports = LDAPLoggerMiddleware
|
||||
@@ -1,27 +0,0 @@
|
||||
const example_routes = {
|
||||
|
||||
prefix: 'dc=base',
|
||||
|
||||
middleware: [
|
||||
|
||||
],
|
||||
|
||||
search: {
|
||||
|
||||
},
|
||||
|
||||
bind: {
|
||||
|
||||
},
|
||||
|
||||
add: {
|
||||
|
||||
},
|
||||
|
||||
del: {
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
module.exports = exports = example_routes
|
||||
30
app/ldap/routes/users.routes.js
Normal file
30
app/ldap/routes/users.routes.js
Normal file
@@ -0,0 +1,30 @@
|
||||
const users_routes = {
|
||||
|
||||
prefix: false, // false | string
|
||||
|
||||
middleware: [
|
||||
'Logger'
|
||||
],
|
||||
|
||||
search: {
|
||||
'ou=people': [
|
||||
'ldap_middleware::BindUser',
|
||||
'ldap_controller::Users.search_people',
|
||||
],
|
||||
},
|
||||
|
||||
bind: {
|
||||
'ou=people': ['ldap_controller::Users.bind'],
|
||||
},
|
||||
|
||||
add: {
|
||||
|
||||
},
|
||||
|
||||
del: {
|
||||
|
||||
},
|
||||
|
||||
}
|
||||
|
||||
module.exports = exports = users_routes
|
||||
Reference in New Issue
Block a user