users: Refactor valid user name checking for reuse

- Supress output from getent

- More accurate message
This commit is contained in:
Sunil Mohan Adapa 2016-08-12 18:47:16 +05:30
parent c8c6bc377b
commit e719966c4b
No known key found for this signature in database
GPG Key ID: 36C361440C9BC971
2 changed files with 31 additions and 44 deletions

View File

@ -35,31 +35,18 @@ from plinth import cfg
from plinth.errors import ActionError, DomainRegistrationError
from plinth.modules.pagekite.utils import PREDEFINED_SERVICES, run
from plinth.modules.security import set_restricted_access
from plinth.modules.users.forms import GROUP_CHOICES, RESTRICTED_USERNAMES
from plinth.modules.users.forms import GROUP_CHOICES, ValidNewUsernameCheckMixin
from plinth.utils import format_lazy
logger = logging.getLogger(__name__)
class State1Form(auth.forms.UserCreationForm):
class State1Form(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm):
"""Firstboot state 1: create a new user."""
def __init__(self, *args, **kwargs):
self.request = kwargs.pop('request')
super().__init__(*args, **kwargs)
def clean(self):
"""Check for username collisions with system users."""
username = self.cleaned_data['username']
try:
subprocess.run(['getent', 'passwd', username], check=True)
# Exit code 0 means that the username is already in use.
raise ValidationError(_('Username is reserved'))
except subprocess.CalledProcessError:
if username in RESTRICTED_USERNAMES:
raise ValidationError(_('Username is reserved'))
return super().clean()
def save(self, commit=True):
"""Create and log the user in."""
user = super().save(commit=commit)

View File

@ -28,7 +28,7 @@ from plinth import actions
from plinth.errors import ActionError
# Usernames used by optional services (that might not be installed yet).
RESTRICTED_USERNAMES = [
RESERVED_USERNAMES = [
'debian-deluged',
'Debian-minetest',
'debian-tor',
@ -50,7 +50,33 @@ GROUP_CHOICES = (
)
class CreateUserForm(UserCreationForm):
class ValidNewUsernameCheckMixin(object):
"""Mixin to check if a username is valid for created new user."""
def clean(self):
"""Check for username collisions with system users."""
if not self.is_valid_new_username():
raise ValidationError(_('Username is taken or is reserved'))
return super().clean()
def is_valid_new_username(self):
"""Check for username collisions with system users."""
username = self.cleaned_data['username']
try:
subprocess.run(['getent', 'passwd', username],
stdout=subprocess.DEVNULL, check=True)
# Exit code 0 means that the username is already in use.
return False
except subprocess.CalledProcessError:
pass
if username in RESERVED_USERNAMES:
return False
return True
class CreateUserForm(ValidNewUsernameCheckMixin, UserCreationForm):
"""Custom user create form.
Include options to add user to groups.
@ -75,19 +101,6 @@ class CreateUserForm(UserCreationForm):
self.request = request
super(CreateUserForm, self).__init__(*args, **kwargs)
def clean(self):
"""Check for username collisions with system users."""
username = self.cleaned_data['username']
try:
subprocess.run(['getent', 'passwd', username], check=True)
# Exit code 0 means that the username is already in use.
raise ValidationError(_('Username is reserved'))
except subprocess.CalledProcessError:
if username in RESTRICTED_USERNAMES:
raise ValidationError(_('Username is reserved'))
return super().clean()
def save(self, commit=True):
"""Save the user model and create LDAP user if required."""
user = super(CreateUserForm, self).save(commit)
@ -119,7 +132,7 @@ class CreateUserForm(UserCreationForm):
return user
class UserUpdateForm(forms.ModelForm):
class UserUpdateForm(ValidNewUsernameCheckMixin, forms.ModelForm):
"""When user info is changed, also updates LDAP user."""
ssh_keys = forms.CharField(
label=ugettext_lazy('SSH Keys'),
@ -149,19 +162,6 @@ class UserUpdateForm(forms.ModelForm):
self.username = username
super(UserUpdateForm, self).__init__(*args, **kwargs)
def clean(self):
"""Check for username collisions with system users."""
username = self.cleaned_data['username']
try:
subprocess.run(['getent', 'passwd', username], check=True)
# Exit code 0 means that the username is already in use.
raise ValidationError(_('Username is reserved'))
except subprocess.CalledProcessError:
if username in RESTRICTED_USERNAMES:
raise ValidationError(_('Username is reserved'))
return super().clean()
def save(self, commit=True):
"""Update LDAP user name and groups after saving user model."""
user = super(UserUpdateForm, self).save(commit)