From 31fc3a1098ab52630efe9b3df291637f6a5cf236 Mon Sep 17 00:00:00 2001 From: Eduardo Silva Date: Wed, 3 Apr 2024 15:19:01 -0300 Subject: [PATCH] Routerfleet integration --- accounts/views.py | 8 ++ api/views.py | 84 ++++++++++++++++++- .../migrations/0003_authenticationtoken.py | 27 ++++++ user_manager/models.py | 7 ++ wireguard_webadmin/settings.py | 2 +- wireguard_webadmin/urls.py | 4 +- 6 files changed, 127 insertions(+), 5 deletions(-) create mode 100644 user_manager/migrations/0003_authenticationtoken.py diff --git a/accounts/views.py b/accounts/views.py index d413cd4..b7bdac8 100644 --- a/accounts/views.py +++ b/accounts/views.py @@ -1,6 +1,9 @@ from django.shortcuts import render, Http404, redirect from django.contrib.auth.models import User from django.contrib import auth +from django.contrib import messages + +from api.views import get_api_key from .forms import CreateUserForm, LoginForm from django.http import HttpResponse from user_manager.models import UserAcl @@ -25,6 +28,11 @@ def view_create_first_user(request): def view_login(request): if not User.objects.filter().all(): return redirect('/accounts/create_first_user/') + + if get_api_key('routerfleet'): + messages.warning(request, 'Login disabled|Login form is disabled. Check integration settings.') + return redirect('/accounts/logout/') + if request.method == 'POST': form = LoginForm(request.POST) if form.is_valid(): diff --git a/api/views.py b/api/views.py index df8be57..5befd37 100644 --- a/api/views.py +++ b/api/views.py @@ -1,9 +1,14 @@ +from django.contrib.auth.models import User +from django.contrib import auth from django.http import JsonResponse +from django.shortcuts import get_object_or_404, redirect from django.views.decorators.http import require_http_methods from django.http import HttpResponseForbidden from django.conf import settings from django.utils import timezone + +from user_manager.models import UserAcl, AuthenticationToken from wireguard.models import WebadminSettings, Peer, PeerStatus import requests import subprocess @@ -13,9 +18,14 @@ import os import uuid -def get_api_key(): - api_file_path = '/etc/wireguard/api_key' +def get_api_key(api_name): api_key = None + if api_name == 'api': + api_file_path = '/etc/wireguard/api_key' + elif api_name == 'routerfleet': + api_file_path = '/etc/wireguard/routerfleet_key' + else: + return api_key if os.path.exists(api_file_path) and os.path.isfile(api_file_path): with open(api_file_path, 'r') as api_file: @@ -31,12 +41,80 @@ def get_api_key(): return api_key +def routerfleet_authenticate_session(request): + AuthenticationToken.objects.filter(created__lt=timezone.now() - timezone.timedelta(minutes=1)).delete() + authentication_token = get_object_or_404(AuthenticationToken, uuid=request.GET.get('token')) + auth.login(request, authentication_token.user) + authentication_token.delete() + return redirect('/') + + +@require_http_methods(["GET"]) +def routerfleet_get_user_token(request): + data = {'status': '', 'message': '', 'authentication_token': ''} + if request.GET.get('key'): + api_key = get_api_key('routerfleet') + if api_key and api_key == request.GET.get('key'): + pass + else: + return HttpResponseForbidden() + else: + return HttpResponseForbidden() + + try: + default_user_level = int(request.GET.get('default_user_level')) + if default_user_level not in [10, 20, 30, 40, 50]: + default_user_level = 0 + except: + default_user_level = 0 + + if request.GET.get('username'): + user = User.objects.filter(username=request.GET.get('username')).first() + + if request.GET.get('action') == 'test': + if UserAcl.objects.filter(user=user, user_level__gte=50).exists(): + data['status'] = 'success' + data['message'] = 'User exists and is an administrator' + else: + data['status'] = 'error' + data['message'] = f'Administrator with username {request.GET.get("username")} not found at wireguard_webadmin.' + + elif request.GET.get('action') == 'login': + if user: + user_acl = UserAcl.objects.filter(user=user).first() + else: + if default_user_level == 0: + data['status'] = 'error' + data['message'] = 'User not found' + else: + user = User.objects.create_user(username=request.GET.get('username'), password=str(uuid.uuid4())) + user_acl = UserAcl.objects.create(user=user, user_level=default_user_level) + + if user and user_acl: + authentication_token = AuthenticationToken.objects.create(user=user) + data['status'] = 'success' + data['message'] = 'User authenticated successfully' + data['authentication_token'] = str(authentication_token.uuid) + else: + data['status'] = 'error' + data['message'] = 'Invalid action' + + else: + data['status'] = 'error' + data['message'] = 'No username provided' + + if data['status'] == 'error': + return JsonResponse(data, status=400) + else: + return JsonResponse(data) + + @require_http_methods(["GET"]) def wireguard_status(request): if request.user.is_authenticated: pass elif request.GET.get('key'): - api_key = get_api_key() + api_key = get_api_key('api') if api_key and api_key == request.GET.get('key'): pass else: diff --git a/user_manager/migrations/0003_authenticationtoken.py b/user_manager/migrations/0003_authenticationtoken.py new file mode 100644 index 0000000..a91c473 --- /dev/null +++ b/user_manager/migrations/0003_authenticationtoken.py @@ -0,0 +1,27 @@ +# Generated by Django 5.0.2 on 2024-04-03 16:45 + +import django.db.models.deletion +import uuid +from django.conf import settings +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('user_manager', '0002_remove_useracl_id_useracl_created_useracl_updated_and_more'), + migrations.swappable_dependency(settings.AUTH_USER_MODEL), + ] + + operations = [ + migrations.CreateModel( + name='AuthenticationToken', + fields=[ + ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('created', models.DateTimeField(auto_now_add=True)), + ('updated', models.DateTimeField(auto_now=True)), + ('uuid', models.UUIDField(default=uuid.uuid4, editable=False)), + ('user', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)), + ], + ), + ] diff --git a/user_manager/models.py b/user_manager/models.py index 1768846..9fec415 100644 --- a/user_manager/models.py +++ b/user_manager/models.py @@ -19,3 +19,10 @@ class UserAcl(models.Model): def __str__(self): return self.user.username + + +class AuthenticationToken(models.Model): + user = models.ForeignKey(User, on_delete=models.CASCADE) + created = models.DateTimeField(auto_now_add=True) + updated = models.DateTimeField(auto_now=True) + uuid = models.UUIDField(editable=False, default=uuid.uuid4) diff --git a/wireguard_webadmin/settings.py b/wireguard_webadmin/settings.py index 19858bd..787c510 100644 --- a/wireguard_webadmin/settings.py +++ b/wireguard_webadmin/settings.py @@ -129,6 +129,6 @@ STATICFILES_DIRS = [ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' -WIREGUARD_WEBADMIN_VERSION = 9604 +WIREGUARD_WEBADMIN_VERSION = 9605 from wireguard_webadmin.production_settings import * \ No newline at end of file diff --git a/wireguard_webadmin/urls.py b/wireguard_webadmin/urls.py index 0c853cd..cb669f1 100644 --- a/wireguard_webadmin/urls.py +++ b/wireguard_webadmin/urls.py @@ -22,7 +22,7 @@ from console.views import view_console from user_manager.views import view_user_list, view_manage_user from accounts.views import view_create_first_user, view_login, view_logout from wireguard_tools.views import export_wireguard_configs, download_config_or_qrcode, restart_wireguard_interfaces -from api.views import wireguard_status, cron_check_updates, cron_update_peer_latest_handshake +from api.views import wireguard_status, cron_check_updates, cron_update_peer_latest_handshake, routerfleet_get_user_token, routerfleet_authenticate_session from firewall.views import view_redirect_rule_list, manage_redirect_rule, view_firewall_rule_list, manage_firewall_rule, view_manage_firewall_settings, view_generate_iptables_script, view_reset_firewall, view_firewall_migration_required @@ -43,6 +43,8 @@ urlpatterns = [ path('accounts/create_first_user/', view_create_first_user, name='create_first_user'), path('accounts/login/', view_login, name='login'), path('accounts/logout/', view_logout, name='logout'), + path('accounts/routerfleet_authenticate_session/', routerfleet_authenticate_session, name='routerfleet_authenticate_session'), + path('api/routerfleet_get_user_token/', routerfleet_get_user_token, name='routerfleet_get_user_token'), path('api/wireguard_status/', wireguard_status, name='api_wireguard_status'), path('api/cron_check_updates/', cron_check_updates, name='cron_check_updates'), path('api/cron_update_peer_latest_handshake/', cron_update_peer_latest_handshake, name='cron_update_peer_latest_handshake'),