mirror of
https://gitlab.com/allianceauth/allianceauth.git
synced 2025-07-09 12:30:15 +02:00
Permissions Auditing Tool (#698)
* Added block for page_title as title fragment * Add permissions auditing tool * Added tests for permissions audit tool * Added documentation for permissions tool * Add permissions tool to coverage
This commit is contained in:
parent
489b9a601d
commit
b636262e0c
@ -11,6 +11,7 @@ source =
|
|||||||
hrapplications
|
hrapplications
|
||||||
notifications
|
notifications
|
||||||
optimer
|
optimer
|
||||||
|
permissions_tool
|
||||||
services
|
services
|
||||||
srp
|
srp
|
||||||
timerboard
|
timerboard
|
||||||
|
@ -65,6 +65,7 @@ INSTALLED_APPS = [
|
|||||||
'fleetactivitytracking',
|
'fleetactivitytracking',
|
||||||
'notifications',
|
'notifications',
|
||||||
'esi',
|
'esi',
|
||||||
|
'permissions_tool',
|
||||||
'geelweb.django.navhelper',
|
'geelweb.django.navhelper',
|
||||||
'bootstrap_pagination',
|
'bootstrap_pagination',
|
||||||
|
|
||||||
|
@ -54,6 +54,7 @@ INSTALLED_APPS = [
|
|||||||
'fleetactivitytracking',
|
'fleetactivitytracking',
|
||||||
'notifications',
|
'notifications',
|
||||||
'esi',
|
'esi',
|
||||||
|
'permissions_tool',
|
||||||
'geelweb.django.navhelper',
|
'geelweb.django.navhelper',
|
||||||
'bootstrap_pagination',
|
'bootstrap_pagination',
|
||||||
'services.modules.mumble',
|
'services.modules.mumble',
|
||||||
@ -141,7 +142,7 @@ SUPERUSER_STATE_BYPASS = 'True' == os.environ.get('AA_SUPERUSER_STATE_BYPASS', '
|
|||||||
# Internationalization
|
# Internationalization
|
||||||
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
||||||
|
|
||||||
LANGUAGE_CODE = os.environ.get('AA_LANGUAGE_CODE', 'en-us')
|
LANGUAGE_CODE = os.environ.get('AA_LANGUAGE_CODE', 'en')
|
||||||
|
|
||||||
TIME_ZONE = os.environ.get('AA_TIME_ZONE', 'UTC')
|
TIME_ZONE = os.environ.get('AA_TIME_ZONE', 'UTC')
|
||||||
|
|
||||||
|
@ -17,6 +17,7 @@ import notifications.views
|
|||||||
import hrapplications.views
|
import hrapplications.views
|
||||||
import corputils.urls
|
import corputils.urls
|
||||||
import esi.urls
|
import esi.urls
|
||||||
|
import permissions_tool.urls
|
||||||
from alliance_auth import NAME
|
from alliance_auth import NAME
|
||||||
|
|
||||||
admin.site.site_header = NAME
|
admin.site.site_header = NAME
|
||||||
@ -211,6 +212,8 @@ urlpatterns += i18n_patterns(
|
|||||||
url(r'^fat/link/$', fleetactivitytracking.views.fatlink_view, name='auth_click_fatlink_view'),
|
url(r'^fat/link/$', fleetactivitytracking.views.fatlink_view, name='auth_click_fatlink_view'),
|
||||||
url(r'^fat/link/(?P<hash>[a-zA-Z0-9]+)/(?P<fatname>[a-z0-9_-]+)/$',
|
url(r'^fat/link/(?P<hash>[a-zA-Z0-9]+)/(?P<fatname>[a-z0-9_-]+)/$',
|
||||||
fleetactivitytracking.views.click_fatlink_view),
|
fleetactivitytracking.views.click_fatlink_view),
|
||||||
|
|
||||||
|
url(r'^permissions/', include(permissions_tool.urls))
|
||||||
)
|
)
|
||||||
|
|
||||||
# Append hooked service urls
|
# Append hooked service urls
|
||||||
|
@ -3,8 +3,9 @@
|
|||||||
```eval_rst
|
```eval_rst
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 1
|
:maxdepth: 1
|
||||||
:caption: Contents
|
:caption: Features Contents
|
||||||
|
|
||||||
hrapplications
|
hrapplications
|
||||||
corpstats
|
corpstats
|
||||||
|
permissions_tool
|
||||||
```
|
```
|
||||||
|
39
docs/features/permissions_tool.md
Normal file
39
docs/features/permissions_tool.md
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Permissions Auditing
|
||||||
|
|
||||||
|
```eval_rst
|
||||||
|
.. note::
|
||||||
|
New in 1.15
|
||||||
|
```
|
||||||
|
|
||||||
|
Access to most of Alliance Auth's features are controlled by Django's permissions system. In order to help you secure your services, Alliance Auth provides a permissions auditing tool.
|
||||||
|
|
||||||
|
### Access
|
||||||
|
|
||||||
|
In order to grant users access to the permissions auditing tool they will need to be granted the `permissions_tool.audit_permissions` permission or be a superuser.
|
||||||
|
|
||||||
|
When a user has access to the tool they will see the "Permissions Audit" menu item under the "Util" sub menu.
|
||||||
|
|
||||||
|
|
||||||
|
### Permissions Overview
|
||||||
|
|
||||||
|
The first page gives you a general overview of permissions and how many users have access to each permission.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
**App**, **Model** and **Code Name** contain the internal details of the permission while **Name** contains the name/description you'll see in the admin panel.
|
||||||
|
|
||||||
|
**Users** is the number of users explicitly granted this permission on their account.
|
||||||
|
|
||||||
|
**Groups** is the number of groups with this permission assigned.
|
||||||
|
|
||||||
|
**Groups Users** is the total number of users in all of the groups with this permission assigned.
|
||||||
|
|
||||||
|
Clicking on the **Code Name** link will take you to the [Permissions Audit Page](#permissions-audit-page)
|
||||||
|
|
||||||
|
### Permissions Audit Page
|
||||||
|
|
||||||
|
The permissions audit page will give you an overview of all the users who have access to this permission either directly or granted via group membership.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
Please note that users may appear multiple times if this permission is granted via multiple sources.
|
0
permissions_tool/__init__.py
Normal file
0
permissions_tool/__init__.py
Normal file
8
permissions_tool/apps.py
Normal file
8
permissions_tool/apps.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
|
class ServicesConfig(AppConfig):
|
||||||
|
name = 'permissions_tool'
|
||||||
|
|
20
permissions_tool/auth_hooks.py
Normal file
20
permissions_tool/auth_hooks.py
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
from services.hooks import MenuItemHook
|
||||||
|
from alliance_auth import hooks
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsTool(MenuItemHook):
|
||||||
|
def __init__(self):
|
||||||
|
MenuItemHook.__init__(self,
|
||||||
|
'Permissions Audit',
|
||||||
|
'fa fa-key fa-id-card grayiconecolor',
|
||||||
|
'permissions_overview', 400)
|
||||||
|
|
||||||
|
def render(self, request):
|
||||||
|
if request.user.has_perm('permissions_tool.audit_permissions'):
|
||||||
|
return MenuItemHook.render(self, request)
|
||||||
|
return ''
|
||||||
|
|
||||||
|
|
||||||
|
@hooks.register('menu_util_hook')
|
||||||
|
def register_menu():
|
||||||
|
return PermissionsTool()
|
26
permissions_tool/migrations/0001_initial.py
Normal file
26
permissions_tool/migrations/0001_initial.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# Generated by Django 1.10.5 on 2017-02-06 08:58
|
||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
|
||||||
|
initial = True
|
||||||
|
|
||||||
|
dependencies = [
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.CreateModel(
|
||||||
|
name='PermissionsTool',
|
||||||
|
fields=[
|
||||||
|
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||||
|
],
|
||||||
|
options={
|
||||||
|
'managed': False,
|
||||||
|
'permissions': (('audit_permissions', 'Can audit permissions'),),
|
||||||
|
},
|
||||||
|
),
|
||||||
|
]
|
0
permissions_tool/migrations/__init__.py
Normal file
0
permissions_tool/migrations/__init__.py
Normal file
12
permissions_tool/models.py
Normal file
12
permissions_tool/models.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from django.db import models
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsTool(models.Model):
|
||||||
|
"""
|
||||||
|
Dummy model for holding permissions
|
||||||
|
"""
|
||||||
|
class Meta:
|
||||||
|
managed = False
|
||||||
|
permissions = (
|
||||||
|
('audit_permissions', 'Can audit permissions'),
|
||||||
|
)
|
39
permissions_tool/templates/permissions_tool/audit.html
Normal file
39
permissions_tool/templates/permissions_tool/audit.html
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
{% extends "public/base.html" %}
|
||||||
|
{% load bootstrap %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page_title %}{{ permission.permission.codename }} - {% trans "Permissions Audit" %}{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<h1 class="page-header">{% trans "Permissions Audit" %}: {{ permission.permission.codename }}</h1>
|
||||||
|
<a href="{% url 'permissions_overview' %}" class="btn btn-default">
|
||||||
|
<i class="glyphicon glyphicon-chevron-left"></i> {% trans "Back" %}
|
||||||
|
</a>
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="col-md-3">
|
||||||
|
{% trans "Group" %}
|
||||||
|
</th>
|
||||||
|
<th class="col-md-3">
|
||||||
|
{% trans "User" %}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for user in permission.users %}
|
||||||
|
<tr>
|
||||||
|
{% include 'permissions_tool/audit_row.html' with group="Permission Granted Directly (No Group)" %}
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
{% for group in permission.groups %}
|
||||||
|
{% for user in group.user_set.all %}
|
||||||
|
{% include 'permissions_tool/audit_row.html' %}
|
||||||
|
{% endfor %}
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
10
permissions_tool/templates/permissions_tool/audit_row.html
Normal file
10
permissions_tool/templates/permissions_tool/audit_row.html
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{% if forloop.first %}
|
||||||
|
<b>{{ group }}</b>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ user }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
79
permissions_tool/templates/permissions_tool/overview.html
Normal file
79
permissions_tool/templates/permissions_tool/overview.html
Normal file
@ -0,0 +1,79 @@
|
|||||||
|
{% extends "public/base.html" %}
|
||||||
|
{% load bootstrap %}
|
||||||
|
{% load staticfiles %}
|
||||||
|
{% load i18n %}
|
||||||
|
|
||||||
|
{% block page_title %}{% trans "Permissions Overview" %}{% endblock page_title %}
|
||||||
|
|
||||||
|
{% block content %}
|
||||||
|
<div>
|
||||||
|
<h1 class="page-header">{% trans "Permissions Overview" %}</h1>
|
||||||
|
{% if request.GET.all != 'yes' %}
|
||||||
|
<span class="pull-right">
|
||||||
|
{% blocktrans %}Showing only applied permissions{% endblocktrans %}
|
||||||
|
<a href="{% url 'permissions_overview' %}?all=yes" class="btn btn-primary">{% trans "Show All" %}</a>
|
||||||
|
</span>
|
||||||
|
{% else %}
|
||||||
|
<span class="pull-right">
|
||||||
|
{% blocktrans %}Showing all permissions{% endblocktrans %}
|
||||||
|
<a href="{% url 'permissions_overview' %}?all=no" class="btn btn-primary">{% trans "Show Applied" %}</a>
|
||||||
|
</span>
|
||||||
|
{% endif %}
|
||||||
|
<table class="table table-hover">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>
|
||||||
|
{% trans "App" %}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{% trans "Model" %}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{% trans "Code Name" %}
|
||||||
|
</th>
|
||||||
|
<th>
|
||||||
|
{% trans "Name" %}
|
||||||
|
</th>
|
||||||
|
<th class="col-md-1">
|
||||||
|
{% trans "Users" %}
|
||||||
|
</th>
|
||||||
|
<th class="col-md-1">
|
||||||
|
{% trans "Groups" %}
|
||||||
|
</th>
|
||||||
|
<th class="col-md-1">
|
||||||
|
{% trans "Groups Users" %}
|
||||||
|
</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
{% for perm in permissions %}
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
{{ perm.permission.content_type.app_label }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ perm.permission.content_type.model }}
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<a href="{% url "permissions_audit" app_label=perm.permission.content_type.app_label model=perm.permission.content_type.model codename=perm.permission.codename %}">
|
||||||
|
{{ perm.permission.codename }}
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ perm.permission.name }}
|
||||||
|
</td>
|
||||||
|
<td class="{% if perm.users > 0 %}info {% endif %}text-right">
|
||||||
|
{{ perm.users }}
|
||||||
|
</td>
|
||||||
|
<td class="{% if perm.groups > 0 %}info {% endif %}text-right">
|
||||||
|
{{ perm.groups }}
|
||||||
|
</td>
|
||||||
|
<td class="{% if perm.group_users > 0 %}info {% endif %}text-right">
|
||||||
|
{{ perm.group_users }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
{% endblock content %}
|
122
permissions_tool/tests.py
Normal file
122
permissions_tool/tests.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Py3
|
||||||
|
from unittest import mock
|
||||||
|
except ImportError:
|
||||||
|
# Py2
|
||||||
|
import mock
|
||||||
|
|
||||||
|
from django.test import TestCase
|
||||||
|
from django import urls
|
||||||
|
from django.contrib.auth.models import User, Group, Permission
|
||||||
|
|
||||||
|
from alliance_auth.tests.auth_utils import AuthUtils
|
||||||
|
|
||||||
|
import six
|
||||||
|
|
||||||
|
|
||||||
|
class PermissionsToolViewsTestCase(TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.member = AuthUtils.create_member('auth_member')
|
||||||
|
self.member.set_password('password')
|
||||||
|
self.member.email = 'auth_member@example.com'
|
||||||
|
self.member.save()
|
||||||
|
self.none_user = AuthUtils.create_user('none_user', disconnect_signals=True)
|
||||||
|
self.none_user2 = AuthUtils.create_user('none_user2', disconnect_signals=True)
|
||||||
|
self.none_user3 = AuthUtils.create_user('none_user3', disconnect_signals=True)
|
||||||
|
|
||||||
|
self.no_perm_user = AuthUtils.create_user('no_perm_user', disconnect_signals=True)
|
||||||
|
self.no_perm_user.set_password('password')
|
||||||
|
|
||||||
|
AuthUtils.disconnect_signals()
|
||||||
|
self.no_perm_group = Group.objects.create(name="No Permission Group")
|
||||||
|
|
||||||
|
self.test_group = Group.objects.create(name="Test group")
|
||||||
|
|
||||||
|
self.test_group.user_set.add(self.none_user)
|
||||||
|
self.test_group.user_set.add(self.none_user2)
|
||||||
|
self.test_group.user_set.add(self.none_user3)
|
||||||
|
|
||||||
|
self.permission = Permission.objects.get_by_natural_key(codename='audit_permissions',
|
||||||
|
app_label='permissions_tool',
|
||||||
|
model='permissionstool')
|
||||||
|
|
||||||
|
self.test_group.permissions.add(self.permission)
|
||||||
|
self.member.user_permissions.add(self.permission)
|
||||||
|
AuthUtils.connect_signals()
|
||||||
|
|
||||||
|
def test_menu_item(self):
|
||||||
|
self.client.login(username=self.member.username, password='password')
|
||||||
|
|
||||||
|
response = self.client.get(urls.reverse('permissions_overview'))
|
||||||
|
|
||||||
|
response_content = response.content
|
||||||
|
if six.PY3:
|
||||||
|
response_content = str(response_content, encoding='utf8')
|
||||||
|
|
||||||
|
self.assertInHTML('<li><a class="active" href="/en/permissions/overview/"><i class="fa fa-key fa-id-card '
|
||||||
|
'grayiconecolor"></i> Permissions Audit</a></li>', response_content)
|
||||||
|
|
||||||
|
def test_permissions_overview(self):
|
||||||
|
self.client.login(username=self.member.username, password='password')
|
||||||
|
|
||||||
|
response = self.client.get(urls.reverse('permissions_overview'))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertTemplateUsed('permissions_tool/overview.html')
|
||||||
|
self.assertContains(response, self.permission.codename)
|
||||||
|
self.assertContains(response, self.permission.content_type.app_label)
|
||||||
|
self.assertContains(response, self.permission.content_type.model)
|
||||||
|
|
||||||
|
tested_context = False
|
||||||
|
# Test the context
|
||||||
|
for perm in response.context['permissions']:
|
||||||
|
if perm['permission'] == self.permission:
|
||||||
|
tested_context = True
|
||||||
|
self.assertDictContainsSubset({'users': 1}, perm)
|
||||||
|
self.assertDictContainsSubset({'groups': 1}, perm)
|
||||||
|
self.assertDictContainsSubset({'group_users': 3}, perm)
|
||||||
|
break
|
||||||
|
self.assertTrue(tested_context)
|
||||||
|
|
||||||
|
def test_permissions_overview_perms(self):
|
||||||
|
# Ensure permission effectively denys access
|
||||||
|
self.client.login(username=self.no_perm_user.username, password='password')
|
||||||
|
|
||||||
|
response = self.client.get(urls.reverse('permissions_overview'))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
def test_permissions_audit(self):
|
||||||
|
self.client.login(username=self.member.username, password='password')
|
||||||
|
|
||||||
|
response = self.client.get(urls.reverse('permissions_audit',
|
||||||
|
kwargs={
|
||||||
|
'app_label': self.permission.content_type.app_label,
|
||||||
|
'model': self.permission.content_type.model,
|
||||||
|
'codename': self.permission.codename,
|
||||||
|
}))
|
||||||
|
|
||||||
|
self.assertTemplateUsed('permissions_tool/audit.html')
|
||||||
|
self.assertTemplateUsed('permissions_tool/audit_row.html')
|
||||||
|
|
||||||
|
self.assertContains(response, self.permission.codename)
|
||||||
|
self.assertContains(response, self.none_user)
|
||||||
|
self.assertContains(response, self.none_user3)
|
||||||
|
self.assertContains(response, self.test_group)
|
||||||
|
|
||||||
|
self.assertNotContains(response, self.no_perm_user)
|
||||||
|
|
||||||
|
def test_permissions_audit_perms(self):
|
||||||
|
# Ensure permission effectively denys access
|
||||||
|
self.client.login(username=self.no_perm_user.username, password='password')
|
||||||
|
|
||||||
|
response = self.client.get(urls.reverse('permissions_audit',
|
||||||
|
kwargs={
|
||||||
|
'app_label': self.permission.content_type.app_label,
|
||||||
|
'model': self.permission.content_type.model,
|
||||||
|
'codename': self.permission.codename,
|
||||||
|
}))
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 302)
|
10
permissions_tool/urls.py
Normal file
10
permissions_tool/urls.py
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from django.conf.urls import url
|
||||||
|
|
||||||
|
from . import views
|
||||||
|
|
||||||
|
urlpatterns = [
|
||||||
|
url(r'^overview/$', views.permissions_overview, name='permissions_overview'),
|
||||||
|
url(r'^audit/(?P<app_label>[\w\-_]+)/(?P<model>[\w\-_]+)/(?P<codename>[\w\-_]+)/$', views.permissions_audit,
|
||||||
|
name='permissions_audit'),
|
||||||
|
]
|
55
permissions_tool/views.py
Normal file
55
permissions_tool/views.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
from django.contrib.auth.decorators import login_required, permission_required
|
||||||
|
from django.contrib.auth.models import Permission
|
||||||
|
from django.shortcuts import render, get_object_or_404
|
||||||
|
from django.db.models import Count
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@permission_required('permissions_tool.audit_permissions')
|
||||||
|
def permissions_overview(request):
|
||||||
|
logger.debug("permissions_overview called by user %s" % request.user)
|
||||||
|
perms = Permission.objects.all()
|
||||||
|
|
||||||
|
get_all = True if request.GET.get('all', 'no') == 'yes' else False
|
||||||
|
|
||||||
|
context = {'permissions': []}
|
||||||
|
for perm in perms:
|
||||||
|
this_perm = {
|
||||||
|
'users': perm.user_set.all().count(),
|
||||||
|
'groups': perm.group_set.all().count(),
|
||||||
|
'permission': perm
|
||||||
|
}
|
||||||
|
|
||||||
|
if get_all or this_perm['users'] > 0 or this_perm['groups'] > 0:
|
||||||
|
# Only add if we're getting everything or one of the objects has this permission
|
||||||
|
# Add group_users separately to improve performance
|
||||||
|
this_perm['group_users'] = sum(group.user_count for group in
|
||||||
|
perm.group_set.annotate(user_count=Count('user')))
|
||||||
|
context['permissions'].append(this_perm)
|
||||||
|
|
||||||
|
return render(request, 'permissions_tool/overview.html', context=context)
|
||||||
|
|
||||||
|
|
||||||
|
@login_required
|
||||||
|
@permission_required('permissions_tool.audit_permissions')
|
||||||
|
def permissions_audit(request, app_label, model, codename):
|
||||||
|
logger.debug("permissions_audit called by user {} on {}:{}:{}".format(request.user, app_label, model, codename))
|
||||||
|
perm = get_object_or_404(Permission,
|
||||||
|
content_type__app_label=app_label,
|
||||||
|
content_type__model=model,
|
||||||
|
codename=codename)
|
||||||
|
|
||||||
|
context = {'permission': {
|
||||||
|
'permission': perm,
|
||||||
|
'users': perm.user_set.all(),
|
||||||
|
'groups': perm.group_set.all(),
|
||||||
|
'group_users': [group.user_set.all() for group in perm.group_set.all()]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return render(request, 'permissions_tool/audit.html', context=context)
|
@ -13,7 +13,7 @@
|
|||||||
<meta name="description" content="">
|
<meta name="description" content="">
|
||||||
<meta name="author" content="">
|
<meta name="author" content="">
|
||||||
|
|
||||||
<title>{% block title %}Alliance Auth{% endblock title %}</title>
|
<title>{% block title %}{% block page_title %}{% endblock page_title %} - Alliance Auth{% endblock title %}</title>
|
||||||
|
|
||||||
<!-- Bootstrap Core CSS -->
|
<!-- Bootstrap Core CSS -->
|
||||||
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
<link href="{% static 'css/bootstrap.min.css' %}" rel="stylesheet">
|
||||||
|
Loading…
x
Reference in New Issue
Block a user