Enforcing useracl permissions

This commit is contained in:
Eduardo Silva 2024-04-04 11:18:46 -03:00
parent 07cd83fb03
commit 6a53c8bc97
8 changed files with 80 additions and 26 deletions

View file

@ -11,6 +11,8 @@ from backup_data.models import RouterBackup
import difflib import difflib
import unicodedata import unicodedata
from routerlib.functions import gen_backup_name, get_router_backup_file_extension from routerlib.functions import gen_backup_name, get_router_backup_file_extension
from django.conf import settings
from user_manager.models import UserAcl
@login_required() @login_required()
@ -25,6 +27,8 @@ def view_backup_profile_list(request):
@login_required() @login_required()
def view_manage_backup_profile(request): def view_manage_backup_profile(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=40).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
if request.GET.get('uuid'): if request.GET.get('uuid'):
backup_profile = get_object_or_404(BackupProfile, uuid=request.GET.get('uuid')) backup_profile = get_object_or_404(BackupProfile, uuid=request.GET.get('uuid'))
if request.GET.get('action') == 'delete': if request.GET.get('action') == 'delete':
@ -85,6 +89,8 @@ def view_backup_list(request):
@login_required() @login_required()
def view_backup_details(request): def view_backup_details(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid')) backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid'))
hash_list = [backup.backup_text_hash] hash_list = [backup.backup_text_hash]
backup_list = [] backup_list = []
@ -108,7 +114,10 @@ def normalize_text(text):
return text return text
@login_required()
def view_compare_backups(request): def view_compare_backups(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
backup1 = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid')) backup1 = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid'))
backup2 = get_object_or_404(RouterBackup, uuid=request.GET.get('compare_uuid')) backup2 = get_object_or_404(RouterBackup, uuid=request.GET.get('compare_uuid'))
if request.GET.get('display') == 'all': if request.GET.get('display') == 'all':
@ -140,15 +149,19 @@ def view_debug_run_backups(request):
data = { data = {
'backup_count': 0, 'backup_count': 0,
} }
for backup in RouterBackup.objects.filter(success=False, error=False): if settings.DEBUG:
data['backup_count'] += 1 for backup in RouterBackup.objects.filter(success=False, error=False):
perform_backup(backup) data['backup_count'] += 1
perform_backup(backup)
else:
data['error'] = 'Debug mode is not enabled'
return JsonResponse(data) return JsonResponse(data)
@login_required() @login_required()
def view_backup_download(request): def view_backup_download(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid')) backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid'))
if request.GET.get('type') == 'text': if request.GET.get('type') == 'text':
response = HttpResponse(backup.backup_text, content_type='text/plain') response = HttpResponse(backup.backup_text, content_type='text/plain')
@ -169,6 +182,8 @@ def view_backup_download(request):
@login_required() @login_required()
def view_backup_delete(request): def view_backup_delete(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid')) backup = get_object_or_404(RouterBackup, uuid=request.GET.get('uuid'))
redirect_url = f'/router/details/?uuid={backup.router.uuid}' redirect_url = f'/router/details/?uuid={backup.router.uuid}'
if request.GET.get('confirmation') == f'delete{backup.id}': if request.GET.get('confirmation') == f'delete{backup.id}':

View file

@ -83,7 +83,6 @@ def view_generate_backup_schedule(request):
'monthly_backup_schedule_removed': 0 'monthly_backup_schedule_removed': 0
} }
for router in Router.objects.filter(backupschedule__isnull=True): for router in Router.objects.filter(backupschedule__isnull=True):
new_backup_schedule, _ = BackupSchedule.objects.get_or_create(router=router) new_backup_schedule, _ = BackupSchedule.objects.get_or_create(router=router)
data['backup_schedule_created'] += 1 data['backup_schedule_created'] += 1

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.3 on 2024-04-04 14:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('integration_manager', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='externalintegration',
name='wireguard_webadmin_default_user_level',
field=models.PositiveIntegerField(choices=[(0, 'Do not create users'), (10, 'Debugging Analyst'), (20, 'View Only User'), (30, 'Peer Manager'), (40, 'Manager'), (50, 'Administrator')], default=0),
),
]

View file

@ -4,6 +4,7 @@ from .models import ExternalIntegration
from .forms import WireGuardWebAdminForm from .forms import WireGuardWebAdminForm
from django.contrib import messages from django.contrib import messages
import requests import requests
from user_manager.models import UserAcl
@login_required() @login_required()
@ -48,6 +49,8 @@ def view_launch_wireguard_webadmin(request):
@login_required() @login_required()
def view_manage_wireguard_integration(request): def view_manage_wireguard_integration(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=50).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
context = { context = {
'page_title': 'Manage WireGuard WebAdmin Integration', 'page_title': 'Manage WireGuard WebAdmin Integration',
'delete_confirmation_message': 'Are you sure you want to delete this integration? This action cannot be undone. Type delete in the box below to confirm.' 'delete_confirmation_message': 'Are you sure you want to delete this integration? This action cannot be undone. Type delete in the box below to confirm.'

View file

@ -6,6 +6,7 @@ from django.contrib.auth.decorators import login_required
from backup_data.models import RouterBackup from backup_data.models import RouterBackup
from .models import Router, RouterGroup, RouterStatus, SSHKey, BackupSchedule from .models import Router, RouterGroup, RouterStatus, SSHKey, BackupSchedule
from .forms import RouterForm, RouterGroupForm, SSHKeyForm from .forms import RouterForm, RouterGroupForm, SSHKeyForm
from user_manager.models import UserAcl
@login_required @login_required
@ -45,6 +46,8 @@ def view_router_details(request):
@login_required() @login_required()
def view_manage_router(request): def view_manage_router(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=30).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
if request.GET.get('uuid'): if request.GET.get('uuid'):
router = get_object_or_404(Router, uuid=request.GET.get('uuid')) router = get_object_or_404(Router, uuid=request.GET.get('uuid'))
if request.GET.get('action') == 'delete': if request.GET.get('action') == 'delete':
@ -85,6 +88,8 @@ def view_router_group_list(request):
@login_required() @login_required()
def view_manage_router_group(request): def view_manage_router_group(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=40).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
if request.GET.get('uuid'): if request.GET.get('uuid'):
router_group = get_object_or_404(RouterGroup, uuid=request.GET.get('uuid')) router_group = get_object_or_404(RouterGroup, uuid=request.GET.get('uuid'))
if request.GET.get('action') == 'delete': if request.GET.get('action') == 'delete':
@ -123,6 +128,8 @@ def view_ssh_key_list(request):
@login_required() @login_required()
def view_manage_sshkey(request): def view_manage_sshkey(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=40).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
if request.GET.get('uuid'): if request.GET.get('uuid'):
sshkey = get_object_or_404(SSHKey, uuid=request.GET.get('uuid')) sshkey = get_object_or_404(SSHKey, uuid=request.GET.get('uuid'))
if request.GET.get('action') == 'delete': if request.GET.get('action') == 'delete':
@ -152,6 +159,8 @@ def view_manage_sshkey(request):
@login_required() @login_required()
def view_create_instant_backup_task(request): def view_create_instant_backup_task(request):
if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists():
return render(request, 'access_denied.html', {'page_title': 'Access Denied'})
router = get_object_or_404(Router, uuid=request.GET.get('uuid')) router = get_object_or_404(Router, uuid=request.GET.get('uuid'))
router_details_url = f'/router/details/?uuid={router.uuid}' router_details_url = f'/router/details/?uuid={router.uuid}'
if RouterBackup.objects.filter(router=router, success=False, error=False).exists(): if RouterBackup.objects.filter(router=router, success=False, error=False).exists():

View file

@ -49,25 +49,17 @@
<div class="col-md-8"> <div class="col-md-8">
<h5>Viewer</h5>
<h5>Debugging Analyst</h5> <p>This level has view-only access. Users can see queue information and the backup list, but they cannot access backup data or any sensitive information.</p>
<p>Access to basic system information and logs for troubleshooting. No access to modify settings or view sensitive data such as peer keys.</p> <h5>Backup Operator</h5>
<p>In addition to the permissions of the Viewer level, users at this level can view host backups and start instant backups.</p>
<h5>View Only User</h5> <h5>Host Manager</h5>
<p>Full view access, including peer keys and configuration files. Cannot modify any settings or configurations.</p> <p>Users at this level can configure, add, and remove hosts, and delete backups. They also have all the permissions of the Backup Operator level.</p>
<h5>Configuration Manager</h5>
<h5>Peer Manager</h5> <p>In addition to the permissions of the Host Manager level, users at this level can configure backup profiles, SSH keys, and router groups.</p>
<p>Permissions to add, edit, and remove peers and IP addresses. Does not include access to modify WireGuard instance configurations or higher-level settings.</p>
<h5>Manager</h5>
<p>Authority to add, edit, and remove configurations of WireGuard instances.</p>
<h5>Administrator</h5> <h5>Administrator</h5>
<p>Full access across the system. Can view and modify all settings, configurations and manage users. </p> <p>Users at this level have full administrative rights, including all the permissions of the previous levels.</p>
</div> </div>
</div> </div>
</div> </div>

View file

@ -0,0 +1,18 @@
# Generated by Django 5.0.3 on 2024-04-04 14:12
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('user_manager', '0001_initial'),
]
operations = [
migrations.AlterField(
model_name='useracl',
name='user_level',
field=models.PositiveIntegerField(choices=[(10, 'Viewer'), (20, 'Backup Operator'), (30, 'Host Manager'), (40, 'configuration Manager'), (50, 'Administrator')], default=0),
),
]

View file

@ -6,10 +6,10 @@ import uuid
class UserAcl(models.Model): class UserAcl(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE) user = models.OneToOneField(User, on_delete=models.CASCADE)
user_level = models.PositiveIntegerField(default=0, choices=( user_level = models.PositiveIntegerField(default=0, choices=(
(10, 'Debugging Analyst'), (10, 'Viewer'),
(20, 'View Only User'), (20, 'Backup Operator'),
(30, 'Peer Manager'), (30, 'Host Manager'),
(40, 'Manager'), (40, 'configuration Manager'),
(50, 'Administrator'), (50, 'Administrator'),
)) ))