add policy type selection for access policies

This commit is contained in:
Eduardo Silva
2026-03-13 20:12:29 -03:00
parent e19033a28c
commit a9baffe725
6 changed files with 182 additions and 62 deletions

View File

@@ -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'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
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'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
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'<a href="{cancel_url}" class="btn btn-secondary">{_("Cancel")}</a>'),
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):

View File

@@ -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'),

View File

@@ -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': _('''
<h5>Application</h5>
<p>Define the main details of the application you want to expose through the gateway.</p>
<ul>
<li><strong>Name</strong>: A unique internal identifier for this application (e.g., "wiki", "crm"). Contains only letters, numbers, hyphens, or underscores.</li>
<li><strong>Display Name</strong>: A friendly, human-readable name for display purposes.</li>
<li><strong>Upstream</strong>: The destination URL where requests will be forwarded (e.g., <code>http://10.188.18.27:3000</code>). Must start with <code>http://</code> or <code>https://</code>.</li>
</ul>
''')
}
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': _('''
<h5>Public Policy</h5>
<p>A Public policy allows access to the application without requiring any authentication.</p>
''')
}
elif policy_type == 'deny':
form_description = {
'size': 'col-lg-6',
'content': _('''
<h5>Deny Policy</h5>
<p>A Deny policy blocks all access to the matched routes.</p>
''')
}
else:
form_description = {
'size': 'col-lg-6',
'content': _('''
<h5>Protected Policy</h5>
<p>A Protected policy requires users to authenticate before accessing the application.</p>
<ul>
<li><strong>Allowed Groups</strong>: Limits access to specific user groups. Note: Using groups requires selecting an Authentication Method of type "Local Password".</li>
<li><strong>Authentication Methods</strong>: Specify which methods users can use to authenticate (e.g., Local Password, TOTP, OIDC).</li>
</ul>
''')
}
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 = {