major rewrite of the auth function
This commit is contained in:
parent
20052a773d
commit
1f405f7990
4 changed files with 89 additions and 56 deletions
88
clientsdb.py
88
clientsdb.py
|
@ -16,23 +16,28 @@ def addclient(vmid, vmname, clientid, clientname, clientemail, vmpass):
|
|||
clientsdb = readclientsdb()
|
||||
|
||||
if str(clientid) in clientsdb:
|
||||
ioconfig.logger.info('clients> client ' + clientid + ' already exists. merging.')
|
||||
ioconfig.logger.info('client[{}]> already exist. merging.'.format(clientid))
|
||||
else:
|
||||
ioconfig.logger.info('clients> client ' + clientid + ' does not exist. creating.')
|
||||
vcard = { 'name':str(clientname), 'email':str(clientemail) }
|
||||
ioconfig.logger.info('client[{}]> does not exist. creating...'.format(clientid))
|
||||
#generate password and send it to the client
|
||||
newpass = utils.genpassword(30)
|
||||
salt = bcrypt.gensalt()
|
||||
b_newpass = newpass.encode('utf-8')
|
||||
encpasswd = bcrypt.hashpw(b_newpass, salt).decode('utf-8')
|
||||
vcard = { 'name':str(clientname), 'email':str(clientemail), 'encpasswd':str(encpasswd) }
|
||||
newclient = { str(clientid):vcard }
|
||||
clientsdb.update(newclient)
|
||||
ioconfig.logger.info('clients> vmid {} owner set to {} (id: {}, email: {})'.format(vmid, clientname, clientid, clientemail))
|
||||
#TODO: 1. Send initial email to the user as we wont use the internal auth from now on.
|
||||
#TODO: 2. Sync with proxmaster-admin database (shell command could be used for this one)
|
||||
ioconfig.logger.info('client[{}]> vmid {} is now owned by {} ({})'.format(clientemail, vmid, clientid, clientname))
|
||||
|
||||
#create initial vm template
|
||||
vmdata = { 'hostname':str(vmname), 'vmid':str(vmid), 'ownerid':str(clientid) }
|
||||
clientsdb[str(clientid)][str(vmid)] = vmdata
|
||||
writeclientsdb(clientsdb)
|
||||
#set password for the first time...
|
||||
setencpasswd(vmname, vmpass)
|
||||
|
||||
|
||||
def setencpasswd(vmname, newpass):
|
||||
def setencpasswd(clientemail, newpass):
|
||||
""" setup a new management password """
|
||||
salt = bcrypt.gensalt()
|
||||
b_newpass = newpass.encode('utf-8')
|
||||
|
@ -41,62 +46,69 @@ def setencpasswd(vmname, newpass):
|
|||
try:
|
||||
clientsdb = readclientsdb()
|
||||
#print(clientsdb)
|
||||
path = utils.get_path(clientsdb, vmname)
|
||||
path = utils.get_path(clientsdb, clientemail)
|
||||
#print(path)
|
||||
c_id = str(path[0])
|
||||
v_id = str(path[1])
|
||||
#check the returned path with forward query
|
||||
query = clientsdb[c_id][v_id]['hostname']
|
||||
query = clientsdb[c_id]['email']
|
||||
except:
|
||||
raise
|
||||
|
||||
if query != vmname:
|
||||
ioconfig.logger.critical('clients> test query returns different vmname! check clients.json consistency!')
|
||||
if query != clientemail:
|
||||
ioconfig.logger.critical('clients.db> test query returns different vmname! check clients db for consistency!')
|
||||
raise
|
||||
else:
|
||||
clientsdb[c_id][v_id]['encpasswd'] = encpasswd
|
||||
ioconfig.logger.info('clients> {} (clientid: {}, vmid: {}) got its management password changed!'.format(query, c_id, v_id))
|
||||
clientsdb[c_id]['encpasswd'] = encpasswd
|
||||
ioconfig.logger.info('client[{}]> got its management password changed!'.format(clientemail))
|
||||
writeclientsdb(clientsdb)
|
||||
#TODO: change lxc container password
|
||||
#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, srvpass):
|
||||
""" return vmid or false if credentials match something in clientdb. useful for authing extrnal admin panels """
|
||||
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])
|
||||
#check the returned path with forward query
|
||||
ioconfig.logger.info('clients> {} was found with clientid: {}'.format(clientemail, c_id))
|
||||
ioconfig.logger.info('client[{}]> found. path={}'.format(clientemail, str(path)))
|
||||
except:
|
||||
raise
|
||||
ioconfig.logger.warning('clients> {} was not found in the database!'.format(clientemail))
|
||||
ioconfig.logger.warning('clients.db> {} was not found in the database!'.format(clientemail))
|
||||
#log bad ips here...
|
||||
return False
|
||||
|
||||
vmlist = clientsdb[c_id]
|
||||
#2. check the password
|
||||
encpass = clientsdb[c_id]['encpasswd']
|
||||
b_srvpass = password.encode('utf-8')
|
||||
b_encpass = encpass.encode('utf-8')
|
||||
|
||||
if (hmac.compare_digest(bcrypt.hashpw(b_srvpass, b_encpass), b_encpass)):
|
||||
#login successful
|
||||
ioconfig.logger.info('client[{}]> logged in successfully'.format(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(vmid))
|
||||
#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')
|
||||
|
||||
#try each vmid owned by this user for a password match
|
||||
|
||||
response = []
|
||||
for vmid,data in vmlist.items():
|
||||
print(vmid)
|
||||
|
||||
print(data)
|
||||
#try to capture the encrypted password
|
||||
encpass = data['encpasswd']
|
||||
b_srvpass = srvpass.encode('utf-8')
|
||||
b_encpass = encpass.encode('utf-8')
|
||||
if (hmac.compare_digest(bcrypt.hashpw(b_srvpass, b_encpass), b_encpass)):
|
||||
#login successful
|
||||
ioconfig.logger.info('clients> {} was validated successfully by {}'.format(vmid, clientemail))
|
||||
response = { 'vmid':vmid }
|
||||
else:
|
||||
ioconfig.logger.warning('clients> {} ACCESS DENIED!'.format(vmid))
|
||||
#cant compare password
|
||||
response = { }
|
||||
#TODO: this will require major rewrite again.. or it will fail to auth 2 machines with same password. lame..
|
||||
response = { 'vmid':vmid }
|
||||
return response
|
||||
|
||||
|
||||
|
@ -136,5 +148,5 @@ def writeclientsdb(clientsdb):
|
|||
|
||||
|
||||
if __name__ == '__main__':
|
||||
#setencpasswd('srv.test1.com', 'todos')
|
||||
validate('daniel@deflax.net', 'todos')
|
||||
setencpasswd('daniel@deflax.net', 'todos')
|
||||
print(validate('daniel@deflax.net', 'todos'))
|
||||
|
|
6
grid.py
6
grid.py
|
@ -168,7 +168,7 @@ def query_region(region_name):
|
|||
|
||||
for region in all_regions:
|
||||
if grid_data[region]['region'] == region_name:
|
||||
logger.info('grid> region ' + region_name + ' found')
|
||||
logger.info('region[{}]> found: id={}'.format(region_name, region))
|
||||
return grid_data[region]['id']
|
||||
break
|
||||
logger.error('grid> cant find region ' + region_name)
|
||||
|
@ -339,10 +339,10 @@ def query_vm(req_vmid):
|
|||
try:
|
||||
vm_type = grid_data[str(region_id)][str(slave_id)][str(target)]['type']
|
||||
except:
|
||||
logger.error('{}> type is unknown!'.format(vm_id))
|
||||
logger.error('vm[{}]> type is unknown!'.format(vm_id))
|
||||
raise
|
||||
|
||||
logger.info('{}> region={}, slave={}, type={} found.'.format(target, region_id, slave_id, vm_type))
|
||||
logger.info('vm[{}]> type {} found. path=region={} found.'.format(target, vm_type, str(path)))
|
||||
|
||||
return slave_id, vm_type
|
||||
|
||||
|
|
28
plugin.py
28
plugin.py
|
@ -148,13 +148,13 @@ def vmstart(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> starting %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> starting %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
result = proxobject.nodes(slave_name).qemu(vm_id).status.start.post()
|
||||
if vm_type == 'lxc':
|
||||
result = proxobject.nodes(slave_name).lxc(vm_id).status.start.post()
|
||||
#ioconfig.logger.info('grid[{}]> {}'.format(slave_name, result))
|
||||
#ioconfig.logger.info('slave[{}]> {}'.format(slave_name, result))
|
||||
response = { 'status':'START' }
|
||||
return response
|
||||
|
||||
|
@ -165,13 +165,13 @@ def vmshutdown(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> acpi shutdown %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> acpi shutdown %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
result = proxobject.nodes(slave_name).qemu(vm_id).status.stop.post()
|
||||
if vm_type == 'lxc':
|
||||
result = proxobject.nodes(slave_name).lxc(vm_id).status.stop.post()
|
||||
#ioconfig.logger.info('grid[{}]> {}'.format(slave_name, result))
|
||||
#ioconfig.logger.info('slave[{}]> {}'.format(slave_name, result))
|
||||
response = { 'status':'SHUTDOWN', 'vmid':vm_id }
|
||||
return response
|
||||
|
||||
|
@ -182,13 +182,13 @@ def vmstop(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> power off %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> power off %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
result = proxobject.nodes(slave_name).qemu(vm_id).status.stop.post()
|
||||
if vm_type == 'lxc':
|
||||
result = proxobject.nodes(slave_name).lxc(vm_id).status.stop.post()
|
||||
#ioconfig.logger.info('grid[{}]> {}'.format(slave_name, result))
|
||||
#ioconfig.logger.info('slave[{}]> {}'.format(slave_name, result))
|
||||
response = { 'status':'STOP', 'vmid':vm_id }
|
||||
return response
|
||||
|
||||
|
@ -199,13 +199,13 @@ def vmshutdown(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> acpi shutdown sent to %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> acpi shutdown sent to %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
result = proxobject.nodes(slave_name).qemu(vm_id).status.shutdown.post()
|
||||
if vm_type == 'lxc':
|
||||
result = proxobject.nodes(slave_name).lxc(vm_id).status.shutdown.post()
|
||||
#ioconfig.logger.info('grid[{}]> {}'.format(slave_name, result))
|
||||
#ioconfig.logger.info('slave[{}]> {}'.format(slave_name, result))
|
||||
response = { 'status':'SHUTDOWN', 'vmid':vm_id }
|
||||
return response
|
||||
|
||||
|
@ -216,13 +216,13 @@ def vmsuspend(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> suspending %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> suspending %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
result = proxobject.nodes(slave_name).qemu(vm_id).status.suspend.post()
|
||||
if vm_type == 'lxc':
|
||||
result = proxobject.nodes(slave_name).lxc(vm_id).status.suspend.post()
|
||||
#ioconfig.logger.info('grid[{}]> {}'.format(slave_name, result))
|
||||
#ioconfig.logger.info('slave[{}]> {}'.format(slave_name, result))
|
||||
response = { 'status':'SUSPEND', 'vmid':vm_id }
|
||||
return response
|
||||
|
||||
|
@ -233,13 +233,13 @@ def vmresume(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> resuming %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> resuming %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
result = proxobject.nodes(slave_name).qemu(vm_id).status.resume.post()
|
||||
if vm_type == 'lxc':
|
||||
result = proxobject.nodes(slave_name).lxc(vm_id).status.resume.post()
|
||||
#ioconfig.logger.info('grid[{}]> {}'.format(slave_name, result))
|
||||
#ioconfig.logger.info('slave[{}]> {}'.format(slave_name, result))
|
||||
response = { 'status':'RESUME', 'vmid':vm_id }
|
||||
return response
|
||||
|
||||
|
@ -250,7 +250,7 @@ def vmvnc(vm_id):
|
|||
proxobject = auth(slave_id)
|
||||
vm_type = vm_type.lower()
|
||||
slave_name = proxobject.cluster.status.get()[0]['name']
|
||||
ioconfig.logger.info('grid[%s]> invoking vnc ticket for %s %s' % (slave_name, vm_type, vm_id))
|
||||
ioconfig.logger.info('slave[%s]> invoking vnc ticket for %s %s' % (slave_name, vm_type, vm_id))
|
||||
|
||||
if vm_type == 'kvm':
|
||||
ticket = proxobject.nodes(slave_name).qemu(vm_id).vncproxy.post(websocket=1)
|
||||
|
@ -282,7 +282,7 @@ def vmvnc(vm_id):
|
|||
external_url = ioconfig.parser.get('general', 'novnc_url')
|
||||
prefix = external_url + "/?host=" + myip + "&port=" + listenport + "&encrypt=0&true_color=1&password="
|
||||
vnc_url = prefix + ticket['ticket']
|
||||
ioconfig.logger.info('grid[{}]> {}'.format(slave_name, vnc_url))
|
||||
ioconfig.logger.info('slave[{}]> {}'.format(slave_name, vnc_url))
|
||||
|
||||
response = { 'status':'VNC', 'fqdn':external_url, 'host':myip, 'port':listenport, 'encrypt':'0', 'true_color':'1', 'ticket':ticket['ticket'] }
|
||||
return response
|
||||
|
|
23
utils.py
23
utils.py
|
@ -2,8 +2,27 @@
|
|||
#
|
||||
# helper functions
|
||||
|
||||
from copy import deepcopy
|
||||
import functools
|
||||
from copy import deepcopy
|
||||
from random import SystemRandom
|
||||
|
||||
|
||||
def genpassword(length=20):
|
||||
""" generates pseudo-random password """
|
||||
choice = SystemRandom().choice
|
||||
charsets = [
|
||||
'abcdefghijklmnopqrstuvwxyz',
|
||||
'ABCDEFGHIJKLMNOPQRSTUVWXYZ',
|
||||
'0123456789',
|
||||
'%&=?+~#-_.',
|
||||
]
|
||||
pwd = []
|
||||
charset = choice(charsets)
|
||||
while len(pwd) < length:
|
||||
pwd.append(choice(charset))
|
||||
charset = choice(list(set(charsets) - set([charset])))
|
||||
return "".join(pwd)
|
||||
|
||||
|
||||
def dict_merge(target, *args):
|
||||
""" Recursively merges mutiple dicts """
|
||||
|
@ -24,6 +43,7 @@ def dict_merge(target, *args):
|
|||
target[k] = deepcopy(v)
|
||||
return target
|
||||
|
||||
|
||||
def find_rec(search_dict, field):
|
||||
"""
|
||||
Takes a dict with nested lists and dicts,
|
||||
|
@ -68,3 +88,4 @@ def chained_get(dct, *keys):
|
|||
return 'NA' if level is SENTRY else level.get(key, SENTRY)
|
||||
return functools.reduce(getter, keys, dct)
|
||||
|
||||
|
||||
|
|
Loading…
Reference in a new issue