# -*- coding: utf-8 # # manage clientsdb.json #import site packages import json import hmac import bcrypt #import local packages import ioconfig import utils def addclient(vmid, vmname, clientid, clientname, clientemail, vmpass): """ add new client with the requested vm to the clientsdb.json """ clientsdb = readclientsdb() if str(clientid) in clientsdb: ioconfig.logger.info('client[{}]> already exist. merging.'.format(clientid)) else: ioconfig.logger.info('client[{}]> does not exist. creating...'.format(clientid)) #generate password and send it to the client newpass = utils.genpassword(30) ioconfig.logger.info('client[{}]> initial password is: {}'.format(clientid, newpass)) salt = bcrypt.gensalt() b_newpass = newpass.encode('ascii') encpasswd = bcrypt.hashpw(b_newpass, salt).decode('ascii') vcard = { 'name':str(clientname), 'email':str(clientemail), 'encpasswd':str(encpasswd) } newclient = { str(clientid):vcard } clientsdb.update(newclient) #Send initial email to the user as we will use the internal auth from now on. ###utils.sendmail(clientemail, 'W{} logged in.'.format) #TODO: Sync with proxmaster-admin database (shell command could be used for this one) ioconfig.logger.info('client[{}]> vmid {} is now owned by {} ({})'.format(clientid, vmid, clientemail, clientname)) #create initial vm template vmdata = { 'hostname':str(vmname), 'vmid':str(vmid), 'ownerid':str(clientid) } clientsdb[str(clientid)][str(vmid)] = vmdata writeclientsdb(clientsdb) def setencpasswd(clientemail, newpass): """ setup a new management password """ salt = bcrypt.gensalt() b_newpass = newpass.encode('ascii') encpasswd = bcrypt.hashpw(b_newpass, salt).decode('ascii') try: clientsdb = readclientsdb() path = utils.get_path(clientsdb, clientemail) c_id = str(path[0]) #check the returned path with forward query query = clientsdb[c_id]['email'] #ioconfig.logger.info('client[{}]> path={}'.format(c_id, str(path))) except: ioconfig.logger.critical('clients> client {} not found'.format(clientemail)) raise if query != clientemail: ioconfig.logger.critical('clients> test query returns different vmname! check clients db for consistency!') raise else: clientsdb[c_id]['encpasswd'] = encpasswd ioconfig.logger.info('client[{}]> {} password changed!'.format(c_id, clientemail)) writeclientsdb(clientsdb) #TODO: Send new email to the client to notify the password change. This time sending the password in plain text is not needed. def validate(clientemail, password): """ return list of owned vmids or false if credentials match an user form the database. useful for authing extrnal admin panels """ #1. search for the client try: clientsdb = readclientsdb() path = utils.get_path(clientsdb, clientemail) c_id = str(path[0]) #ioconfig.logger.info('client[{}]> path={}'.format(c_id, str(path))) except: ioconfig.logger.warning('clients> {} was not found in the database!'.format(clientemail)) #log bad ips here... return {} #2. check the password encpass = clientsdb[c_id]['encpasswd'] b_srvpass = password.encode('ascii') b_encpass = encpass.encode('ascii') if (hmac.compare_digest(bcrypt.hashpw(b_srvpass, b_encpass), b_encpass)): #login successful ioconfig.logger.info('client[{}]> {} logged in successfully'.format(c_id, clientemail)) #TODO: Notify admin #3. generate vmlist to return the owned ids to the client. return clientvms(clientsdb[c_id]) else: ioconfig.logger.warning('clients> {} access denied!'.format(clientemail)) #cant compare password #TODO: Log attempts and block. return {} def clientvms(vmlist): """ generate vmlist """ #clear unused objects. perhaps there is a better way to do this but im kinda anxious today... vmlist.pop('name') vmlist.pop('email') vmlist.pop('encpasswd') response = {} for vmid,data in vmlist.items(): response[vmid] = data return response def vmowner(vmid, vmname, verbose): """ find the owner of the vm """ clientsdb = readclientsdb() try: clientid = utils.find_rec(clientsdb, str(vmid))[0]['ownerid'] clientname = clientsdb[str(clientid)]['name'] except: raise clientid = '0' #unknown owner clientname = 'unknown' if verbose: ioconfig.logger.info('client[{}]> {} is the owner of {} ({})'.format(str(clientid), clientname, str(vmid), vmname)) return clientid def readclientsdb(): """ read client db """ try: with open('clients.json') as dbr: clientsdb = json.load(dbr) dbr.close() except: clientsdb = {} ioconfig.logger.warning('clients> initializing...') #writeclientsdb(clientsdb) return clientsdb def writeclientsdb(clientsdb): """ write db """ with open('clients.json', 'w') as dbw: json.dump(clientsdb, dbw) dbw.close() if __name__ == '__main__': setencpasswd('abc@xyz.com', 'todos')