diff --git a/app_gateway/forms.py b/app_gateway/forms.py
index 79425e2..dadc893 100644
--- a/app_gateway/forms.py
+++ b/app_gateway/forms.py
@@ -104,29 +104,72 @@ class AccessPolicyForm(forms.ModelForm):
def __init__(self, *args, **kwargs):
cancel_url = kwargs.pop('cancel_url', '#')
+ policy_type = kwargs.pop('policy_type', None)
super().__init__(*args, **kwargs)
+ if self.instance and self.instance.pk:
+ policy_type = self.instance.policy_type
+
+ if policy_type and not self.initial.get('policy_type'):
+ self.initial['policy_type'] = policy_type
+
+ self.fields['policy_type'].widget = forms.HiddenInput()
+
self.helper = FormHelper()
- self.helper.layout = Layout(
- Div(
- Div('name', css_class='col-md-6'),
- Div('policy_type', css_class='col-md-6'),
- css_class='row'
- ),
- Div(
- Div('groups', css_class='col-md-6'),
- Div('methods', css_class='col-md-6'),
- css_class='row'
- ),
- Div(
+
+ if policy_type in ['public', 'deny']:
+ self.helper.layout = Layout(
Div(
- Submit('submit', _('Save'), css_class='btn btn-primary'),
- HTML(f'{_("Cancel")}'),
- css_class='col-md-12'
+ Div('name', css_class='col-md-12'),
+ 'policy_type',
+ css_class='row'
),
- css_class='row'
+ Div(
+ Div(
+ Submit('submit', _('Save'), css_class='btn btn-primary'),
+ HTML(f'{_("Cancel")}'),
+ css_class='col-md-12'
+ ),
+ css_class='row'
+ )
)
- )
+ else:
+ self.helper.layout = Layout(
+ Div(
+ Div('name', css_class='col-md-12'),
+ 'policy_type',
+ css_class='row'
+ ),
+ Div(Div('methods', css_class='col-md-12'), css_class='row'),
+ Div(Div('groups', css_class='col-md-12'), css_class='row'),
+ Div(
+ Div(
+ Submit('submit', _('Save'), css_class='btn btn-primary'),
+ HTML(f'{_("Cancel")}'),
+ css_class='col-md-12'
+ ),
+ css_class='row'
+ )
+ )
+
+ def clean(self):
+ cleaned_data = super().clean()
+ policy_type = cleaned_data.get('policy_type')
+ groups = cleaned_data.get('groups')
+ methods = cleaned_data.get('methods')
+
+ if policy_type == 'protected':
+ if groups and len(groups) > 0:
+ has_local_password = False
+ if methods:
+ for method in methods:
+ if method.auth_type == 'local_password':
+ has_local_password = True
+ break
+ if not has_local_password:
+ self.add_error(None, _("User groups can only be used with local user authentication."))
+
+ return cleaned_data
class ApplicationPolicyForm(forms.ModelForm):
diff --git a/app_gateway/urls.py b/app_gateway/urls.py
index fac4c35..f0311aa 100644
--- a/app_gateway/urls.py
+++ b/app_gateway/urls.py
@@ -16,6 +16,7 @@ urlpatterns = [
path('host/delete/', views.view_delete_application_host, name='delete_application_host'),
# Access Policies
+ path('policy/select-type/', views.view_select_policy_type, name='select_policy_type'),
path('policy/manage/', views.view_manage_access_policy, name='manage_access_policy'),
path('policy/delete/', views.view_delete_access_policy, name='delete_access_policy'),
diff --git a/app_gateway/views.py b/app_gateway/views.py
index fe96609..7d2e614 100644
--- a/app_gateway/views.py
+++ b/app_gateway/views.py
@@ -1,5 +1,6 @@
from django.contrib import messages
from django.contrib.auth.decorators import login_required
+from django.db.models import ProtectedError
from django.shortcuts import render, get_object_or_404, redirect
from django.urls import reverse
from django.utils.translation import gettext as _
@@ -78,10 +79,24 @@ def view_manage_application(request):
messages.success(request, _('Application saved successfully.'))
return redirect(cancel_url)
+ form_description = {
+ 'size': 'col-lg-6',
+ 'content': _('''
+
Application
+ Define the main details of the application you want to expose through the gateway.
+
+ - Name: A unique internal identifier for this application (e.g., "wiki", "crm"). Contains only letters, numbers, hyphens, or underscores.
+ - Display Name: A friendly, human-readable name for display purposes.
+ - Upstream: The destination URL where requests will be forwarded (e.g.,
http://10.188.18.27:3000). Must start with http:// or https://.
+
+ ''')
+ }
+
context = {
'form': form,
'title': title,
'page_title': title,
+ 'form_description': form_description,
}
return render(request, 'generic_form.html', context)
@@ -168,34 +183,77 @@ def view_delete_application_host(request):
return render(request, 'generic_delete_confirmation.html', context)
+@login_required
+def view_select_policy_type(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 = {
+ 'page_title': _('Select Access Policy Type'),
+ }
+ return render(request, 'app_gateway/access_policy_type_select.html', context)
+
+
@login_required
def view_manage_access_policy(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')})
access_policy_uuid = request.GET.get('uuid')
+ policy_type = request.GET.get('policy_type')
if access_policy_uuid:
access_policy = get_object_or_404(AccessPolicy, uuid=access_policy_uuid)
title = _('Edit Access Policy')
+ policy_type = access_policy.policy_type
else:
access_policy = None
title = _('Create Access Policy')
cancel_url = reverse('app_gateway_list') + '?tab=policies'
- form = AccessPolicyForm(request.POST or None, instance=access_policy, cancel_url=cancel_url)
+ form = AccessPolicyForm(request.POST or None, instance=access_policy, cancel_url=cancel_url, policy_type=policy_type)
if form.is_valid():
form.save()
messages.success(request, _('Access Policy saved successfully.'))
return redirect(cancel_url)
+ if policy_type == 'public':
+ form_description = {
+ 'size': 'col-lg-6',
+ 'content': _('''
+ Public Policy
+ A Public policy allows access to the application without requiring any authentication.
+ ''')
+ }
+ elif policy_type == 'deny':
+ form_description = {
+ 'size': 'col-lg-6',
+ 'content': _('''
+ Deny Policy
+ A Deny policy blocks all access to the matched routes.
+ ''')
+ }
+ else:
+ form_description = {
+ 'size': 'col-lg-6',
+ 'content': _('''
+ Protected Policy
+ A Protected policy requires users to authenticate before accessing the application.
+
+ - Allowed Groups: Limits access to specific user groups. Note: Using groups requires selecting an Authentication Method of type "Local Password".
+ - Authentication Methods: Specify which methods users can use to authenticate (e.g., Local Password, TOTP, OIDC).
+
+ ''')
+ }
+
context = {
'form': form,
'title': title,
'page_title': title,
+ 'form_description': form_description,
}
- return render(request, 'app_gateway/app_gateway_policy_form.html', context)
+ return render(request, 'generic_form.html', context)
@login_required
@@ -208,8 +266,11 @@ def view_delete_access_policy(request):
cancel_url = reverse('app_gateway_list') + '?tab=policies'
if request.method == 'POST':
- access_policy.delete()
- messages.success(request, _('Access Policy deleted successfully.'))
+ try:
+ access_policy.delete()
+ messages.success(request, _('Access Policy deleted successfully.'))
+ except ProtectedError:
+ messages.error(request, _('Cannot delete this Access Policy because it is currently in use by an Application Route or Application Default Policy.'))
return redirect(cancel_url)
context = {
diff --git a/templates/app_gateway/access_policy_type_select.html b/templates/app_gateway/access_policy_type_select.html
new file mode 100644
index 0000000..2fb16ca
--- /dev/null
+++ b/templates/app_gateway/access_policy_type_select.html
@@ -0,0 +1,55 @@
+{% extends "base.html" %}
+{% load i18n %}
+
+{% block content %}
+
+
+
+
+
+
{% trans 'Choose the type of access policy you want to create.' %}
+
+
+
+
+
+
+
{% trans 'Public' %}
+
{% trans 'Allow access to everyone without authentication.' %}
+
{% trans 'Select' %}
+
+
+
+
+
+
+
+
+
{% trans 'Protected' %}
+
{% trans 'Require authentication using specified methods or groups.' %}
+
{% trans 'Select' %}
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %}
diff --git a/templates/app_gateway/app_gateway_list.html b/templates/app_gateway/app_gateway_list.html
index 184b6d3..ad72d44 100644
--- a/templates/app_gateway/app_gateway_list.html
+++ b/templates/app_gateway/app_gateway_list.html
@@ -119,7 +119,7 @@
{% elif active_tab == 'policies' %}
diff --git a/templates/app_gateway/app_gateway_policy_form.html b/templates/app_gateway/app_gateway_policy_form.html
deleted file mode 100644
index df995b1..0000000
--- a/templates/app_gateway/app_gateway_policy_form.html
+++ /dev/null
@@ -1,40 +0,0 @@
-{% extends 'base.html' %}
-{% load crispy_forms_tags %}
-
-{% block content %}
-
-
-
- {% if form_description %}
-
- {% endif %}
-
-
-{% endblock %}
-
-{% block custom_page_scripts %}
-
-{% endblock %}
\ No newline at end of file