groups: User permissions for access to apps based on LDAP groups

- More user-friendly treatment of groups and their permissions

Closes #690

Signed-off-by: Joseph Nuthalapati <njoseph@thoughtworks.com>
Reviewed-by: James Valleroy <jvalleroy@mailbox.org>
This commit is contained in:
Joseph Nuthalapati 2017-10-25 17:50:33 +05:30 committed by James Valleroy
parent 2f67fb49d4
commit 7ce5d1f636
No known key found for this signature in database
GPG Key ID: 77C0C75E7B650808
8 changed files with 51 additions and 38 deletions

View File

@ -346,17 +346,6 @@ def subcommand_remove_user_from_group(arguments):
flush_cache()
def subcommand_get_all_groups(_):
"""Get all user groups"""
get_groups = "getent group".split()
cut_names = "cut -d: -f1".split()
groups = subprocess.Popen(get_groups, stdout=subprocess.PIPE, shell=False)
trimmed_groups = subprocess.Popen(cut_names, stdin=groups.stdout,
stdout=subprocess.PIPE, shell=False)
groups.stdout.close()
print(trimmed_groups.communicate()[0].decode())
def flush_cache():
"""Flush nscd cache."""
_run(['nscd', '--invalidate=passwd'])

View File

@ -8,12 +8,12 @@ Alias /tt-rss-app /usr/share/tt-rss/www
<Location /tt-rss>
Include includes/freedombox-single-sign-on.conf
<IfModule mod_auth_pubtkt.c>
TKTAuthToken "newsfeed" "admin"
TKTAuthToken "feed-reader" "admin"
</IfModule>
</Location>
<Location /tt-rss-app>
Include includes/freedombox-auth-ldap.conf
Require valid-user
# TODO Restrict access to `newsfeed` group
# TODO Restrict access to `feed-reader` group
</Location>

View File

@ -26,7 +26,7 @@ from plinth import action_utils
from plinth import frontpage
from plinth import service as service_module
from plinth.menu import main_menu
from plinth.modules.users import add_group
from plinth.modules.users import create_group, register_group
from .manifest import clients
@ -51,6 +51,8 @@ description = [
'it immediately after enabling this service.')
]
group = ('bit-torrent', _('Download files using BitTorrent applications'))
reserved_usernames = ['debian-deluged']
clients = clients
@ -72,6 +74,7 @@ def init():
if is_enabled():
add_shortcut()
register_group(group)
def setup(helper, old_version=None):
@ -86,7 +89,7 @@ def setup(helper, old_version=None):
disable=disable)
helper.call('post', service.notify_enabled, None, True)
helper.call('post', add_shortcut)
add_group('bittorrent')
create_group(group[0])
def add_shortcut():

View File

@ -28,6 +28,7 @@ from plinth import cfg
from plinth import frontpage
from plinth import service as service_module
from plinth.menu import main_menu
from plinth.modules.users import create_group, register_group
from .manifest import clients
@ -61,6 +62,9 @@ description = [
clients = clients
group = ('wiki', _('View and edit wiki applications'))
def init():
"""Initialize the ikiwiki module."""
menu = main_menu.get('apps')
@ -75,6 +79,7 @@ def init():
if is_enabled():
add_shortcuts()
register_group(group)
def setup(helper, old_version=None):
@ -88,6 +93,7 @@ def setup(helper, old_version=None):
is_enabled=is_enabled, enable=enable, disable=disable)
helper.call('post', service.notify_enabled, None, True)
helper.call('post', add_shortcuts)
create_group(group[0])
def add_shortcuts():

View File

@ -25,7 +25,7 @@ from django.utils.translation import ugettext_lazy as _
from plinth import service as service_module
from plinth import action_utils, actions, frontpage
from plinth.menu import main_menu
from plinth.modules.users import add_group
from plinth.modules.users import create_group, register_group
from .manifest import clients
@ -37,7 +37,7 @@ managed_packages = ['transmission-daemon']
name = _('Transmission')
short_description = _('BitTorrent')
short_description = _('BitTorrent Web Client')
description = [
_('BitTorrent is a peer-to-peer file sharing protocol. '
@ -50,6 +50,8 @@ clients = clients
reserved_usernames = ['debian-transmission']
group = ('bit-torrent', _('Download files using BitTorrent applications'))
service = None
@ -69,6 +71,7 @@ def init():
if is_enabled():
add_shortcut()
register_group(group)
def setup(helper, old_version=None):
@ -92,7 +95,7 @@ def setup(helper, old_version=None):
disable=disable)
helper.call('post', service.notify_enabled, None, True)
helper.call('post', add_shortcut)
add_group('bit-torrent')
create_group(group[0])
def add_shortcut():

View File

@ -28,7 +28,7 @@ from plinth import cfg
from plinth import frontpage
from plinth import service as service_module
from plinth.menu import main_menu
from plinth.modules.users import add_group
from plinth.modules.users import create_group, register_group
from .manifest import clients
@ -61,6 +61,8 @@ description = [
clients = clients
group = ('feed-reader', _('Read and subscribe to news feeds'))
service = None
@ -80,6 +82,7 @@ def init():
if is_enabled():
add_shortcut()
register_group(group)
def setup(helper, old_version=None):
@ -95,7 +98,7 @@ def setup(helper, old_version=None):
is_enabled=is_enabled, enable=enable, disable=disable)
helper.call('post', service.notify_enabled, None, True)
helper.call('post', add_shortcut)
add_group('newsfeed')
create_group(group[0])
def add_shortcut():

View File

@ -45,6 +45,9 @@ first_boot_steps = [
name = _('Users and Groups')
# List of all Plinth user groups
groups = set()
def init():
"""Intialize the user module."""
@ -87,7 +90,7 @@ def _diagnose_ldap_entry(search_item):
.format(search_item=search_item), result]
def add_group(group):
def create_group(group):
"""Add an LDAP group."""
actions.superuser_run('users', options=['create-group', group])
@ -104,3 +107,7 @@ def get_all_groups():
return set(groups.strip().split())
except ActionError:
return {}
def register_group(group):
groups.add(group)

View File

@ -28,23 +28,18 @@ from django.utils.translation import ugettext as _, ugettext_lazy
from plinth import actions
from plinth.errors import ActionError
from plinth.modules import first_boot
from plinth.modules import users
from plinth.modules.security import set_restricted_access
from plinth.modules.users import get_all_groups
from plinth.utils import is_user_admin
from plinth import module_loader
PLINTH_APP_GROUPS = {
'admin',
'newsfeed',
}
def get_group_choices():
groups = PLINTH_APP_GROUPS.intersection(get_all_groups())
return ((group, _(group)) for group in groups)
GROUP_CHOICES = get_group_choices()
"""Return localized group description and group name in one string."""
admin_group = ('admin', _('Access to all services and system settings'))
users.register_group(admin_group)
choices = {(g[0], ('{} ({})'.format(g[1], g[0]))) for g in users.groups}
return sorted(list(choices), key=lambda g: g[0])
class ValidNewUsernameCheckMixin(object):
@ -84,10 +79,9 @@ class CreateUserForm(ValidNewUsernameCheckMixin, UserCreationForm):
Include options to add user to groups.
"""
groups = forms.MultipleChoiceField(
choices=GROUP_CHOICES,
label=ugettext_lazy('Groups'),
choices=get_group_choices(),
label=ugettext_lazy('Permissions'),
required=False,
widget=forms.CheckboxSelectMultiple,
help_text=ugettext_lazy(
@ -103,6 +97,7 @@ class CreateUserForm(ValidNewUsernameCheckMixin, UserCreationForm):
"""Initialize the form with extra request argument."""
self.request = request
super(CreateUserForm, self).__init__(*args, **kwargs)
self.fields['groups'].choices = get_group_choices()
def save(self, commit=True):
"""Save the user model and create LDAP user if required."""
@ -158,14 +153,21 @@ class UserUpdateForm(ValidNewUsernameCheckMixin, forms.ModelForm):
def __init__(self, request, username, *args, **kwargs):
"""Initialize the form with extra request argument."""
for group, group_name in GROUP_CHOICES:
group_choices = dict(get_group_choices())
for group in group_choices:
Group.objects.get_or_create(name=group)
self.request = request
self.username = username
super(UserUpdateForm, self).__init__(*args, **kwargs)
choices = [ # Replace group names with descriptions
(c[0], group_choices[c[1]])
for c in sorted(self.fields['groups'].choices, key=lambda x: x[1])]
self.fields['groups'].label = 'Permissions'
self.fields['groups'].choices = choices
if not is_user_admin(request):
self.fields['is_active'].widget = forms.HiddenInput()
self.fields['groups'].disabled = True
@ -278,7 +280,7 @@ class FirstBootForm(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm):
_('Failed to add new user to admin group.'))
# Create initial Django groups
for group_choice in GROUP_CHOICES:
for group_choice in get_group_choices():
auth.models.Group.objects.get_or_create(name=group_choice[0])
admin_group = auth.models.Group.objects.get(name='admin')