chg: [user roles] rename coordinator as org_admin

otp
terrtia 2024-09-16 14:36:10 +02:00
parent 7b66ff6a8c
commit 7efc26bab9
No known key found for this signature in database
GPG Key ID: 1E1B1F50D84613D0
8 changed files with 197 additions and 15 deletions

View File

@ -151,6 +151,13 @@ class Organisation:
meta['creator'] = self._get_field('creator')
if 'date_created' in options:
meta['date_created'] = self._get_field('date_created')
if 'users' in options:
meta['users'] = self.get_users()
if 'nb_users' in options:
if 'users' in meta:
meta['nb_users'] = len(meta['users'])
else:
meta['nb_users'] = self.get_nb_users()
return meta
def is_user(self, user_id):
@ -228,7 +235,7 @@ def check_access_acl(obj, user_org, is_admin=False):
# view
# edit
# delete -> coordinator or admin
# delete -> org_admin or admin
def check_obj_access_acl(obj, user_org, user_id, user_role, action):
if user_role == 'admin':
return True
@ -243,7 +250,7 @@ def check_obj_access_acl(obj, user_org, user_id, user_role, action):
return True
# edit + delete
else: # TODO allow user to edit same org global
if user_role == 'coordinator':
if user_role == 'org_admin':
creator_org = obj.get_creator_org()
if user_org == creator_org:
return True
@ -258,7 +265,7 @@ def check_obj_access_acl(obj, user_org, user_id, user_role, action):
elif action == 'edit':
return obj.get_org() == user_org
elif action == 'delete':
if user_role == 'coordinator':
if user_role == 'org_admin':
if user_org == obj.get_org():
return True
else:
@ -285,14 +292,14 @@ def check_acl_edit_level(obj, user_org, user_id, user_role, new_level):
elif new_level == 1:
if level == 0 and obj.get_id() == user_id:
return True
elif level == 2 and user_role == 'coordinator':
elif level == 2 and user_role == 'org_admin':
if obj.get_creator_org() == user_org:
return True
# Organisation
elif new_level == 2:
if level == 0 and obj.get_id() == user_id:
return True
elif level == 1 and user_role == 'coordinator':
elif level == 1 and user_role == 'org_admin':
if obj.get_creator_org() == user_org:
return True
return False
@ -308,6 +315,15 @@ def api_get_orgs_meta():
meta['orgs'].append(org.get_meta(options=options))
return meta
def api_get_org_meta(org_uuid):
if not is_valid_uuid_v4(org_uuid):
return {'status': 'error', 'reason': 'Invalid UUID'}, 400
if not exists_org(org_uuid):
return {'status': 'error', 'reason': 'Unknown org'}, 404
org = Organisation(org_uuid)
meta = org.get_meta(options={'date_created', 'description', 'name', 'users', 'nb_users'})
return meta, 200
def api_create_org(creator, org_uuid, name, ip_address, user_agent, description=None):
if not is_valid_uuid_v4(org_uuid):
return {'status': 'error', 'reason': 'Invalid UUID'}, 400

View File

@ -270,6 +270,13 @@ def disable_user_2fa(user_id):
def get_users():
return r_serv_db.hkeys('ail:users:all')
def get_users_meta(users):
meta = []
for user_id in users:
user = AILUser(user_id)
meta.append(user.get_meta({'role'}))
return meta
def get_user_role(user_id):
return r_serv_db.hget(f'ail:user:metadata:{user_id}', 'role')
@ -733,15 +740,15 @@ def is_in_role(user_id, role):
return r_serv_db.sismember(f'ail:users:role:{role}', user_id)
def _get_users_roles_list():
return ['read_only', 'user_no_api', 'user', 'coordinator', 'admin']
return ['read_only', 'user_no_api', 'user', 'org_admin', 'admin']
def _get_users_roles_dict():
return {
'read_only': ['read_only'],
'user_no_api': ['read_only', 'user_no_api'],
'user': ['read_only', 'user_no_api', 'user'],
'coordinator': ['read_only', 'user_no_api', 'user', 'coordinator'],
'admin': ['read_only', 'user_no_api', 'user', 'coordinator', 'admin'],
'org_admin': ['read_only', 'user_no_api', 'user', 'org_admin'],
'admin': ['read_only', 'user_no_api', 'user', 'org_admin', 'admin'],
}
def set_user_role(user_id, role):

View File

@ -16,7 +16,7 @@ sys.path.append('modules')
import Flask_config
# Import Role_Manager
from Role_Manager import login_admin, login_coordinator, login_user, login_user_no_api, login_read_only
from Role_Manager import login_admin, login_org_admin, login_user, login_user_no_api, login_read_only
sys.path.append(os.environ['AIL_BIN'])
##################################
@ -669,7 +669,7 @@ def retro_hunt_resume_task():
@hunters.route('/retro_hunt/task/delete', methods=['GET'])
@login_required
@login_coordinator
@login_org_admin
def retro_hunt_delete_task():
user_org = current_user.get_org()
user_id = current_user.get_id()

View File

@ -15,7 +15,7 @@ from flask_login import login_required, current_user
sys.path.append('modules')
# Import Role_Manager
from Role_Manager import login_admin, login_coordinator, login_read_only, login_user_no_api
from Role_Manager import login_admin, login_org_admin, login_read_only, login_user_no_api
sys.path.append(os.environ['AIL_BIN'])
##################################
@ -216,7 +216,7 @@ def delete_object_id_to_export():
@import_export.route("/investigation/misp/export", methods=['GET'])
@login_required
@login_coordinator
@login_org_admin
def export_investigation():
investigation_uuid = request.args.get("uuid")
investigation = Investigation(investigation_uuid)

View File

@ -318,6 +318,18 @@ def organisations_list():
meta = ail_orgs.api_get_orgs_meta()
return render_template("orgs_list.html", meta=meta, acl_admin=True)
@settings_b.route("/settings/organisation", methods=['GET'])
@login_required
@login_admin
def organisation():
org_uuid = request.args.get('uuid')
meta, r = ail_orgs.api_get_org_meta(org_uuid)
if r != 200:
return create_json_response(meta, r)
if 'users' in meta:
meta['users'] = ail_users.get_users_meta(meta['users'])
return render_template("view_organisation.html", meta=meta, acl_admin=True)
@settings_b.route("/settings/create_organisation", methods=['GET'])
@login_required
@login_admin

View File

@ -41,12 +41,12 @@ def login_admin(func):
return func(*args, **kwargs)
return decorated_view
def login_coordinator(func):
def login_org_admin(func):
@wraps(func)
def decorated_view(*args, **kwargs):
if not current_user.is_authenticated:
return login_manager.unauthorized()
elif not current_user.is_in_role('coordinator'):
elif not current_user.is_in_role('org_admin'):
return login_manager.unauthorized()
return func(*args, **kwargs)
return decorated_view

View File

@ -42,7 +42,7 @@
{% for org in meta['orgs'] %}
<tr>
<td>{{org['name']}}</td>
<td>{{org['uuid']}}</td>
<td><a href="{{ url_for('settings_b.organisation', uuid=org['uuid']) }}">{{ org['uuid'] }}</a></td>
<td>{{org['description']}}</td>
<td>
{% if org['date_created'] %}

View File

@ -0,0 +1,147 @@
<!DOCTYPE html>
<html>
<head>
<title>AIL-Framework</title>
<link rel="icon" href="{{ url_for('static', filename='image/ail-icon.png')}}">
<!-- Core CSS -->
<link href="{{ url_for('static', filename='css/bootstrap4.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/font-awesome.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/dataTables.bootstrap.min.css') }}" rel="stylesheet">
<link href="{{ url_for('static', filename='css/ail-project.css') }}" rel="stylesheet">
<!-- JS -->
<script src="{{ url_for('static', filename='js/jquery.js')}}"></script>
<script src="{{ url_for('static', filename='js/bootstrap4.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/jquery.dataTables.min.js')}}"></script>
<script src="{{ url_for('static', filename='js/dataTables.bootstrap.min.js')}}"></script>
</head>
<body>
{% include 'nav_bar.html' %}
<div class="container-fluid">
<div class="row">
{% include 'sidebars/sidebar_objects.html' %}
<div class="col-12 col-lg-10" id="core_content">
<div class="card my-1">
<div class="card-header bg-dark text-white">
<h4 class="card-title">{{meta['name']}}</h4>
</div>
<div class="card-body">
<div class="container-fluid">
<div class="row">
<div class="col-12 col-lg-6">
<table class="table table-hover">
<tr>
<th style="width:30%">UUID</th>
<td>{{meta['uuid']}}</td>
</tr>
<tr>
<th>Creator</th>
<td>{{meta['creator']}}</td>
</tr>
<tr>
<th>Date</th>
<td>{{meta['date_created']}}</td>
</tr>
<tr>
<th>NB Users</th>
<td>
{{ meta['nb_users'] }}
</td>
</tr>
<tr>
<th>Tags</th>
<td>
{% for tag in meta['tags'] %}
<span class="badge badge-{{ bootstrap_label[loop.index0 % 5] }} pull-left">{{ tag }}</span>
{% endfor %}
</td>
</tr>
<tr>
<th>Description</th>
<td>{{meta['descriptions']}}</td>
</tr>
</table>
</div>
<div class="col-12 col-lg-6">
<div class="my-4">
{# <a href="{{ url_for('investigations_b.delete_investigation') }}?uuid={{metadata['uuid']}}">#}
{# <button type="button" class="btn btn-danger">#}
{# <i class="fas fa-trash-alt"></i> <b>Delete</b>#}
{# </button>#}
{# </a>#}
{# <a href="{{ url_for('investigations_b.edit_investigation') }}?uuid={{metadata['uuid']}}">#}
{# <button type="button" class="btn btn-info">#}
{# <i class="fas fa-pencil-alt"></i> <b>Edit</b>#}
{# </button>#}
{# </a>#}
</div>
</div>
</div>
</div>
</div>
</div>
<h3>Users</h3>
<table id="table_org_users" class="table table-striped border-primary">
<thead class="bg-dark text-white">
<tr>
<th>User</th>
<th>Role</th>
<th></th>
</tr>
</thead>
<tbody style="font-size: 15px;">
{% for user in meta['users'] %}
<tr class="border-color: blue;">
<td>
{{ user['id'] }}
</td>
<td>
{{ user['role'] }}
</td>
<td class="text-right">
{# <a href="{{ url_for('investigations_b.unregister_investigation') }}?uuid={{ metadata['uuid']}}&type={{ object['type'] }}&subtype={{ object['subtype']}}&id={{ object['id']}}">#}
{# <button type="button" class="btn btn-danger"><i class="fas fa-trash-alt"></i></button>#}
{# </a>#}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</body>
<script>
$(document).ready(function(){
$('#nav_sync').removeClass("text-muted");
$('#table_org_users').DataTable({
"aLengthMenu": [[5, 10, 15, -1], [5, 10, 15, "All"]],
"iDisplayLength": 10,
"order": [[ 0, "asc" ]]
});
});
</script>