From b656df33ba1ee0551e03e1317ba44340bcc750ac Mon Sep 17 00:00:00 2001 From: Jordan Rodgers Date: Tue, 12 Dec 2017 15:41:25 -0500 Subject: [PATCH] use oidc for auth, remove proxtar from paths, check if rtp when necessary --- app.py | 97 ++++++++++++++++++++++++++++------------- proxmox.py | 4 +- starrs.py | 2 + static/js/script.js | 64 +++++++++++++-------------- templates/base.html | 18 ++++---- templates/list_vms.html | 4 +- 6 files changed, 115 insertions(+), 74 deletions(-) diff --git a/app.py b/app.py index 8b55fe0..e2ec590 100644 --- a/app.py +++ b/app.py @@ -5,7 +5,8 @@ import subprocess from db import * from starrs import * from proxmox import * -from flask import Flask, render_template, request, redirect, send_from_directory +from flask_pyoidc.flask_pyoidc import OIDCAuthentication +from flask import Flask, render_template, request, redirect, send_from_directory, session app = Flask(__name__) @@ -16,11 +17,16 @@ app.config.from_pyfile(config) app.config["GIT_REVISION"] = subprocess.check_output( ['git', 'rev-parse', '--short', 'HEAD']).decode('utf-8').rstrip() -user = 'proxstar' +auth = OIDCAuthentication(app, + issuer=app.config['OIDC_ISSUER'], + client_registration_info=app.config['OIDC_CLIENT_CONFIG']) @app.route("/") +@auth.oidc_auth def list_vms(): + user = session['userinfo']['preferred_username'] + rtp = 'rtp' in session['userinfo']['groups'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) @@ -29,7 +35,7 @@ def list_vms(): if 'name' not in vm: vms.remove(vm) vms = sorted(vms, key=lambda k: k['name']) - return render_template('list_vms.html', username='com6056', vms=vms) + return render_template('list_vms.html', username=user, rtp=rtp, vms=vms) @app.route("/isos") @@ -57,13 +63,15 @@ def hostname(name): @app.route("/vm/") def vm_details(vmid): + user = session['userinfo']['preferred_username'] + rtp = 'rtp' in session['userinfo']['groups'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) starrs = connect_starrs( app.config['STARRS_DB_NAME'], app.config['STARRS_DB_USER'], app.config['STARRS_DB_HOST'], app.config['STARRS_DB_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: vm = get_vm(proxmox, vmid) vm['vmid'] = vmid vm['config'] = get_vm_config(proxmox, vmid) @@ -76,17 +84,18 @@ def vm_details(vmid): usage = get_user_usage(proxmox, 'proxstar') limits = get_user_usage_limits(user) usage_check = check_user_usage(proxmox, user, vm['config']['cores'], vm['config']['memory'], 0) - return render_template('vm_details.html', username='com6056', vm=vm, usage=usage, limits=limits, usage_check=usage_check) + return render_template('vm_details.html', username=user, rtp=rtp, vm=vm, usage=usage, limits=limits, usage_check=usage_check) else: return '', 403 @app.route("/vm//power/", methods=['POST']) def vm_power(vmid, action): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: if action == 'start': config = get_vm_config(proxmox, vmid) usage_check = check_user_usage(proxmox, user, config['cores'], config['memory'], 0) @@ -100,10 +109,11 @@ def vm_power(vmid, action): @app.route("/vm//cpu/", methods=['POST']) def vm_cpu(vmid, cores): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: cur_cores = get_vm_config(proxmox, vmid)['cores'] if cores >= cur_cores: status = get_vm(proxmox, vmid)['qmpstatus'] @@ -121,10 +131,11 @@ def vm_cpu(vmid, cores): @app.route("/vm//mem/", methods=['POST']) def vm_mem(vmid, mem): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: cur_mem = get_vm_config(proxmox, vmid)['memory'] // 1024 if mem >= cur_mem: status = get_vm(proxmox, vmid)['qmpstatus'] @@ -142,13 +153,14 @@ def vm_mem(vmid, mem): @app.route("/vm//renew", methods=['POST']) def vm_renew(vmid): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) starrs = connect_starrs( app.config['STARRS_DB_NAME'], app.config['STARRS_DB_USER'], app.config['STARRS_DB_HOST'], app.config['STARRS_DB_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: renew_vm_expire(vmid, app.config['VM_EXPIRE_MONTHS']) for interface in get_vm_interfaces(proxmox, vmid): renew_ip(starrs, get_ip_for_mac(starrs, interface[1])) @@ -159,10 +171,11 @@ def vm_renew(vmid): @app.route("/vm//eject", methods=['POST']) def iso_eject(vmid): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: eject_vm_iso(proxmox, vmid) return '', 200 else: @@ -171,10 +184,11 @@ def iso_eject(vmid): @app.route("/vm//mount/", methods=['POST']) def iso_mount(vmid, iso): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: iso = "{}:iso/{}".format(app.config['PROXMOX_ISO_STORAGE'], iso) mount_vm_iso(proxmox, vmid, iso) return '', 200 @@ -184,13 +198,14 @@ def iso_mount(vmid, iso): @app.route("/vm//delete", methods=['POST']) def delete(vmid): + user = session['userinfo']['preferred_username'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) starrs = connect_starrs( app.config['STARRS_DB_NAME'], app.config['STARRS_DB_USER'], app.config['STARRS_DB_HOST'], app.config['STARRS_DB_PASS']) - if int(vmid) in get_user_allowed_vms(proxmox, user): + if int(vmid) in get_user_allowed_vms(proxmox, user) or 'rtp' in session['userinfo']['groups']: vmname = get_vm_config(proxmox, vmid)['name'] delete_vm(proxmox, starrs, vmid) delete_starrs(starrs, vmname) @@ -202,6 +217,8 @@ def delete(vmid): @app.route("/vm/create", methods=['GET', 'POST']) def create(): + user = session['userinfo']['preferred_username'] + rtp = 'rtp' in session['userinfo']['groups'] proxmox = connect_proxmox(app.config['PROXMOX_HOST'], app.config['PROXMOX_USER'], app.config['PROXMOX_PASS']) @@ -215,7 +232,8 @@ def create(): isos = get_isos(proxmox, app.config['PROXMOX_ISO_STORAGE']) return render_template( 'create.html', - username='com6056', + username=user, + rtp=rtp, usage=usage, limits=limits, percents=percents, @@ -245,32 +263,43 @@ def create(): @app.route('/limits/', methods=['POST']) def set_limits(user): - cpu = request.form['cpu'] - mem = request.form['mem'] - disk = request.form['disk'] - set_user_usage_limits(user, cpu, mem, disk) - return '', 200 + if 'rtp' in session['userinfo']['groups']: + cpu = request.form['cpu'] + mem = request.form['mem'] + disk = request.form['disk'] + set_user_usage_limits(user, cpu, mem, disk) + return '', 200 + else: + return '', 403 @app.route('/limits//reset', methods=['POST']) def reset_limits(user): - delete_user_usage_limits(user) - return '', 200 + if 'rtp' in session['userinfo']['groups']: + delete_user_usage_limits(user) + return '', 200 + else: + return '', 403 @app.route('/limits') def limits(): - proxmox = connect_proxmox(app.config['PROXMOX_HOST'], - app.config['PROXMOX_USER'], - app.config['PROXMOX_PASS']) - pools = get_pools(proxmox) - pools = sorted(pools) - user_limits = [] - for pool in pools: - if pool not in app.config['IGNORED_POOLS']: - limits = get_user_usage_limits(pool) - user_limits.append([pool, limits['cpu'], limits['mem'], limits['disk']]) - return render_template('limits.html', username='com6056', user_limits=user_limits) + if 'rtp' in session['userinfo']['groups']: + user = session['userinfo']['preferred_username'] + rtp = 'rtp' in session['userinfo']['groups'] + proxmox = connect_proxmox(app.config['PROXMOX_HOST'], + app.config['PROXMOX_USER'], + app.config['PROXMOX_PASS']) + pools = get_pools(proxmox) + pools = sorted(pools) + user_limits = [] + for pool in pools: + if pool not in app.config['IGNORED_POOLS']: + limits = get_user_usage_limits(pool) + user_limits.append([pool, limits['cpu'], limits['mem'], limits['disk']]) + return render_template('limits.html', username=user, rtp=rtp, user_limits=user_limits) + else: + return '', 403 @app.route('/novnc/') @@ -278,5 +307,11 @@ def send_novnc(path): return send_from_directory('static/novnc-pve/novnc', path) +@app.route("/logout") +@auth.oidc_logout +def logout(): + return redirect(url_for('list_vms'), 302) + + if __name__ == "__main__": app.run(debug=True) diff --git a/proxmox.py b/proxmox.py index 082c3db..b5c740e 100644 --- a/proxmox.py +++ b/proxmox.py @@ -14,6 +14,8 @@ def connect_proxmox(host, user, password): def get_vms_for_user(proxmox, user): + if user not in get_pools(proxmox): + proxmox.pools.post(poolid=user, comment='Managed by Proxstar') return proxmox.pools(user).get()['members'] @@ -96,7 +98,7 @@ def get_vm_disks(proxmox, vmid, config=None): for key, val in config.items(): valid_disk_types = ['virtio', 'ide', 'sata', 'scsi'] if any(disk_type in key for disk_type in valid_disk_types): - if 'cdrom' not in val: + if 'scsihw' not in key and 'cdrom' not in val: disk_size = val.split(',') if 'size' in disk_size[0]: disk_size = disk_size[0].split('=')[1].rstrip('G') diff --git a/starrs.py b/starrs.py index a773fb7..d8385c6 100644 --- a/starrs.py +++ b/starrs.py @@ -34,6 +34,8 @@ def get_ip_for_mac(starrs, mac): c.execute("COMMIT") finally: c.close() + if not results: + return 'No IP' return results[0][3] diff --git a/static/js/script.js b/static/js/script.js index 41b9c9c..4b25a19 100644 --- a/static/js/script.js +++ b/static/js/script.js @@ -16,7 +16,7 @@ $("#delete-vm").click(function(){ .then((willDelete) => { if (willDelete) { const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/delete`, { + fetch(`/vm/${vmid}/delete`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -24,7 +24,7 @@ $("#delete-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = "/proxstar"; + window.location = ""; }).catch(err => { if (err) { swal("Uh oh...", `Unable to delete ${vmname}. Please try again later.`, "error"); @@ -55,7 +55,7 @@ $("#stop-vm").click(function(){ .then((willStop) => { if (willStop) { const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/power/stop`, { + fetch(`/vm/${vmid}/power/stop`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -63,7 +63,7 @@ $("#stop-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to stop ${vmname}. Please try again later.`, "error"); @@ -94,7 +94,7 @@ $("#reset-vm").click(function(){ .then((willReset) => { if (willReset) { const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/power/reset`, { + fetch(`/vm/${vmid}/power/reset`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -102,7 +102,7 @@ $("#reset-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to reset ${vmname}. Please try again later.`, "error"); @@ -133,7 +133,7 @@ $("#shutdown-vm").click(function(){ .then((willShutdown) => { if (willShutdown) { const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/power/shutdown`, { + fetch(`/vm/${vmid}/power/shutdown`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -141,7 +141,7 @@ $("#shutdown-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to shutdown ${vmname}. Please try again later.`, "error"); @@ -172,7 +172,7 @@ $("#suspend-vm").click(function(){ .then((willSuspend) => { if (willSuspend) { const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/power/suspend`, { + fetch(`/vm/${vmid}/power/suspend`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -180,7 +180,7 @@ $("#suspend-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to suspend ${vmname}. Please try again later.`, "error"); @@ -196,7 +196,7 @@ $("#suspend-vm").click(function(){ $("#start-vm").click(function(){ const vmname = $(this).data('vmname') const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/power/start`, { + fetch(`/vm/${vmid}/power/start`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -204,7 +204,7 @@ $("#start-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to start ${vmname}. Please try again later.`, "error"); @@ -218,7 +218,7 @@ $("#start-vm").click(function(){ $("#resume-vm").click(function(){ const vmname = $(this).data('vmname') const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/power/resume`, { + fetch(`/vm/${vmid}/power/resume`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -226,7 +226,7 @@ $("#resume-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to resume ${vmname}. Please try again later.`, "error"); @@ -261,7 +261,7 @@ $("#eject-iso").click(function(){ .then((willEject) => { if (willEject) { const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/eject`, { + fetch(`/vm/${vmid}/eject`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -276,7 +276,7 @@ $("#eject-iso").click(function(){ } }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to eject ${iso}. Please try again later.`, "error"); @@ -292,7 +292,7 @@ $("#eject-iso").click(function(){ $("#change-iso").click(function(){ const vmid = $(this).data('vmid') - fetch(`/proxstar/isos`, { + fetch(`/isos`, { credentials: 'same-origin', }).then((response) => { return response.text() @@ -324,7 +324,7 @@ $("#change-iso").click(function(){ if (willChange) { const vmid = $(this).data('vmid') const iso = $(iso_list).val() - fetch(`/proxstar/vm/${vmid}/mount/${iso}`, { + fetch(`/vm/${vmid}/mount/${iso}`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -339,7 +339,7 @@ $("#change-iso").click(function(){ } }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to mount ${iso}. Please try again later.`, "error"); @@ -363,7 +363,7 @@ $("#change-iso").click(function(){ $("#renew-vm").click(function(){ const vmname = $(this).data('vmname') const vmid = $(this).data('vmid') - fetch(`/proxstar/vm/${vmid}/renew`, { + fetch(`/vm/${vmid}/renew`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -371,7 +371,7 @@ $("#renew-vm").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to renew ${vmname}. Please try again later.`, "error"); @@ -393,7 +393,7 @@ $("#create-vm").click(function(){ if (disk > max_disk) { swal("Uh oh...", `You do not have enough disk resources available! Please lower the VM disk size to ${max_disk}GB or lower.`, "error"); } else { - fetch(`/proxstar/hostname/${name}`, { + fetch(`/hostname/${name}`, { credentials: 'same-origin', }).then((response) => { return response.text() @@ -424,14 +424,14 @@ $("#create-vm").click(function(){ data.append('mem', mem); data.append('disk', disk); data.append('iso', iso); - fetch('/proxstar/vm/create', { + fetch('/vm/create', { credentials: 'same-origin', method: 'post', body: data }).then((response) => { return response.text() }).then((vmid) => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }); } }); @@ -488,7 +488,7 @@ $("#change-cores").click(function(){ .then((willChange) => { if (willChange) { const cores = $(core_list).val() - fetch(`/proxstar/vm/${vmid}/cpu/${cores}`, { + fetch(`/vm/${vmid}/cpu/${cores}`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -503,7 +503,7 @@ $("#change-cores").click(function(){ } }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }); } }).catch(err => { @@ -546,7 +546,7 @@ $("#change-mem").click(function(){ .then((willChange) => { if (willChange) { const mem = $(mem_list).val() - fetch(`/proxstar/vm/${vmid}/mem/${mem}`, { + fetch(`/vm/${vmid}/mem/${mem}`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -561,7 +561,7 @@ $("#change-mem").click(function(){ } }); }).then(() => { - window.location = `/proxstar/vm/${vmid}`; + window.location = `/vm/${vmid}`; }); } }).catch(err => { @@ -624,7 +624,7 @@ $(".edit-limit").click(function(){ data.append('cpu', $(cpu).val()); data.append('mem', $(mem).val()); data.append('disk', $(disk).val()); - fetch(`/proxstar/limits/${user}`, { + fetch(`/limits/${user}`, { credentials: 'same-origin', method: 'post', body: data @@ -640,7 +640,7 @@ $(".edit-limit").click(function(){ } }); }).then(() => { - window.location = `/proxstar/limits`; + window.location = `/limits`; }); } }).catch(err => { @@ -670,7 +670,7 @@ $(".reset-limit").click(function(){ }) .then((willReset) => { if (willReset) { - fetch(`/proxstar/limits/${user}/reset`, { + fetch(`/limits/${user}/reset`, { credentials: 'same-origin', method: 'post' }).then((response) => { @@ -678,7 +678,7 @@ $(".reset-limit").click(function(){ icon: "success", }); }).then(() => { - window.location = `/proxstar/limits`; + window.location = `/limits`; }).catch(err => { if (err) { swal("Uh oh...", `Unable to reset the usage limits for ${user}. Please try again later.`, "error"); diff --git a/templates/base.html b/templates/base.html index e2809bf..239ab09 100644 --- a/templates/base.html +++ b/templates/base.html @@ -5,9 +5,9 @@ - - - + + + @@ -22,28 +22,30 @@ - Proxstar + Proxstar