users: Handle errors better during POSIX user operations

- If during an action, user does not exist ignore.

- If during an action, return a non-zero exist status.

- Catch an errors during actions as exceptions.

- Display a message that corresponding POSIX operation failed.
This commit is contained in:
Sunil Mohan Adapa 2015-01-25 01:42:15 +05:30
parent d27cd02193
commit a3de3ae277
9 changed files with 114 additions and 35 deletions

View File

@ -30,5 +30,5 @@ fi
echo "$username:$password" | chpasswd echo "$username:$password" | chpasswd
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed: could not set user password" echo "Failed: could not set user password"
exit exit 2
fi fi

View File

@ -22,17 +22,17 @@ password="$2"
adduser --disabled-password --gecos "" "$username" adduser --disabled-password --gecos "" "$username"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed to create user" echo "Failed to create user"
exit exit 1
fi fi
adduser "$username" sudo adduser "$username" sudo
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed to add user to sudo group" echo "Failed to add user to sudo group"
exit exit 2
fi fi
echo "$username:$password" | chpasswd echo "$username:$password" | chpasswd
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed to set user password" echo "Failed to set user password"
exit exit 3
fi fi

View File

@ -31,4 +31,5 @@ if [ $? -eq 0 ]; then
echo "Success: user deleted" echo "Success: user deleted"
else else
echo "Failed: userdel error" echo "Failed: userdel error"
exit 2
fi fi

View File

@ -20,7 +20,14 @@
username="$1" username="$1"
getent passwd "$username"
if [ $? -ne 0 ]; then
echo "Failed: user not found"
exit
fi
usermod --expiredate 1 "$username" usermod --expiredate 1 "$username"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed" echo "Failed"
exit 2
fi fi

View File

@ -20,7 +20,14 @@
username="$1" username="$1"
getent passwd "$username"
if [ $? -ne 0 ]; then
echo "Failed: user not found"
exit
fi
usermod --expiredate "" "$username" usermod --expiredate "" "$username"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
echo "Failed" echo "Failed"
exit 2
fi fi

View File

@ -21,6 +21,7 @@ from django.core import validators
from gettext import gettext as _ from gettext import gettext as _
from plinth import actions from plinth import actions
from plinth.errors import ActionError
from plinth.modules.config import config from plinth.modules.config import config
@ -62,9 +63,13 @@ than 63 characters in length.'),
user.set_password(self.cleaned_data['password']) user.set_password(self.cleaned_data['password'])
if commit: if commit:
user.save() user.save()
actions.superuser_run( try:
'create-user', actions.superuser_run(
[user.username, self.cleaned_data['password']]) 'create-user',
[user.get_username(), self.cleaned_data['password']])
except ActionError:
messages.error(self.request,
_('Creating POSIX system user failed.'))
self.login_user() self.login_user()
return user return user

View File

@ -19,12 +19,9 @@
Plinth module to manage users Plinth module to manage users
""" """
from django.db.models.signals import post_delete
from django.contrib.auth.models import User
from gettext import gettext as _ from gettext import gettext as _
from plinth import cfg from plinth import cfg
from plinth import actions
__all__ = ['init'] __all__ = ['init']
@ -36,14 +33,3 @@ def init():
menu = cfg.main_menu.get('system:index') menu = cfg.main_menu.get('system:index')
menu.add_urlname(_('Users and Groups'), 'glyphicon-user', 'users:index', menu.add_urlname(_('Users and Groups'), 'glyphicon-user', 'users:index',
15) 15)
post_delete.connect(delete_posix_user)
def delete_posix_user(sender, instance=None, **kwargs):
try:
instance
except User.DoesNotExist:
pass
else:
actions.superuser_run('delete-user', [instance.username])

View File

@ -16,29 +16,42 @@
# #
from django import forms from django import forms
from django.contrib import messages
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.contrib.auth.forms import UserCreationForm, SetPasswordForm from django.contrib.auth.forms import UserCreationForm, SetPasswordForm
from gettext import gettext as _ from gettext import gettext as _
from plinth import actions from plinth import actions
from plinth.errors import ActionError
class CreateUserForm(UserCreationForm): class CreateUserForm(UserCreationForm):
"""Custom user create form with option to also create POSIX user.""" """Custom user create form with option to also create POSIX user."""
add_posix_user = forms.BooleanField( add_posix_user = forms.BooleanField(
label=_('Also create POSIX user'), label=_('Also create a POSIX system user'),
required=False, required=False,
help_text=_('This will allow the new user to log in to the system ' help_text=_('This will allow the new user to log in to the system '
'through SSH. The new user will also have administrative ' 'through SSH. The new user will also have administrative '
'privileges (sudo).')) 'privileges (sudo).'))
def __init__(self, request, *args, **kwargs):
"""Initialize the form with extra request argument."""
self.request = request
super(CreateUserForm, self).__init__(*args, **kwargs)
def save(self, commit=True): def save(self, commit=True):
"""Save the user model and create POSIX user if required."""
user = super(CreateUserForm, self).save(commit) user = super(CreateUserForm, self).save(commit)
if commit and self.cleaned_data['add_posix_user']: if commit and self.cleaned_data['add_posix_user']:
actions.superuser_run( try:
'create-user', actions.superuser_run(
[user.username, self.cleaned_data['password1']]) 'create-user',
[user.get_username(), self.cleaned_data['password1']])
except ActionError:
messages.error(self.request,
_('Creating POSIX system user failed.'))
return user return user
@ -46,29 +59,57 @@ class UserUpdateForm(forms.ModelForm):
"""When user is enabled/disabled, also enables/disables the POSIX user.""" """When user is enabled/disabled, also enables/disables the POSIX user."""
class Meta: class Meta:
"""Metadata to control automatic form building."""
fields = ('username', 'groups', 'is_active') fields = ('username', 'groups', 'is_active')
model = User model = User
widgets = { widgets = {
'groups': forms.widgets.CheckboxSelectMultiple(), 'groups': forms.widgets.CheckboxSelectMultiple(),
} }
def __init__(self, request, username, *args, **kwargs):
"""Initialize the form with extra request argument."""
self.request = request
self.username = username
super(UserUpdateForm, self).__init__(*args, **kwargs)
def save(self, commit=True): def save(self, commit=True):
"""Enable/disable POSIX user after saving user model."""
user = super(UserUpdateForm, self).save(commit) user = super(UserUpdateForm, self).save(commit)
if commit: if commit:
if user.is_active: try:
actions.superuser_run('enable-user', [user.username]) if user.is_active:
else: actions.superuser_run('enable-user', [user.get_username()])
actions.superuser_run('disable-user', [user.username]) else:
actions.superuser_run('disable-user',
[user.get_username()])
except ActionError:
messages.error(
self.request,
_('Setting active status for POSIX system user failed.'))
return user return user
class UserChangePasswordForm(SetPasswordForm): class UserChangePasswordForm(SetPasswordForm):
"""Custom form that also updates password for POSIX users.""" """Custom form that also updates password for POSIX users."""
def __init__(self, request, *args, **kwargs):
"""Initialize the form with extra request argument."""
self.request = request
super(UserChangePasswordForm, self).__init__(*args, **kwargs)
def save(self, commit=True): def save(self, commit=True):
"""Save the user model and change POSIX password as well."""
user = super(UserChangePasswordForm, self).save(commit) user = super(UserChangePasswordForm, self).save(commit)
if commit: if commit:
actions.superuser_run( try:
'change-user-password', actions.superuser_run(
[user.username, self.cleaned_data['new_password1']]) 'change-user-password',
[user.get_username(), self.cleaned_data['new_password1']])
except ActionError:
messages.error(
self.request,
_('Changing POSIX system user password failed.'))
return user return user

View File

@ -25,8 +25,9 @@ from django.views.generic.edit import (CreateView, DeleteView, UpdateView,
from django.views.generic import ListView from django.views.generic import ListView
from gettext import gettext as _ from gettext import gettext as _
from .forms import CreateUserForm, UserUpdateForm, UserChangePasswordForm from .forms import CreateUserForm, UserChangePasswordForm, UserUpdateForm
from plinth import actions from plinth import actions
from plinth.errors import ActionError
subsubmenu = [{'url': reverse_lazy('users:index'), subsubmenu = [{'url': reverse_lazy('users:index'),
@ -54,6 +55,12 @@ class UserCreate(ContextMixin, SuccessMessageMixin, CreateView):
success_url = reverse_lazy('users:create') success_url = reverse_lazy('users:create')
title = _('Create User') title = _('Create User')
def get_form_kwargs(self):
"""Make the request object available to the form."""
kwargs = super(UserCreate, self).get_form_kwargs()
kwargs['request'] = self.request
return kwargs
class UserList(ContextMixin, ListView): class UserList(ContextMixin, ListView):
"""View to list users.""" """View to list users."""
@ -71,7 +78,15 @@ class UserUpdate(ContextMixin, SuccessMessageMixin, UpdateView):
success_message = _('User %(username)s updated.') success_message = _('User %(username)s updated.')
title = _('Edit User') title = _('Edit User')
def get_form_kwargs(self):
"""Make the requst object available to the form."""
kwargs = super(UserUpdate, self).get_form_kwargs()
kwargs['request'] = self.request
kwargs['username'] = self.object.username
return kwargs
def get_context_data(self, **kwargs): def get_context_data(self, **kwargs):
"""Return the data to be used for rendering templates."""
context = super(UserUpdate, self).get_context_data(**kwargs) context = super(UserUpdate, self).get_context_data(**kwargs)
output = actions.run('check-user-exists', [self.object.username]) output = actions.run('check-user-exists', [self.object.username])
context['is_posix_user'] = 'User exists' in output context['is_posix_user'] = 'User exists' in output
@ -107,9 +122,17 @@ class UserDelete(ContextMixin, DeleteView):
The SuccessMessageMixin doesn't work with the DeleteView on Django1.7, The SuccessMessageMixin doesn't work with the DeleteView on Django1.7,
so set the success message manually here. so set the success message manually here.
""" """
message = _('User %s deleted.') % self.kwargs['slug']
output = super(UserDelete, self).delete(*args, **kwargs) output = super(UserDelete, self).delete(*args, **kwargs)
message = _('User %s deleted.') % self.kwargs['slug']
messages.success(self.request, message) messages.success(self.request, message)
try:
actions.superuser_run('delete-user', [self.kwargs['slug']])
except ActionError:
messages.error(self.request,
_('Deleting POSIX system user failed.'))
return output return output
@ -121,8 +144,9 @@ class UserChangePassword(ContextMixin, SuccessMessageMixin, FormView):
success_message = _('Password changed successfully.') success_message = _('Password changed successfully.')
def get_form_kwargs(self): def get_form_kwargs(self):
"""Make the user object available to the form""" """Make the user object available to the form."""
kwargs = super(UserChangePassword, self).get_form_kwargs() kwargs = super(UserChangePassword, self).get_form_kwargs()
kwargs['request'] = self.request
kwargs['user'] = User.objects.get(username=self.kwargs['slug']) kwargs['user'] = User.objects.get(username=self.kwargs['slug'])
return kwargs return kwargs
@ -134,9 +158,17 @@ class UserChangePassword(ContextMixin, SuccessMessageMixin, FormView):
return context return context
def get_success_url(self): def get_success_url(self):
"""Return the URL to go to on successful sumbission."""
return reverse('users:edit', kwargs={'slug': self.kwargs['slug']}) return reverse('users:edit', kwargs={'slug': self.kwargs['slug']})
def form_valid(self, form): def form_valid(self, form):
"""Save the form if the submission is valid.
Django user session authentication hashes are based on password to have
the ability to logout all sessions on password change. Update the
session authentications to ensure that the current sessions is not
logged out.
"""
form.save() form.save()
update_session_auth_hash(self.request, form.user) update_session_auth_hash(self.request, form.user)
return super(UserChangePassword, self).form_valid(form) return super(UserChangePassword, self).form_valid(form)