beta
This commit is contained in:
		
							
								
								
									
										48
									
								
								nodejs/models/auth.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								nodejs/models/auth.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,48 @@ | ||||
| const {User} = require('./user'); | ||||
| const {Token, AuthToken} = require('./token'); | ||||
|  | ||||
| Auth = {} | ||||
| Auth.errors = {} | ||||
|  | ||||
| Auth.errors.login = function(){ | ||||
| 	let error = new Error('PamLoginFailed'); | ||||
| 	error.name = 'PamLoginFailed'; | ||||
| 	error.message = `Invalid Credentials, login failed.`; | ||||
| 	error.status = 401; | ||||
|  | ||||
| 	return error; | ||||
| } | ||||
|  | ||||
| Auth.login = async function(data){ | ||||
| 	try{ | ||||
| 		let user = await User.login(data); | ||||
| 		let token = await AuthToken.add(user); | ||||
|  | ||||
| 		return {user, token} | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|  | ||||
| Auth.checkToken = async function(data){ | ||||
| 	try{ | ||||
| 		let token = await AuthToken.get(data); | ||||
| 		if(token.is_valid){ | ||||
| 			return await User.get(token.created_by); | ||||
| 		} | ||||
| 	}catch(error){ | ||||
| 		throw this.errors.login(); | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| Auth.logOut = async function(data){ | ||||
| 	try{ | ||||
| 		let token = await AuthToken.get(data); | ||||
| 		await token.remove(); | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| module.exports = {Auth, AuthToken}; | ||||
							
								
								
									
										137
									
								
								nodejs/models/group_ldap.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								nodejs/models/group_ldap.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,137 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const { Client, Attribute, Change } = require('ldapts'); | ||||
| const conf = require('../app').conf.ldap; | ||||
|  | ||||
| const client = new Client({ | ||||
|   url: conf.url, | ||||
| }); | ||||
|  | ||||
| async function getGroups(client){ | ||||
| 	try{ | ||||
| 		let groups = (await client.search(conf.groupBase, { | ||||
| 			scope: 'sub', | ||||
| 			filter: '(&(objectClass=groupOfNames))', | ||||
| 			attributes: ['*', 'createTimestamp', 'modifyTimestamp'], | ||||
| 		})).searchEntries; | ||||
|  | ||||
| 		return groups.map(function(group){ | ||||
| 			if(!Array.isArray(group.member)) group.member = [group.member]; | ||||
| 			return group | ||||
| 		}); | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| async function addGroup(client, data){ | ||||
|   try{ | ||||
|  | ||||
|     await client.add(`cn=${data.name},${conf.groupBase}`, { | ||||
|       cn: data.name, | ||||
|       member: data.owner, | ||||
|       description: data.description, | ||||
|       owner: data.owner, | ||||
|       objectclass: [ 'groupOfNames', 'top'  ] | ||||
|     }); | ||||
|  | ||||
|     return data; | ||||
|  | ||||
|   }catch(error){ | ||||
|     throw error; | ||||
|   } | ||||
| } | ||||
|  | ||||
| async function addMember(client, group, user){ | ||||
| 	try{ | ||||
| 		await client.modify(group.dn, [ | ||||
| 			new Change({ | ||||
| 				operation: 'add', | ||||
| 				modification: new Attribute({ | ||||
| 					type: 'member', | ||||
| 					values: [user.dn]  | ||||
| 				}) | ||||
| 			}), | ||||
| 		]);  | ||||
| 	}catch(error){ | ||||
| 		if(error = "TypeOrValueExistsError")return ; | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| async function removeMember(client, group, user){ | ||||
|   try{ | ||||
|     await client.modify(group.dn, [ | ||||
|       new Change({ | ||||
|         operation: 'delete', | ||||
|         modification: new Attribute({ | ||||
|           type: 'member', | ||||
|           values: [user.dn]  | ||||
|         })}), | ||||
|     ]);  | ||||
|   }catch(error){ | ||||
|     if(error = "TypeOrValueExistsError")return ; | ||||
|     throw error; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| Group = {}; | ||||
|  | ||||
| Group.list = async function(){ | ||||
| 	try{ | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		let groups = await getGroups(client) | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		return groups.map(group => group.cn); | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| Group.listDetail = async function(){ | ||||
| 	try{ | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		let groups = await getGroups(client) | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		return groups; | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| Group.get = async function(data){ | ||||
| 	try{ | ||||
|  | ||||
| 		if(typeof data !== 'object'){ | ||||
| 			let name = data; | ||||
| 			data = {}; | ||||
| 			data.name = name; | ||||
| 		} | ||||
| 		 | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		let group = (await client.search(conf.groupBase, { | ||||
| 			scope: 'sub', | ||||
| 			filter: `(&(objectClass=groupOfNames)(cn=${data.name}))`, | ||||
| 			attributes: ['*', 'createTimestamp', 'modifyTimestamp'], | ||||
| 		})).searchEntries; | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		if(!Array.isArray(group.member)) group.member = [group.member]; | ||||
|  | ||||
| 		return group; | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| module.exports = {Group}; | ||||
							
								
								
									
										60
									
								
								nodejs/models/token.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								nodejs/models/token.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,60 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const redis_model = require('../utils/redis_model') | ||||
| const UUID = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}; | ||||
|  | ||||
|  | ||||
| const Token = function(data){ | ||||
| 	return redis_model({ | ||||
| 		_name: `token_${data.name}`, | ||||
| 		_key: 'token', | ||||
| 		_keyMap: Object.assign({}, { | ||||
| 			'created_by': {isRequired: true, type: 'string', min: 3, max: 500}, | ||||
| 			'created_on': {default: function(){return (new Date).getTime()}}, | ||||
| 			'updated_on': {default: function(){return (new Date).getTime()}, always: true}, | ||||
| 			'token': {default: UUID, type: 'string', min: 36, max: 36}, | ||||
| 			'is_valid': {default: true, type: 'boolean'} | ||||
| 		}, data.keyMap || {}) | ||||
| 	}); | ||||
| }; | ||||
|  | ||||
| Token.check = async function(data){ | ||||
| 	try{ | ||||
| 		return this.is_valid; | ||||
| 	}catch(error){ | ||||
| 		return false | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var InviteToken = Object.create(Token({ | ||||
| 	name: 'invite', | ||||
| 	keyMap:{ | ||||
| 		claimed_by: {default:"__NONE__", isRequired: false, type: 'string',} | ||||
| 	} | ||||
| })); | ||||
|  | ||||
| InviteToken.consume = async function(data){ | ||||
| 	try{ | ||||
| 		if(this.is_valid){ | ||||
| 			data['is_valid'] = false; | ||||
|  | ||||
| 			await this.update(data); | ||||
| 			return true; | ||||
| 		} | ||||
| 		return false; | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| var AuthToken = Object.create(Token({ | ||||
| 	name: 'auth', | ||||
| })); | ||||
|  | ||||
| AuthToken.add = async function(data){ | ||||
| 	data.created_by = data.username; | ||||
| 	return AuthToken.__proto__.add(data); | ||||
| }; | ||||
|  | ||||
| module.exports = {Token, InviteToken, AuthToken} | ||||
							
								
								
									
										7
									
								
								nodejs/models/user.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								nodejs/models/user.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,7 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const conf = require('../app').conf; | ||||
|  | ||||
| const User = require(`./user_${conf.userModel}`) | ||||
|  | ||||
| module.exports = User; | ||||
							
								
								
									
										327
									
								
								nodejs/models/user_ldap.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										327
									
								
								nodejs/models/user_ldap.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,327 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const { Client, Attribute, Change } = require('ldapts'); | ||||
| const crypto = require('crypto'); | ||||
|  | ||||
| const {Token, InviteToken} = require('./token'); | ||||
| const conf = require('../app').conf.ldap; | ||||
|  | ||||
| const client = new Client({ | ||||
|   url: conf.url, | ||||
| }); | ||||
|  | ||||
| async function addPosixGroup(client, data){ | ||||
|   try{ | ||||
|     const groups = (await client.search(conf.groupBase, { | ||||
|       scope: 'sub', | ||||
|       filter: '(&(objectClass=posixGroup))', | ||||
|     })).searchEntries; | ||||
|  | ||||
|     data.gidNumber = (Math.max(...groups.map(i => i.gidNumber))+1)+''; | ||||
|  | ||||
|     await client.add(`cn=${data.cn},${conf.groupBase}`, { | ||||
|       cn: data.cn, | ||||
|       gidNumber: data.gidNumber, | ||||
|       objectclass: [ 'posixGroup', 'top' ] | ||||
|     }); | ||||
|  | ||||
|     return data; | ||||
|  | ||||
|   }catch(error){ | ||||
|     throw error; | ||||
|   } | ||||
| } | ||||
|  | ||||
| async function addPosixAccount(client, data){ | ||||
|   try{ | ||||
|     const people = (await client.search(conf.userBase, { | ||||
|       scope: 'sub', | ||||
|       filter: conf.userFilter, | ||||
|     })).searchEntries; | ||||
|  | ||||
|     data.uidNumber = (Math.max(...people.map(i => i.uidNumber))+1)+''; | ||||
|  | ||||
|     await client.add(`cn=${data.cn},${conf.userBase}`, { | ||||
|       cn: data.cn, | ||||
|       sn: data.sn, | ||||
|       uid: data.uid, | ||||
|       uidNumber: data.uidNumber, | ||||
|       gidNumber: data.gidNumber, | ||||
|       mail: data.mail, | ||||
|       loginShell: data.loginShell, | ||||
|       homeDirectory: data.homeDirectory, | ||||
|       userPassword: data.userPassword, | ||||
|       objectclass: [ 'inetOrgPerson', 'posixAccount', 'top' ] | ||||
|     }); | ||||
|  | ||||
|     return data | ||||
|  | ||||
|   }catch(error){ | ||||
|     throw error; | ||||
|   } | ||||
|  | ||||
| } | ||||
|  | ||||
| async function addLdapUser(client, data){ | ||||
|  | ||||
|   try{ | ||||
|     data.uid = `${data.givenName[0]}${data.sn}`; | ||||
|     data.cn = data.uid; | ||||
|     data.loginShell = '/bin/bash'; | ||||
|     data.homeDirectory= `/home/${data.uid}`; | ||||
|     data.userPassword = '{MD5}'+crypto.createHash('md5').update(data.userPassword, "binary").digest('base64'); | ||||
|  | ||||
|     data = await addPosixGroup(client, data); | ||||
|     data = await addPosixAccount(client, data); | ||||
|  | ||||
|     return data; | ||||
|  | ||||
|   }catch(error){ | ||||
|     throw error; | ||||
|   } | ||||
| } | ||||
|  | ||||
|  | ||||
| async function changeLdapPassword(client, data){ | ||||
|   try{ | ||||
|     await client.modify(`cn=${data.uid},${conf.userBase}`, [ | ||||
|       new Change({ | ||||
|         operation: 'replace', | ||||
|         modification: new Attribute({ | ||||
|           type: 'userPassword', | ||||
|           values: ['{MD5}'+crypto.createHash('md5').update(data.userPassword, "binary").digest('base64')]  | ||||
|         })}), | ||||
|     ]);  | ||||
|   }catch(error){ | ||||
|     throw error; | ||||
|   } | ||||
| } | ||||
|  | ||||
| const user_parse = function(data){ | ||||
| 	if(data[conf.userNameAttribute]){ | ||||
| 		data.username = data[conf.userNameAttribute] | ||||
| 		// delete data[conf.userNameAttribute]; | ||||
| 	} | ||||
|  | ||||
| 	// if(data.uidNumber){ | ||||
| 	// 	data.uid = data.uidNumber; | ||||
| 	// 	delete data.uidNumber; | ||||
| 	// } | ||||
|  | ||||
| 	return data; | ||||
| } | ||||
|  | ||||
| var User = {} | ||||
|  | ||||
| User.backing = "LDAP"; | ||||
|  | ||||
| User.keyMap = { | ||||
| 	'username': {isRequired: true, type: 'string', min: 3, max: 500}, | ||||
| 	'password': {isRequired: true, type: 'string', min: 3, max: 500}, | ||||
| } | ||||
|  | ||||
| User.list = async function(){ | ||||
| 	try{ | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		const res = await client.search(conf.userBase, { | ||||
| 		  scope: 'sub', | ||||
| 		  filter: conf.userFilter, | ||||
| 		  attributes: ['*', 'createTimestamp', 'modifyTimestamp'], | ||||
| 		}); | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		return res.searchEntries.map(function(user){return user.uid}); | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| User.listDetail = async function(){ | ||||
| 	try{ | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		const res = await client.search(conf.userBase, { | ||||
| 		  scope: 'sub', | ||||
| 		  filter: conf.userFilter, | ||||
| 		  attributes: ['*', 'createTimestamp', 'modifyTimestamp'], | ||||
| 		}); | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		let users = [] | ||||
|  | ||||
| 		for(let user of res.searchEntries){ | ||||
| 			let obj = Object.create(this); | ||||
| 			Object.assign(obj, user_parse(user)); | ||||
| 			 | ||||
| 			users.push(obj) | ||||
|  | ||||
| 		} | ||||
|  | ||||
| 		return users; | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| User.get = async function(data){ | ||||
| 	try{ | ||||
| 		if(typeof data !== 'object'){ | ||||
| 			let username = data; | ||||
| 			data = {}; | ||||
| 			data.username = username; | ||||
| 		} | ||||
| 		 | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		let filter = `(&${conf.userFilter}(${conf.userNameAttribute}=${data.username}))`; | ||||
|  | ||||
| 		const res = await client.search(conf.userBase, { | ||||
| 			scope: 'sub', | ||||
| 			filter: filter, | ||||
| 			attributes: ['*', 'createTimestamp', 'modifyTimestamp'], | ||||
| 		}); | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		let user = res.searchEntries[0] | ||||
|  | ||||
| 		if(user){ | ||||
| 			let obj = Object.create(this); | ||||
| 			Object.assign(obj, user_parse(user)); | ||||
| 			 | ||||
| 			return obj; | ||||
| 		}else{ | ||||
| 			let error = new Error('UserNotFound'); | ||||
| 			error.name = 'UserNotFound'; | ||||
| 			error.message = `LDAP:${data.uid} does not exists`; | ||||
| 			error.status = 404; | ||||
| 			throw error; | ||||
| 		} | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| User.exists = async function(data){ | ||||
| 	// Return true or false if the requested entry exists ignoring error's. | ||||
| 	try{ | ||||
| 		await this.get(data); | ||||
|  | ||||
| 		return true | ||||
| 	}catch(error){ | ||||
| 		return false; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| User.add = async function(data) { | ||||
| 	try{ | ||||
| 		await client.bind(conf.bindDN, conf.bindPassword); | ||||
|  | ||||
| 		await addLdapUser(client, data); | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		return this.get(data.uid); | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		if(error.message.includes('exists')){ | ||||
| 			let error = new Error('UserNameUsed'); | ||||
| 			error.name = 'UserNameUsed'; | ||||
| 			error.message = `LDAP:${data.uid} already exists`; | ||||
| 			error.status = 409; | ||||
|  | ||||
| 			throw error; | ||||
| 		} | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| User.addByInvite = async function(data){ | ||||
| 	try{ | ||||
| 		let token = await InviteToken.get(data.token); | ||||
|  | ||||
| 		if(!token.is_valid){ | ||||
| 			let error = new Error('Token Invalid'); | ||||
| 			error.name = 'Token Invalid'; | ||||
| 			error.message = `Token is not valid or as allready been used. ${data.token}`; | ||||
| 			error.status = 401; | ||||
| 			throw error; | ||||
| 		} | ||||
|  | ||||
| 		let user = await this.add(data); | ||||
|  | ||||
| 		if(user){ | ||||
| 			await token.consume({claimed_by: user.uid}); | ||||
| 			return user; | ||||
| 		} | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
|  | ||||
| }; | ||||
|  | ||||
| // User.remove = async function(data){ | ||||
| // 	try{ | ||||
| // 		return await linuxUser.removeUser(this.username); | ||||
| // 	}catch(error){ | ||||
| // 		throw error; | ||||
| // 	} | ||||
| // }; | ||||
|  | ||||
| // User.setPassword = async function(data){ | ||||
| // 	try{ | ||||
| // 		await linuxUser.setPassword(this.username, data.password); | ||||
|  | ||||
| // 		return this; | ||||
| // 	}catch(error){ | ||||
| // 		throw error; | ||||
| // 	} | ||||
| // }; | ||||
|  | ||||
| User.invite = async function(){ | ||||
| 	try{ | ||||
| 		let token = await InviteToken.add({created_by: this.uid}); | ||||
| 		 | ||||
| 		return token; | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
| User.login = async function(data){ | ||||
| 	try{ | ||||
| 		let user = await this.get(data.uid); | ||||
|  | ||||
| 		await client.bind(user.dn, data.password); | ||||
|  | ||||
| 		await client.unbind(); | ||||
|  | ||||
| 		return user; | ||||
|  | ||||
| 	}catch(error){ | ||||
| 		throw error; | ||||
| 	} | ||||
| }; | ||||
|  | ||||
|  | ||||
| module.exports = {User}; | ||||
|  | ||||
|  | ||||
| // (async function(){ | ||||
| // try{ | ||||
| // 	console.log(await User.list()); | ||||
|  | ||||
| // 	console.log(await User.listDetail()); | ||||
|  | ||||
| // 	console.log(await User.get('wmantly')) | ||||
|  | ||||
| // }catch(error){ | ||||
| // 	console.error(error) | ||||
| // } | ||||
| // })() | ||||
		Reference in New Issue
	
	Block a user