Changelog: https://roxy-wi.org/changelog#6_3_2
pull/355/head
Pavel Loginov 2022-12-22 22:19:43 +03:00
parent e0b914074a
commit f61276ce4c
13 changed files with 315 additions and 101 deletions

View File

@ -46,7 +46,13 @@ def index():
data = {
'help': 'show all available endpoints',
'login': 'get temporarily token. Must be JSON body: login, password and group for which getting token. METHOD: POST',
'servers': 'show info about all servers. METHOD: GET',
'user': 'show info about all users inside a group. METHOD: GET',
'user': 'create a new user inside a group. Must be JSON body: username, email, password, role. METHOD: POST',
'server': 'show info about all servers. METHOD: GET',
'server': 'create a new server inside a group. Must be JSON body: hostname, ip, port, virt: enter 0 if is not Virtual IP, group_id, master_id: enter 0 if is not slave, cred_id, description. METHOD: POST',
'server/ssh': 'show info about all SSH credentials inside a group. METHOD: GET',
'server/ssh': 'create a new SSH credentials inside a group. Must be JSON body: name, key_enabled, username, password. METHOD: POST',
'server/ssh/key': 'upload a new SSH key inside a group. Must be JSON body: name, key. Name it is credentials name, in key new lines must be replaced with "\n" METHOD: POST',
'servers/status': 'show status all HAProxyes. METHOD: GET',
'haproxy/<id,hostname,ip>': 'show info about the HAProxy by id or hostname or ip. METHOD: GET',
'haproxy/<id,hostname,ip>/status': 'show HAProxy status by id or hostname or ip. METHOD: GET',
@ -94,14 +100,14 @@ def get_token():
return dict(token=token)
@route('/servers', method=['GET'])
@route('/server', method=['GET'])
def get_servers():
if not check_login():
return dict(error=_error_auth)
data = {}
try:
token = request.headers.get('token')
login, group_id = sql.get_username_groupid_from_api_token(token)
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
servers = roxywi_common.get_dick_permit(username=login, group_id=group_id, token=token)
for s in servers:
@ -117,12 +123,54 @@ def get_servers():
'alert': s[8],
'metrics': s[9]
}
except Exception:
pass
except Exception as e:
data = {'error': e}
return dict(servers=data)
@route('/server', method=['POST'])
def show_users():
if not check_login():
return dict(error=_error_auth)
return api_funct.create_server()
@route('/user', method=['GET'])
def show_users():
if not check_login():
return dict(error=_error_auth)
return api_funct.user_list()
@route('/user', method=['POST'])
def create_user():
if not check_login():
return dict(error=_error_auth)
return api_funct.create_user()
@route('/server/ssh', method=['GET'])
def show_ssh():
if not check_login():
return dict(error=_error_auth)
return api_funct.ssh_list()
@route('/server/ssh', method=['POST'])
def create_ssh():
if not check_login():
return dict(error=_error_auth)
return api_funct.create_ssh()
@route('/server/ssh/key', method=['POST'])
def upload_ssh_key():
if not check_login():
return dict(error=_error_auth)
return api_funct.upload_ssh_key()
@route('/servers/status', method=['GET'])
def servers_status():
if not check_login():

View File

@ -5,12 +5,14 @@ from bottle import request
sys.path.append(os.path.join(sys.path[0], '/var/www/haproxy-wi/app/'))
import modules.db.sql as sql
import modules.server.ssh as ssh_mod
import modules.server.server as server_mod
import modules.config.section as section_mod
import modules.config.config as config_mod
import modules.config.runtime as runtime_mod
import modules.roxy_wi_tools as roxy_wi_tools
import modules.roxywi.logs as roxywi_logs
import modules.roxywi.user as roxywi_user
import modules.roxywi.common as roxywi_common
import modules.service.common as service_common
@ -55,7 +57,8 @@ def get_token():
if login in user.username and password == user.password:
import uuid
user_token = str(uuid.uuid4())
sql.write_api_token(user_token, group_id, user.role, user.username)
role_id = sql.get_role_id_by_name(user.role)
sql.write_api_token(user_token, group_id, role_id, user.username)
return user_token
else:
return False
@ -110,7 +113,7 @@ def return_dict_from_out(server_id, out):
def check_permit_to_server(server_id, service='haproxy'):
servers = sql.select_servers(id_hostname=server_id)
token = request.headers.get('token')
login, group_id = sql.get_username_groupid_from_api_token(token)
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
for s in servers:
server = roxywi_common.get_dick_permit(username=login, group_id=group_id, ip=s[2], token=token, service=service)
@ -215,7 +218,7 @@ def get_all_statuses():
try:
servers = sql.select_servers()
token = request.headers.get('token')
login, group_id = sql.get_username_groupid_from_api_token(token)
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
sock_port = sql.get_setting('haproxy_sock_port')
for s in servers:
@ -344,7 +347,7 @@ def edit_section(server_id):
token = request.headers.get('token')
servers = check_permit_to_server(server_id)
hap_configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir')
login, group_id = sql.get_username_groupid_from_api_token(token)
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
if save == '':
save = 'save'
@ -400,7 +403,7 @@ def upload_config(server_id, **kwargs):
body = request.body.getvalue().decode('utf-8')
save = request.headers.get('action')
token = request.headers.get('token')
login, group_id = sql.get_username_groupid_from_api_token(token)
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
nginx = ''
apache = ''
@ -471,7 +474,7 @@ def add_to_config(server_id):
save = request.headers.get('action')
hap_configs_dir = get_config_var.get_config_var('configs', 'haproxy_save_configs_dir')
token = request.headers.get('token')
login, group_id = sql.get_username_groupid_from_api_token(token)
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
time_zone = sql.get_setting('time_zone')
get_date = roxy_wi_tools.GetDate(time_zone)
@ -683,3 +686,112 @@ def generate_acl(**kwargs):
acl += then_value + ' if { ' + acl_if_word + if_value + ' } ' + newline
return acl
def user_list():
data = {}
token = request.headers.get('token')
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
users = sql.select_users(by_group_id=group_id)
for user in users:
data[user.user_id] = {
'login': user.username,
'email': user.email,
'role': user.role,
'ldap': user.ldap_user,
'enabled': user.activeuser,
'last_login_ip': user.last_login_ip,
}
data = {'users': data}
return dict(data)
def create_user():
body = request.body.getvalue().decode('utf-8')
json_loads = json.loads(body)
name = json_loads['name']
email = json_loads['email']
password = json_loads['password']
role = json_loads['role']
token = request.headers.get('token')
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
if roxywi_user.create_user(name, email, password, role, 1, group_id, role_id=role_id, token=token):
data = {'status': 'done'}
return dict(data)
else:
data = {'status': 'something went wrong'}
return dict(data)
def ssh_list():
data = {}
token = request.headers.get('token')
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
sshs = sql.select_ssh(group=group_id)
for ssh in sshs:
data[ssh.id] = {
'name': ssh.name,
'username': ssh.username,
'key_enabled': ssh.enable,
}
data = {'creds': data}
return dict(data)
def create_ssh():
body = request.body.getvalue().decode('utf-8')
json_loads = json.loads(body)
name = json_loads['name']
enable = json_loads['key_enabled']
username = json_loads['username']
password = json_loads['password']
token = request.headers.get('token')
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
if ssh_mod.create_ssh_cread_api(name, enable, group_id, username, password):
data = {'status': 'done'}
return dict(data)
else:
data = {'status': 'error: check all fields'}
return dict(data)
def upload_ssh_key():
body = request.body.getvalue().decode('utf-8')
json_loads = json.loads(body)
name = json_loads['name']
key = json_loads['key']
token = request.headers.get('token')
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
groups = sql.select_groups(id=group_id)
for group in groups:
user_group = group.name
if ssh_mod.upload_ssh_key(name, user_group, key):
data = {'status': 'done'}
return dict(data)
else:
data = {'status': 'error: check all fields'}
return dict(data)
def create_server():
body = request.body.getvalue().decode('utf-8')
json_loads = json.loads(body)
hostname = json_loads['hostname']
ip = json_loads['ip']
port = json_loads['port']
virt = json_loads['virt']
master_id = json_loads['master_id']
cred_id = json_loads['cred_id']
desc = json_loads['description']
token = request.headers.get('token')
login, group_id, role_id = sql.get_username_groupid_from_api_token(token)
try:
if server_mod.create_server(hostname, ip, group_id, virt, 1, master_id, cred_id, port, desc, 0, 0, 0, 0, '1', role_id=role_id, token=token):
data = {'status': 'done'}
roxywi_common.logging(ip, f'A new server {hostname} has been created', roxywi=1, keep_history=1, service='server')
return dict(data)
except Exception as e:
data = {'status': f'error: {e}'}
return dict(data)

View File

@ -966,7 +966,7 @@ def update_db_v_6_2_1():
def update_ver():
try:
Version.update(version='6.3.1.0').execute()
Version.update(version='6.3.2.0').execute()
except Exception:
print('Cannot update version')

View File

@ -391,6 +391,8 @@ def select_users(**kwargs):
).join(UserGroups, on=(User.user_id == UserGroups.user_id)).where(
UserGroups.user_group_id == kwargs.get("group")
))
elif kwargs.get('by_group_id'):
query = User.select().where(User.groups == kwargs.get("by_group_id"))
else:
cur_date = get_date.return_date('regular', timedelta_minutes_minus=15)
query = User.select(User, Case(0, [(
@ -400,7 +402,7 @@ def select_users(**kwargs):
except Exception as e:
out_error(e)
else:
return query_res
return query
def select_user_groups(user_id, **kwargs):
@ -671,7 +673,7 @@ def get_username_groupid_from_api_token(token):
except Exception as e:
return str(e)
else:
return user_name.user_name, user_name.user_group_id
return user_name.user_name, user_name.user_group_id, user_name.user_role
def get_token(uuid):

View File

@ -35,14 +35,19 @@ def check_login(user_uuid, token, **kwargs):
return False
def is_admin(level=1):
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_id = cookie.get('uuid')
try:
role = sql.get_user_role_by_uuid(user_id.value)
except Exception:
role = 4
pass
def is_admin(level=1, **kwargs):
if kwargs.get('role_id'):
role = kwargs.get('role_id')
else:
cookie = http.cookies.SimpleCookie(os.environ.get("HTTP_COOKIE"))
user_id = cookie.get('uuid')
user_id = user_id.value
try:
role = sql.get_user_role_by_uuid(user_id)
except Exception:
role = 4
pass
try:
return True if role <= level else False

View File

@ -11,29 +11,12 @@ import modules.alerting.alerting as alerting
form = common.form
def create_user():
email = form.getvalue('newemail')
password = form.getvalue('newpassword')
role = form.getvalue('newrole')
new_user = form.getvalue('newusername')
page = form.getvalue('page')
activeuser = form.getvalue('activeuser')
group = form.getvalue('newgroupuser')
role_id = sql.get_role_id_by_name(role)
def create_user(new_user: str, email: str, password: str, role: str, activeuser: int, group: int, **kwargs) -> bool:
if roxywi_common.check_user_group(token=kwargs.get('token')):
if roxywi_common.check_user_group():
if roxywi_auth.is_admin(level=role_id):
if roxywi_auth.is_admin(level=2, role_id=kwargs.get('role_id')):
try:
sql.add_user(new_user, email, password, role, activeuser, group)
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
template = env.get_template('ajax/new_user.html')
template = template.render(users=sql.select_users(user=new_user),
groups=sql.select_groups(),
page=page,
roles=sql.select_roles(),
adding=1)
print(template)
roxywi_common.logging(f'a new user {new_user}', ' has been created ', roxywi=1, login=1)
try:
message = f"A user has been created for you on Roxy-WI portal!\n\n" \
@ -47,10 +30,13 @@ def create_user():
except Exception as e:
print(f'error: Cannot create a new user: {e}')
roxywi_common.logging('error: Cannot create a new user', e, roxywi=1, login=1)
return False
else:
print('error: dalsdm')
roxywi_common.logging(new_user, ' tried to privilege escalation', roxywi=1, login=1)
return False
return True
def delete_user():
userdel = form.getvalue('userdel')

View File

@ -3,6 +3,7 @@ import json
import modules.db.sql as sql
import modules.server.ssh as mod_ssh
import modules.common.common as common
import modules.roxywi.auth as roxywi_auth
import modules.roxywi.common as roxywi_common
form = common.form
@ -408,3 +409,56 @@ def show_firewalld_rules() -> None:
template = env.get_template('ajax/firewall_rules.html')
template = template.render(input=input_chain2, IN_public_allow=in_public_allow, output=output_chain)
print(template)
def create_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall, scan_server, **kwargs) -> bool:
if not roxywi_auth.is_admin(level=2, role_id=kwargs.get('role_id')):
raise Exception('not enough permission')
if sql.add_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall):
try:
if scan_server == '1':
nginx_config_path = sql.get_setting('nginx_config_path')
haproxy_config_path = sql.get_setting('haproxy_config_path')
haproxy_dir = sql.get_setting('haproxy_dir')
apache_config_path = sql.get_setting('apache_config_path')
keepalived_config_path = sql.get_setting('keepalived_config_path')
if is_file_exists(ip, nginx_config_path):
sql.update_nginx(ip)
if is_file_exists(ip, haproxy_config_path):
sql.update_haproxy(ip)
if is_file_exists(ip, keepalived_config_path):
sql.update_keepalived(ip)
if is_file_exists(ip, apache_config_path):
sql.update_apache(ip)
if is_file_exists(ip, haproxy_dir + '/waf/bin/modsecurity'):
sql.insert_waf_metrics_enable(ip, "0")
sql.insert_waf_rules(ip)
if is_service_active(ip, 'firewalld'):
sql.update_firewall(ip)
except Exception as e:
roxywi_common.logging(f'Cannot scan a new server {hostname}', str(e), roxywi=1)
raise Exception(f'error: Cannot scan a new server {hostname} {e}')
try:
sql.insert_new_checker_setting_for_server(ip)
except Exception as e:
roxywi_common.logging(f'Cannot insert Checker settings for {hostname}', str(e), roxywi=1)
raise Exception(f'error: Cannot insert Checker settings for {hostname} {e}')
try:
get_system_info(ip)
except Exception as e:
roxywi_common.logging(f'Cannot get information from {hostname}', str(e), roxywi=1, login=1)
raise Exception(f'error: Cannot get information from {hostname} {e}')
return True
else:
return False

View File

@ -69,18 +69,32 @@ def create_ssh_cred() -> None:
template = env.get_template('/new_ssh.html')
output_from_parsed_template = template.render(groups=sql.select_groups(), sshs=sql.select_ssh(name=name), page=page)
print(output_from_parsed_template)
roxywi_common.logging('Roxy-WI server', f'A new SSH credentials {name} has created', roxywi=1, login=1)
roxywi_common.logging('Roxy-WI server', f'New SSH credentials {name} has been created', roxywi=1, login=1)
def upload_ssh_key() -> None:
user_group = roxywi_common.get_user_group()
name = common.checkAjaxInput(form.getvalue('name'))
def create_ssh_cread_api(name: str, enable: str, group: str, username: str, password: str) -> bool:
groups = sql.select_groups(id=group)
for group in groups:
user_group = group.name
name = common.checkAjaxInput(name)
name = f'{name}_{user_group}'
enable = common.checkAjaxInput(enable)
username = common.checkAjaxInput(username)
password = common.checkAjaxInput(password)
if username is None or name is None:
return False
else:
if sql.insert_new_ssh(name, enable, group, username, password):
return True
def upload_ssh_key(name: str, user_group: str, key: str) -> bool:
try:
key = paramiko.pkey.load_private_key(form.getvalue('ssh_cert'))
key = paramiko.pkey.load_private_key(key)
except Exception as e:
print(f'error: Cannot save SSH key file: {e}')
return
return False
lib_path = get_config.get_config_var('main', 'lib_path')
full_dir = f'{lib_path}/keys/'
@ -104,7 +118,7 @@ def upload_ssh_key() -> None:
key.write_private_key_file(ssh_keys)
except Exception as e:
print(f'error: Cannot save SSH key file: {e}')
return
return False
else:
print(f'success: SSH key has been saved into: {ssh_keys}')
@ -112,8 +126,10 @@ def upload_ssh_key() -> None:
os.chmod(ssh_keys, 0o600)
except IOError as e:
roxywi_common.logging('Roxy-WI server', e.args[0], roxywi=1)
return False
roxywi_common.logging("Roxy-WI server", f"A new SSH cert has been uploaded {ssh_keys}", roxywi=1, login=1)
return True
def update_ssh_key() -> None:

View File

@ -35,20 +35,20 @@ class SshConnection:
banner_timeout=200
)
except paramiko.AuthenticationException:
raise paramiko.SSHException('error: Authentication failed, please verify your credentials')
raise paramiko.SSHException(f'{self.server_ip} Authentication failed, please verify your credentials')
except paramiko.SSHException as sshException:
raise paramiko.SSHException(f'error: Unable to establish SSH connection: {sshException}')
raise paramiko.SSHException(f'{self.server_ip} Unable to establish SSH connection: {sshException}')
except paramiko.PasswordRequiredException as e:
raise paramiko.SSHException(f'error: {e}')
raise paramiko.SSHException(f'{self.server_ip} {e}')
except paramiko.BadHostKeyException as badHostKeyException:
raise paramiko.SSHException(f'error: Unable to verify server\'s host key: {badHostKeyException}')
raise paramiko.SSHException(f'{self.server_ip} Unable to verify server\'s host key: {badHostKeyException}')
except Exception as e:
if e == "No such file or directory":
raise paramiko.SSHException(f'error: {e}. Check SSH key')
raise paramiko.SSHException(f'{self.server_ip} {e}. Check SSH key')
elif e == "Invalid argument":
raise paramiko.SSHException('error: Check the IP of the server')
raise paramiko.SSHException(f'{self.server_ip} Check the IP of the server')
else:
raise paramiko.SSHException(f'error: {e}')
raise paramiko.SSHException(f'{self.server_ip} {e}')
return self
def __exit__(self, exc_type, exc_val, exc_tb):

View File

@ -175,7 +175,7 @@ if form.getvalue("change_pos") is not None:
sql.update_server_pos(pos, server_id)
if form.getvalue('show_ip') is not None and serv is not None:
commands = ["sudo ip a |grep inet |egrep -v '::1' |awk '{ print $2 }' |awk -F'/' '{ print $1 }'"]
commands = ['sudo hostname -i | tr " " "\n"|grep -v "%"']
server_mod.ssh_command(serv, commands, ip="1")
if form.getvalue('showif'):
@ -954,7 +954,24 @@ error_mess = 'error: All fields must be completed'
if form.getvalue('newuser') is not None:
import modules.roxywi.user as roxywi_user
roxywi_user.create_user()
email = common.checkAjaxInput(form.getvalue('newemail'))
password = common.checkAjaxInput(form.getvalue('newpassword'))
role = common.checkAjaxInput(form.getvalue('newrole'))
new_user = common.checkAjaxInput(form.getvalue('newusername'))
page = common.checkAjaxInput(form.getvalue('page'))
activeuser = common.checkAjaxInput(form.getvalue('activeuser'))
group = common.checkAjaxInput(form.getvalue('newgroupuser'))
if roxywi_user.create_user(new_user, email, password, role, activeuser, group):
env = Environment(loader=FileSystemLoader('templates/'), autoescape=True)
template = env.get_template('ajax/new_user.html')
template = template.render(users=sql.select_users(user=new_user),
groups=sql.select_groups(),
page=page,
roles=sql.select_roles(),
adding=1)
print(template)
if form.getvalue('userdel') is not None:
import modules.roxywi.user as roxywi_user
@ -994,47 +1011,7 @@ if form.getvalue('newserver') is not None:
print('error: IP or DNS name is not valid')
sys.exit()
try:
if sql.add_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall):
try:
if scan_server == '1':
nginx_config_path = sql.get_setting('nginx_config_path')
haproxy_config_path = sql.get_setting('haproxy_config_path')
haproxy_dir = sql.get_setting('haproxy_dir')
apache_config_path = sql.get_setting('apache_config_path')
keepalived_config_path = sql.get_setting('keepalived_config_path')
if server_mod.is_file_exists(ip, nginx_config_path):
sql.update_nginx(ip)
if server_mod.is_file_exists(ip, haproxy_config_path):
sql.update_haproxy(ip)
if server_mod.is_file_exists(ip, keepalived_config_path):
sql.update_keepalived(ip)
if server_mod.is_file_exists(ip, apache_config_path):
sql.update_apache(ip)
if server_mod.is_file_exists(ip, haproxy_dir + '/waf/bin/modsecurity'):
sql.insert_waf_metrics_enable(ip, "0")
sql.insert_waf_rules(ip)
if server_mod.is_service_active(ip, 'firewalld'):
sql.update_firewall(ip)
except Exception as e:
roxywi_common.logging('Cannot scan a new server ' + hostname, str(e), roxywi=1)
try:
sql.insert_new_checker_setting_for_server(ip)
except Exception as e:
roxywi_common.logging('Cannot insert Checker settings for ' + hostname, str(e), roxywi=1)
try:
server_mod.get_system_info(ip)
except Exception as e:
roxywi_common.logging('Cannot get information from ' + hostname, str(e), roxywi=1, login=1)
if server_mod.create_server(hostname, ip, group, typeip, enable, master, cred, port, desc, haproxy, nginx, apache, firewall, scan_server):
try:
user_subscription = roxywi_common.return_user_status()
except Exception as e:
@ -1162,7 +1139,11 @@ if form.getvalue('updatessh'):
ssh_mod.update_ssh_key()
if form.getvalue('ssh_cert'):
ssh_mod.upload_ssh_key()
user_group = roxywi_common.get_user_group()
name = common.checkAjaxInput(form.getvalue('name'))
key = form.getvalue('ssh_cert')
ssh_mod.upload_ssh_key(user_group, name, key)
if form.getvalue('newtelegram'):
import modules.alerting.alerting as alerting

View File

@ -1,5 +1,5 @@
{% if user %}
<span id="show-user-settings-button" class="menu-bar login" title="User settings for user {{ user }}" style="margin-top: 7px;"></span>
<span id="show-user-settings-button" class="user-circle login" title="User settings" style="margin-top: 5px;">{{user}}</span>
{% else %}
<a href=/app/login.py title="Login" class="login"> Login</a>
{% endif %}

View File

@ -421,3 +421,12 @@
font-family: "Font Awesome 5 Solid";
content: "\f0f3";
}
.user-circle::before {
display: none;
font-family: "Font Awesome 5 Solid";
content: "\f2bd";
}
.user-circle > .fa-user-circle {
cursor: pointer;
padding-right: 5px;
}

View File

@ -185,6 +185,7 @@ pre {
margin-right: 30px;
color: #fff !important;
font-size: 15px;
cursor: pointer;
}
.auto-refresh {
margin-left: auto;