mirror of
https://github.com/freedombox/FreedomBox.git
synced 2026-05-27 10:44:33 +00:00
users: Refactor valid user name checking for reuse
- Supress output from getent - More accurate message
This commit is contained in:
parent
c8c6bc377b
commit
e719966c4b
@ -35,31 +35,18 @@ from plinth import cfg
|
|||||||
from plinth.errors import ActionError, DomainRegistrationError
|
from plinth.errors import ActionError, DomainRegistrationError
|
||||||
from plinth.modules.pagekite.utils import PREDEFINED_SERVICES, run
|
from plinth.modules.pagekite.utils import PREDEFINED_SERVICES, run
|
||||||
from plinth.modules.security import set_restricted_access
|
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
|
from plinth.utils import format_lazy
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class State1Form(auth.forms.UserCreationForm):
|
class State1Form(ValidNewUsernameCheckMixin, auth.forms.UserCreationForm):
|
||||||
"""Firstboot state 1: create a new user."""
|
"""Firstboot state 1: create a new user."""
|
||||||
def __init__(self, *args, **kwargs):
|
def __init__(self, *args, **kwargs):
|
||||||
self.request = kwargs.pop('request')
|
self.request = kwargs.pop('request')
|
||||||
super().__init__(*args, **kwargs)
|
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):
|
def save(self, commit=True):
|
||||||
"""Create and log the user in."""
|
"""Create and log the user in."""
|
||||||
user = super().save(commit=commit)
|
user = super().save(commit=commit)
|
||||||
|
|||||||
@ -28,7 +28,7 @@ from plinth import actions
|
|||||||
from plinth.errors import ActionError
|
from plinth.errors import ActionError
|
||||||
|
|
||||||
# Usernames used by optional services (that might not be installed yet).
|
# Usernames used by optional services (that might not be installed yet).
|
||||||
RESTRICTED_USERNAMES = [
|
RESERVED_USERNAMES = [
|
||||||
'debian-deluged',
|
'debian-deluged',
|
||||||
'Debian-minetest',
|
'Debian-minetest',
|
||||||
'debian-tor',
|
'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.
|
"""Custom user create form.
|
||||||
|
|
||||||
Include options to add user to groups.
|
Include options to add user to groups.
|
||||||
@ -75,19 +101,6 @@ class CreateUserForm(UserCreationForm):
|
|||||||
self.request = request
|
self.request = request
|
||||||
super(CreateUserForm, self).__init__(*args, **kwargs)
|
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):
|
def save(self, commit=True):
|
||||||
"""Save the user model and create LDAP user if required."""
|
"""Save the user model and create LDAP user if required."""
|
||||||
user = super(CreateUserForm, self).save(commit)
|
user = super(CreateUserForm, self).save(commit)
|
||||||
@ -119,7 +132,7 @@ class CreateUserForm(UserCreationForm):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
|
|
||||||
class UserUpdateForm(forms.ModelForm):
|
class UserUpdateForm(ValidNewUsernameCheckMixin, forms.ModelForm):
|
||||||
"""When user info is changed, also updates LDAP user."""
|
"""When user info is changed, also updates LDAP user."""
|
||||||
ssh_keys = forms.CharField(
|
ssh_keys = forms.CharField(
|
||||||
label=ugettext_lazy('SSH Keys'),
|
label=ugettext_lazy('SSH Keys'),
|
||||||
@ -149,19 +162,6 @@ class UserUpdateForm(forms.ModelForm):
|
|||||||
self.username = username
|
self.username = username
|
||||||
super(UserUpdateForm, self).__init__(*args, **kwargs)
|
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):
|
def save(self, commit=True):
|
||||||
"""Update LDAP user name and groups after saving user model."""
|
"""Update LDAP user name and groups after saving user model."""
|
||||||
user = super(UserUpdateForm, self).save(commit)
|
user = super(UserUpdateForm, self).save(commit)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user