CoreID/app/controllers/api/v1/LDAP.controller.js
2020-05-21 22:56:48 -05:00

343 lines
11 KiB
JavaScript

const { Controller } = require('libflitter')
const zxcvbn = require('zxcvbn')
class LDAPController extends Controller {
static get services() {
return [...super.services, 'models', 'utility', 'configs']
}
async get_config(req, res, next) {
// ldap port
// user base dn
// group base dn
const config = this.configs.get('ldap:server')
return res.api({
port: config.port,
base_dc: config.schema.base_dc,
authentication_base: config.schema.authentication_base,
group_base: config.schema.group_base,
login_field: config.schema.auth.user_id,
})
}
async get_clients(req, res, next) {
const Client = this.models.get('ldap:Client')
const clients = await Client.find({active: true})
const data = []
for ( const client of clients ) {
if ( !req.user.can(`ldap:client:${client.id}:view`) ) continue
data.push(await client.to_api())
}
return res.api(data)
}
async get_groups(req, res, next) {
const Group = this.models.get('ldap:Group')
const groups = await Group.find({active: true})
const data = []
for ( const group of groups ) {
if ( !req.user.can(`ldap:group:${group.id}:view`) ) continue
data.push(await group.to_api())
}
return res.api(data)
}
async get_client(req, res, next) {
const Client = this.models.get('ldap:Client')
const client = await Client.findById(req.params.id)
if ( !client || !client.active )
return res.status(404)
.message('No client found with that ID.')
.api()
if ( !req.user.can(`ldap:client:${client.id}:view`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
return res.api(await client.to_api())
}
async get_group(req, res, next) {
const Group = this.models.get('ldap:Group')
const group = await Group.findById(req.params.id)
if ( !group || !group.active )
return res.status(404)
.message('No group found with that ID.')
.api()
if ( !req.user.can(`ldap:group:${group.id}:view`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
return res.api(await group.to_api())
}
async create_client(req, res, next) {
if ( !req.user.can('ldap:client:create') )
return res.status(401)
.message('Insufficient permissions.')
.api()
// validate inputs
const required_fields = ['name', 'uid', 'password']
for ( const field of required_fields ) {
if ( !req.body[field] )
return res.status(400)
.message(`Missing required field: ${field}`)
}
// Make sure the uid is free
const User = this.models.get('auth:User')
const existing_user = await User.findOne({ uid: req.body.uid })
if ( existing_user )
return res.status(400)
.message('A user with that uid already exists.')
.api()
// Verify password complexity
const min_score = 3
const result = zxcvbn(req.body.password)
if ( result.score < min_score )
return res.status(400)
.message(`Password does not meet the minimum complexity score of ${min_score}.`)
.api()
// Create the client
const Client = this.models.get('ldap:Client')
const client = await Client.create({
uid: req.body.uid,
password: req.body.password,
name: req.body.name,
})
return res.api(await client.to_api())
}
async create_group(req, res, next) {
console.log(req.body)
if ( !req.user.can(`ldap:group:create`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
// validate inputs
const required_fields = ['role', 'name']
for ( const field of required_fields ) {
if ( !req.body[field] )
return res.status(400)
.message(`Missing required field: ${field}`)
.api()
}
// Make sure the group name is free
const Group = this.models.get('ldap:Group')
const User = this.models.get('auth:User')
const existing_group = await Group.findOne({ name: req.body.name })
if ( existing_group )
return res.status(400)
.message('A group already exists with that name.')
.api()
// Make sure the role exists
if ( !this.configs.get('auth.roles')[req.body.role] )
return res.status(400)
.message('Invalid role.')
.api()
const group = new Group({
name: req.body.name,
role: req.body.role,
})
if ( 'ldap_visible' in req.body ) group.ldap_visible = !!req.body.ldap_visible
if ( 'user_ids' in req.body ) {
// Attempt to parse the user_ids
const parsed = typeof req.body.user_ids === 'string' ? this.utility.infer(req.body.user_ids) : req.body.user_ids
const user_ids = Array.isArray(parsed) ? parsed : [parsed]
// Make sure all the user IDs are valid
for ( const user_id of user_ids ) {
const user = await User.findById(user_id)
if ( !user )
return res.status(400)
.message(`Invalid user ID: ${user_id}`)
.api()
}
group.user_ids = user_ids
}
await group.save()
return res.api(await group.to_api())
}
async update_client(req, res, next) {
const Client = this.models.get('ldap:Client')
const client = await Client.findById(req.params.id)
if ( !client || !client.active )
return res.status(404)
.message('No client found with that ID.')
.api()
if ( !req.user.can(`ldap:client:${client.id}:update`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
const required_fields = ['name', 'uid']
for ( const field of required_fields ) {
if ( !req.body[field] )
return res.status(400)
.message(`Missing required field: ${field}`)
.api()
}
const user = await client.user()
// Update the name
if ( req.body.name !== client.name ) {
client.name = req.body.name
user.first_name = req.body.name
}
// Update the uid
if ( req.body.uid !== user.uid ) {
// Make sure the UID is free
const User = this.models.get('auth:User')
const existing_user = await User.findOne({ uid: req.body.uid })
if ( existing_user )
return res.status(400)
.message('A user already exists with that uid.')
.api()
user.uid = req.body.uid
}
// Update the password
if ( req.body.password && !(await user.check_password(req.body.password)) ) {
// Verify the password's complexity
const min_score = 3
const result = zxcvbn(req.body.password)
if ( result.score < min_score )
return res.status(400)
.message(`Password does not meet the minimum complexity score of ${min_score}.`)
.api()
await user.reset_password(req.body.password)
}
await user.save()
await client.save()
return res.api()
}
async update_group(req, res, next) {
const User = await this.models.get('auth:User')
const Group = await this.models.get('ldap:Group')
const group = await Group.findById(req.params.id)
if ( !group || !group.active )
return res.status(404)
.message('No group found with that ID.')
.api()
if ( !req.user.can(`ldap:group:${group.id}:update`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
const required_fields = ['role', 'name']
for ( const field of required_fields ) {
if ( !req.body[field] )
return res.status(400)
.message(`Missing required field: ${field}`)
.api()
}
// Make sure the name is free
const existing_group = await Group.findOne({ name: req.body.name })
if ( existing_group && existing_group.id !== group.id )
return res.status(400)
.message('A group with that name already exists.')
.api()
group.name = req.body.name
group.role = req.body.name
group.ldap_visible = !!req.body.ldap_visible
if ( req.body.user_ids ) {
const parsed = typeof req.body.user_ids === 'string' ? this.utility.infer(req.body.user_ids) : req.body.user_ids
const user_ids = Array.isArray(parsed) ? parsed : [parsed]
for ( const user_id of user_ids ) {
const user = await User.findById(user_id)
if ( !user )
return res.status(400)
.message(`Invalid user_id: ${user_id}`)
.api()
}
group.user_ids = user_ids
} else {
group.user_ids = []
}
await group.save()
return res.api()
}
async delete_client(req, res, next) {
const Client = this.models.get('ldap:Client')
const client = await Client.findById(req.params.id)
if ( !client || !client.active )
return res.status(404)
.message('Client not found with that ID.')
.api()
if ( !req.user.can(`ldap:client:${client.id}:delete`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
const user = await client.user()
client.active = false
user.active = false
user.block_login = true
await user.save()
await client.save()
return res.api()
}
async delete_group(req, res, next) {
const Group = this.models.get('ldap:Group')
const group = await Group.findById(req.params.id)
if ( !group || !group.active )
return res.status(404)
.message('No group found with that ID.')
.api()
if ( !req.user.can(`ldap:group:${group.id}:delete`) )
return res.status(401)
.message('Insufficient permissions.')
.api()
group.active = false
await group.save()
return res.api()
}
}
module.exports = exports = LDAPController