def edit_user(): """Render page for editing user information. This page can only be accessed by an admin """ if not current_user.admin: return abort(403) username = request.args.get('username', '') if username == '': flash('No username specified') abort(404) user = database.get_user(username) if user is None: flash('Unknown username') abort(404) if request.method == 'POST': successful = form_parsers.update_user(username) if successful: database.save_changes() flash('Settings successfully saved', 'info') return redirect(url_for('user_managment')) else: database.revert_changes() flash(messages.ERROR_MESSAGE['invalid_settings'], 'error') user_data = database.get_user_data(username) return render_template('edit_user.html', user=user_data)
def probe_setup(): """Render page for adding/editing probe data. Also parse data on POST. More specifically, the data that can be changed are: - Basic probe info (name, MAC and location) - Script configurations (interval and enabled/disabled for each script) - Network configration (SSID, anon id, username, password, cert) """ probe_id = request.args.get('id', '') if probe_id == '': flash('No probe ID specified') abort(404) probe_id = util.convert_mac(probe_id, mode='storage') probe = database.get_probe(probe_id) if probe is None or probe.user.username != current_user.username: flash('Unknown probe ID') abort(404) if request.method == 'POST': successful_script_update = form_parsers.update_scripts() successful_network_update = form_parsers.update_network_configs() successful_certificate_upload = form_parsers.upload_certificate( probe_id, current_user.username) successful_probe_update = form_parsers.update_probe(probe_id) if (successful_script_update and successful_probe_update and successful_network_update and successful_certificate_upload): database.save_changes() action = request.form.get('action', '') if action == 'save_as_default': ansible.export_group_config( current_user.username, {'group_script_configs': database.get_script_data(probe)}, 'script_configs') ansible.export_group_config( current_user.username, {'networks': database.get_network_config_data(probe)}, 'network_configs') ansible.make_certificate_default(probe_id, current_user.username) return redirect(url_for('probes')) else: database.revert_changes() return generate_probe_setup_template(probe_id, current_user.username)
def register_key(): """Takes an SSH public key, host key and a MAC, and registers it to the corresponding probe if a probe with that MAC has been added through the website. The function can give the following responses (with explanation): invalid-mac : The supplied MAC was invalid (in form) unknown-mac : The MAC was valid, but is not in the database invalid-pub-key : The pub key was invalid (in form) invalid-host-key : The host key was invalid (in form) already-registered : There already exists keys associated with this MAC assocation-period-expired : The assocation period has expired and needs to be renewed through the web site success : The keys were successfully registered/associated with the corresponding MAC address """ mac = request.form.get('mac', '') if not util.is_mac_valid(mac): return 'invalid-mac' mac = util.convert_mac(mac, mode='storage') probe = database.get_probe(mac) if probe is None: return 'unknown-mac' pub_key = request.form.get('pub_key', '') host_key = request.form.get('host_key', '') if pub_key == '' or not util.is_pub_ssh_key_valid(pub_key): return 'invalid-pub-key' if host_key == '' or not util.is_ssh_host_key_valid(host_key): return 'invalid-host-key' if probe.pub_key != '' or probe.host_key != '': return 'already-registered' if probe.association_period_expired(): return 'association-period-expired' probe.set_pub_key(pub_key) probe.set_host_key(host_key) probe.associated = True database.save_changes() ansible.export_known_hosts(database) return 'success'
def user_managment(): """Render page for adding, editing or removing users on GET. Also parse input on POST. This page can only be accessed by an admin. """ if not current_user.admin: return abort(403) if request.method == 'POST': action = request.form.get('action', '') if action == 'new_user': username = request.form.get('username', '') password = request.form.get('password', '') contact_person = request.form.get('contact_person', '') contact_email = request.form.get('contact_email', '') success = database.add_user(username, password, contact_person, contact_email) if not success: database.revert_changes() flash( 'Could not add user. The username is probably already taken', 'error') else: database.save_changes() flash('Successfully added user {}'.format(username), 'info') elif action == 'remove_user': username = request.form.get('username', '') if username == current_user.username: flash('You cannot remove yourself!', 'error') else: success = database.remove_user(username) if success: database.save_changes() flash('User {} successfully removed'.format(username), 'info') else: database.revert_changes() elif action == 'edit_user': username = request.form.get('username', '') return render_template('user_managment.html', users=database.get_all_user_data())
def oauth_callback(): if flask_login.current_user.is_authenticated: return redirect(url_for('index')) oauth = DataportenSignin() userinfo = oauth.callback() if userinfo is None: flash('Authentication failed', 'error') return redirect(url_for('index')) feide_id = userinfo['userid_sec'][0].replace('feide:', '') user = database.session.query(User).filter(User.oauth_id == feide_id).first() if user is None: rand_pass = ''.join(random.choice('abcdefghijklmnopqrstuvwxyz0123456789') for i in range(64)) database.add_user(feide_id, rand_pass, userinfo['name'], userinfo['email'], False, feide_id) database.save_changes() user = database.session.query(User).filter(User.oauth_id == feide_id).first() flask_login.login_user(user, True) return redirect(url_for('index'))
def get_ansible_status(): """Return the status on the current ansible update The only argument is mac, which should be the probe's MAC address Returned statuses will be either: invalid-mac unknown-mac updating failed not-updated updated-{time of last update} """ mac = request.args.get('mac', '') if mac == '': return 'invalid-mac' mac = util.convert_mac(mac, 'storage') probe = database.get_probe(mac) if probe is None: return 'unknown-mac' status = ansible.get_playbook_status(current_user.username, probe) if status in ['updating', 'failed']: return status if status == 'completed': probe.has_been_updated = True if (probe.last_updated is None or (datetime.today() - probe.last_updated).total_seconds() >= 60): probe.last_updated = datetime.today() database.save_changes() if status == 'completed' or probe.has_been_updated: if probe.last_updated is None: probe.last_updated = datetime.today() database.save_changes() time = util.get_textual_timedelta(datetime.today() - probe.last_updated) return 'updated-{}'.format(time) return 'not-updated'
def databases(): """Render database page for GET. Also parse args and export Ansible config for POST.""" if request.method == 'POST': successful = form_parsers.update_databases(current_user.username) if successful: database.save_changes() ansible.export_group_config(current_user.username, { 'databases': database.get_database_info(current_user.username) }, 'database_configs') flash('Settings successfully saved', 'info') else: database.revert_changes() flash(messages.ERROR_MESSAGE['invalid_settings'], 'error') db_info = database.get_database_info(current_user.username) # Make sure the databases occur in the same order each time db_info = OrderedDict(sorted(db_info.items(), key=lambda x: x[0])) return render_template('databases.html', dbs=db_info)
def probes(): """Render page for viewing all the user's probes. On POST: add, update or remove a probe. More specifically, the following can be done via POST: - Add a new probe - Remove a probe - Reboot a probe - Renew a probe's association period (if not already associated) - Push configurations to probes (i.e. run Ansible) """ user = database.get_user(current_user.username) if request.method == 'POST': action = request.form.get('action', '') if action == 'new_probe': form_parsers.new_probe(current_user.username) elif action == 'reboot_probe': probe_id = request.form.get('probe_id', '') probe = database.get_probe(probe_id) if probe is not None and probe.user.username == current_user.username and probe.associated: success = util.reboot_probe(probe.port) if not success: flash('Unable to reboot probe (possibly no connection)') elif action == 'remove_probe': probe_id = request.form.get('probe_id', '') success = database.remove_probe(current_user.username, probe_id) if not success: flash('Invalid probe ID', 'error') else: ansible.remove_host_config(probe_id) database.save_changes() elif action == 'renew_period': probe_id = request.form.get('probe_id', '') probe = database.get_probe(probe_id) if probe is not None and probe.user.username == current_user.username: probe.new_association_period() database.save_changes() elif action == 'push_config': # Only run one instance of Ansible at a time (for each user) if not ansible.is_ansible_running(current_user.username): # Export configs in the sql database to ansible readable configs for probe in database.session.query(Probe).filter( Probe.user_id == user.id).all(): # Export script config data = util.strip_id(database.get_script_data(probe)) ansible.export_host_config(probe.custom_id, {'host_script_configs': data}, 'script_configs') # Export probe info config ansible.export_host_config( probe.custom_id, { 'probe_name': probe.name, 'probe_location': probe.location, 'probe_mac': probe.custom_id, 'probe_organization': user.get_organization() }, 'probe_info') if (probe.associated and util.is_probe_connected(probe.port) and database.valid_network_configs( probe, with_warning=True) and database.valid_database_configs( user, with_warning=True)): data = util.strip_id( database.get_network_config_data(probe)) ansible.export_host_config(probe.custom_id, {'networks': data}, 'network_configs') # Check which probes are selected selected_probes = [] for entry in request.form: match = re.fullmatch('selected\-([0-9a-f]{12})', entry) if match: selected_probes.append(match.group(1)) ansible.export_to_inventory(current_user.username, database, selected_probes) ansible.export_known_hosts(database) ansible.run_ansible_playbook(current_user.username) else: flash(messages.INFO_MESSAGE['ansible_already_running'], 'info') # Redirect to avoid re-POSTing return redirect(url_for('probes')) probes = database.get_all_probes_data(current_user.username) return render_template('probes.html', probes=probes, kibana_dashboard='probe-stats', organization=user.get_organization())