import io import pyotp import qrcode from django.contrib import messages from django.contrib.auth.decorators import login_required from django.http import HttpResponse from django.shortcuts import render, get_object_or_404, redirect from django.urls import reverse from django.utils.translation import gettext as _ from gatekeeper.forms import GatekeeperUserForm, GatekeeperGroupForm, AuthMethodForm, AuthMethodAllowedDomainForm, \ AuthMethodAllowedEmailForm, GatekeeperIPAddressForm from gatekeeper.models import GatekeeperUser, GatekeeperGroup, AuthMethod, AuthMethodAllowedDomain, \ AuthMethodAllowedEmail, GatekeeperIPAddress from user_manager.models import UserAcl @login_required def view_gatekeeper_list(request): """Main list view containing tabs for Users, Groups, and Auth Methods""" if not UserAcl.objects.filter(user=request.user).filter(user_level__gte=20).exists(): return render(request, 'access_denied.html', {'page_title': _('Access Denied')}) active_tab = request.GET.get('tab', 'auth_methods') auth_methods = AuthMethod.objects.all().order_by('name') users = GatekeeperUser.objects.all().order_by('username') groups = GatekeeperGroup.objects.all().order_by('name') auth_domains = AuthMethodAllowedDomain.objects.all().order_by('domain') auth_emails = AuthMethodAllowedEmail.objects.all().order_by('email') auth_ips = GatekeeperIPAddress.objects.all().order_by('address') context = { 'users': users, 'groups': groups, 'auth_methods': auth_methods, 'auth_domains': auth_domains, 'auth_emails': auth_emails, 'auth_ips': auth_ips, 'active_tab': active_tab, } return render(request, 'gatekeeper/gatekeeper_list.html', context) @login_required def view_manage_gatekeeper_user(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')}) gatekeeper_user_uuid = request.GET.get('uuid') if gatekeeper_user_uuid: gatekeeper_user = get_object_or_404(GatekeeperUser, uuid=gatekeeper_user_uuid) title = _('Edit Gatekeeper User') else: gatekeeper_user = None title = _('Create Gatekeeper User') cancel_url = reverse('gatekeeper_list') + '?tab=users' form = GatekeeperUserForm(request.POST or None, instance=gatekeeper_user, cancel_url=cancel_url) if form.is_valid(): form.save() messages.success(request, _('Gatekeeper User saved successfully.')) return redirect(cancel_url) context = { 'form': form, 'title': title, 'page_title': title, } return render(request, 'generic_form.html', context) @login_required def view_delete_gatekeeper_user(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')}) gatekeeper_user = get_object_or_404(GatekeeperUser, uuid=request.GET.get('uuid')) cancel_url = reverse('gatekeeper_list') + '?tab=users' if request.method == 'POST': gatekeeper_user.delete() messages.success(request, _('Gatekeeper User deleted successfully.')) return redirect(cancel_url) context = { 'gatekeeper_user': gatekeeper_user, 'title': _('Delete Gatekeeper User'), 'cancel_url': cancel_url, 'text': _('Are you sure you want to delete the user "%(username)s"?') % {'username': gatekeeper_user.username} } return render(request, 'generic_delete_confirmation.html', context) @login_required def view_manage_gatekeeper_group(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')}) gatekeeper_group_uuid = request.GET.get('uuid') if gatekeeper_group_uuid: gatekeeper_group = get_object_or_404(GatekeeperGroup, uuid=gatekeeper_group_uuid) title = _('Edit Gatekeeper Group') else: gatekeeper_group = None title = _('Create Gatekeeper Group') cancel_url = reverse('gatekeeper_list') + '?tab=groups' form = GatekeeperGroupForm(request.POST or None, instance=gatekeeper_group, cancel_url=cancel_url) if form.is_valid(): form.save() messages.success(request, _('Gatekeeper Group saved successfully.')) return redirect(cancel_url) context = { 'form': form, 'title': title, 'page_title': title, } return render(request, 'generic_form.html', context) @login_required def view_delete_gatekeeper_group(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')}) gatekeeper_group = get_object_or_404(GatekeeperGroup, uuid=request.GET.get('uuid')) cancel_url = reverse('gatekeeper_list') + '?tab=groups' if request.method == 'POST': gatekeeper_group.delete() messages.success(request, _('Gatekeeper Group deleted successfully.')) return redirect(cancel_url) context = { 'gatekeeper_group': gatekeeper_group, 'title': _('Delete Gatekeeper Group'), 'cancel_url': cancel_url, 'text': _('Are you sure you want to delete the group "%(name)s"?') % {'name': gatekeeper_group.name} } return render(request, 'generic_delete_confirmation.html', context) @login_required def view_manage_auth_method(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')}) auth_method_uuid = request.GET.get('uuid') if auth_method_uuid: auth_method = get_object_or_404(AuthMethod, uuid=auth_method_uuid) title = _('Edit Authentication Method') else: auth_method = None title = _('Create Authentication Method') cancel_url = reverse('gatekeeper_list') + '?tab=auth_methods' form = AuthMethodForm(request.POST or None, instance=auth_method, cancel_url=cancel_url) if form.is_valid(): form.save() messages.success(request, _('Authentication Method saved successfully.')) return redirect(cancel_url) form_description = { 'size': '', 'content': _('''
Select how users will authenticate through this method.
Users will authenticate using a standard username and password stored locally. Only one of this type can be created.
Users will authenticate via an external identity provider (like Keycloak, Google, or Authelia). Requires Provider URL, Client ID, and Client Secret.
Users will need to enter a rotating token from an authenticator app. Requires setting a Global TOTP Secret.
If Global TOTP Before Authentication is enabled, the PIN is required before the username and password to help combat bruteforce attacks.
Manage specific IP addresses or networks that are allowed or denied access when using the IP Address List authentication method.
Enter a single IP address (e.g., 192.168.1.50) or a network address. Use the prefix length for CIDR notation (e.g., 24 for a /24 network). Leave prefix blank for a single host (/32 for IPv4, /128 for IPv6).
Allow: Grants access to the specified IP/network.
Deny: Specifically blocks access from the specified IP/network.
An optional note to help identify this entry (e.g., "Office Network", "Blocked Attacker").
''') } context = { 'form': form, 'title': title, 'page_title': title, 'form_description': form_description, } return render(request, 'generic_form.html', context) @login_required def view_delete_gatekeeper_ip(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')}) gatekeeper_ip = get_object_or_404(GatekeeperIPAddress, uuid=request.GET.get('uuid')) cancel_url = reverse('gatekeeper_list') + '?tab=ip_addresses' if request.method == 'POST': gatekeeper_ip.delete() messages.success(request, _('IP Address deleted successfully.')) return redirect(cancel_url) context = { 'gatekeeper_ip': gatekeeper_ip, 'title': _('Delete IP Address'), 'cancel_url': cancel_url, 'text': _('Are you sure you want to delete the IP address "%(address)s"?') % {'address': gatekeeper_ip.address} } return render(request, 'generic_delete_confirmation.html', context)