core: make is_superuser a group property, remove from user
This commit is contained in:
parent
0325847c22
commit
0a5e14a352
|
@ -12,7 +12,7 @@ class UserForm(forms.ModelForm):
|
|||
class Meta:
|
||||
|
||||
model = User
|
||||
fields = ["username", "name", "email", "is_staff", "is_active", "attributes"]
|
||||
fields = ["username", "name", "email", "is_active", "attributes"]
|
||||
widgets = {
|
||||
"name": forms.TextInput,
|
||||
"attributes": CodeMirrorWidget,
|
||||
|
|
|
@ -50,7 +50,7 @@
|
|||
</td>
|
||||
<td role="cell">
|
||||
<span>
|
||||
{{ group.user_set.all|length }}
|
||||
{{ group.users.all|length }}
|
||||
</span>
|
||||
</td>
|
||||
<td>
|
||||
|
|
|
@ -8,7 +8,7 @@ from django.test import Client, TestCase
|
|||
from django.urls.exceptions import NoReverseMatch
|
||||
|
||||
from passbook.admin.urls import urlpatterns
|
||||
from passbook.core.models import User
|
||||
from passbook.core.models import Group, User
|
||||
from passbook.lib.utils.reflection import get_apps
|
||||
|
||||
|
||||
|
@ -16,7 +16,9 @@ class TestAdmin(TestCase):
|
|||
"""Generic admin tests"""
|
||||
|
||||
def setUp(self):
|
||||
self.user = User.objects.create_superuser(username="test")
|
||||
self.user = User.objects.create_user(username="test")
|
||||
self.user.pb_groups.add(Group.objects.filter(is_superuser=True).first())
|
||||
self.user.save()
|
||||
self.client = Client()
|
||||
self.client.force_login(self.user)
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@ class GroupSerializer(ModelSerializer):
|
|||
class Meta:
|
||||
|
||||
model = Group
|
||||
fields = ["pk", "name", "parent", "user_set", "attributes"]
|
||||
fields = ["pk", "name", "is_superuser", "parent", "users", "attributes"]
|
||||
|
||||
|
||||
class GroupViewSet(ModelViewSet):
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
"""User API Views"""
|
||||
from rest_framework.serializers import ModelSerializer
|
||||
from rest_framework.serializers import BooleanField, ModelSerializer
|
||||
from rest_framework.viewsets import ModelViewSet
|
||||
|
||||
from passbook.core.models import User
|
||||
|
@ -8,10 +8,12 @@ from passbook.core.models import User
|
|||
class UserSerializer(ModelSerializer):
|
||||
"""User Serializer"""
|
||||
|
||||
is_superuser = BooleanField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
|
||||
model = User
|
||||
fields = ["pk", "username", "name", "email"]
|
||||
fields = ["pk", "username", "name", "is_superuser", "email"]
|
||||
|
||||
|
||||
class UserViewSet(ModelViewSet):
|
||||
|
|
|
@ -18,21 +18,19 @@ class GroupForm(forms.ModelForm):
|
|||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.instance.pk:
|
||||
self.initial["members"] = self.instance.user_set.values_list(
|
||||
"pk", flat=True
|
||||
)
|
||||
self.initial["members"] = self.instance.users.values_list("pk", flat=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
instance = super().save(*args, **kwargs)
|
||||
if instance.pk:
|
||||
instance.user_set.clear()
|
||||
instance.user_set.add(*self.cleaned_data["members"])
|
||||
instance.users.clear()
|
||||
instance.users.add(*self.cleaned_data["members"])
|
||||
return instance
|
||||
|
||||
class Meta:
|
||||
|
||||
model = Group
|
||||
fields = ["name", "parent", "members", "attributes"]
|
||||
fields = ["name", "is_superuser", "parent", "members", "attributes"]
|
||||
widgets = {
|
||||
"name": forms.TextInput(),
|
||||
"attributes": CodeMirrorWidget,
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
# Generated by Django 3.0.6 on 2020-05-23 16:40
|
||||
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
|
||||
|
@ -15,8 +15,6 @@ def create_default_user(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
|||
username="pbadmin", email="root@localhost", name="passbook Default Admin"
|
||||
)
|
||||
pbadmin.set_password("pbadmin") # noqa # nosec
|
||||
pbadmin.is_superuser = True
|
||||
pbadmin.is_staff = True
|
||||
pbadmin.save()
|
||||
|
||||
|
||||
|
@ -27,5 +25,15 @@ class Migration(migrations.Migration):
|
|||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(model_name="user", name="is_superuser",),
|
||||
migrations.RemoveField(model_name="user", name="is_staff",),
|
||||
migrations.RunPython(create_default_user),
|
||||
migrations.AddField(
|
||||
model_name="user",
|
||||
name="is_superuser",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="user", name="is_staff", field=models.BooleanField(default=False)
|
||||
),
|
||||
]
|
||||
|
|
44
passbook/core/migrations/0009_group_is_superuser.py
Normal file
44
passbook/core/migrations/0009_group_is_superuser.py
Normal file
|
@ -0,0 +1,44 @@
|
|||
# Generated by Django 3.1.1 on 2020-09-15 19:53
|
||||
from django.apps.registry import Apps
|
||||
from django.db import migrations, models
|
||||
from django.db.backends.base.schema import BaseDatabaseSchemaEditor
|
||||
|
||||
|
||||
def create_default_admin_group(apps: Apps, schema_editor: BaseDatabaseSchemaEditor):
|
||||
db_alias = schema_editor.connection.alias
|
||||
Group = apps.get_model("passbook_core", "Group")
|
||||
User = apps.get_model("passbook_core", "User")
|
||||
|
||||
# Creates a default admin group
|
||||
group, _ = Group.objects.using(db_alias).get_or_create(
|
||||
is_superuser=True, defaults={"name": "passbook Admins",}
|
||||
)
|
||||
group.users.add(User.objects.get(username="pbadmin"))
|
||||
group.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("passbook_core", "0008_auto_20200824_1532"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(model_name="user", name="is_superuser",),
|
||||
migrations.RemoveField(model_name="user", name="is_staff",),
|
||||
migrations.AlterField(
|
||||
model_name="user",
|
||||
name="pb_groups",
|
||||
field=models.ManyToManyField(
|
||||
related_name="users", to="passbook_core.Group"
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="group",
|
||||
name="is_superuser",
|
||||
field=models.BooleanField(
|
||||
default=False, help_text="Users added to this group will be superusers."
|
||||
),
|
||||
),
|
||||
migrations.RunPython(create_default_admin_group),
|
||||
]
|
|
@ -4,6 +4,7 @@ from typing import Any, Optional, Type
|
|||
from uuid import uuid4
|
||||
|
||||
from django.contrib.auth.models import AbstractUser
|
||||
from django.contrib.auth.models import UserManager as DjangoUserManager
|
||||
from django.db import models
|
||||
from django.db.models import Q, QuerySet
|
||||
from django.forms import ModelForm
|
||||
|
@ -34,7 +35,12 @@ class Group(models.Model):
|
|||
"""Custom Group model which supports a basic hierarchy"""
|
||||
|
||||
group_uuid = models.UUIDField(primary_key=True, editable=False, default=uuid4)
|
||||
|
||||
name = models.CharField(_("name"), max_length=80)
|
||||
is_superuser = models.BooleanField(
|
||||
default=False, help_text=_("Users added to this group will be superusers.")
|
||||
)
|
||||
|
||||
parent = models.ForeignKey(
|
||||
"Group",
|
||||
blank=True,
|
||||
|
@ -52,6 +58,14 @@ class Group(models.Model):
|
|||
unique_together = (("name", "parent",),)
|
||||
|
||||
|
||||
class UserManager(DjangoUserManager):
|
||||
"""Custom user manager that doesn't assign is_superuser and is_staff"""
|
||||
|
||||
def create_user(self, username, email=None, password=None, **extra_fields):
|
||||
"""Custom user manager that doesn't assign is_superuser and is_staff"""
|
||||
return self._create_user(username, email, password, **extra_fields)
|
||||
|
||||
|
||||
class User(GuardianUserMixin, AbstractUser):
|
||||
"""Custom User model to allow easier adding o f user-based settings"""
|
||||
|
||||
|
@ -59,11 +73,23 @@ class User(GuardianUserMixin, AbstractUser):
|
|||
name = models.TextField(help_text=_("User's display name."))
|
||||
|
||||
sources = models.ManyToManyField("Source", through="UserSourceConnection")
|
||||
pb_groups = models.ManyToManyField("Group")
|
||||
pb_groups = models.ManyToManyField("Group", related_name="users")
|
||||
password_change_date = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
attributes = models.JSONField(default=dict, blank=True)
|
||||
|
||||
objects = UserManager()
|
||||
|
||||
@property
|
||||
def is_superuser(self) -> bool:
|
||||
"""Get supseruser status based on membership in a group with superuser status"""
|
||||
return self.pb_groups.filter(is_superuser=True).exists()
|
||||
|
||||
@property
|
||||
def is_staff(self) -> bool:
|
||||
"""superuser == staff user"""
|
||||
return self.is_superuser
|
||||
|
||||
def set_password(self, password):
|
||||
if self.pk:
|
||||
password_changed.send(sender=self, user=self, password=password)
|
||||
|
|
|
@ -13,7 +13,7 @@ class TestOverviewViews(TestCase):
|
|||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_superuser(
|
||||
self.user = User.objects.create_user(
|
||||
username="unittest user",
|
||||
email="unittest@example.com",
|
||||
password="".join(
|
||||
|
|
|
@ -13,7 +13,7 @@ class TestUserViews(TestCase):
|
|||
|
||||
def setUp(self):
|
||||
super().setUp()
|
||||
self.user = User.objects.create_superuser(
|
||||
self.user = User.objects.create_user(
|
||||
username="unittest user",
|
||||
email="unittest@example.com",
|
||||
password="".join(
|
||||
|
|
|
@ -30,7 +30,7 @@ class GroupMembershipPolicy(Policy):
|
|||
return GroupMembershipPolicyForm
|
||||
|
||||
def passes(self, request: PolicyRequest) -> PolicyResult:
|
||||
return PolicyResult(self.group.user_set.filter(pk=request.user.pk).exists())
|
||||
return PolicyResult(self.group.users.filter(pk=request.user.pk).exists())
|
||||
|
||||
class Meta:
|
||||
|
||||
|
|
|
@ -24,7 +24,7 @@ class TestGroupMembershipPolicy(TestCase):
|
|||
def test_valid(self):
|
||||
"""user in group"""
|
||||
group = Group.objects.create(name="test")
|
||||
group.user_set.add(get_anonymous_user())
|
||||
group.users.add(get_anonymous_user())
|
||||
group.save()
|
||||
policy: GroupMembershipPolicy = GroupMembershipPolicy.objects.create(
|
||||
group=group
|
||||
|
|
|
@ -151,7 +151,7 @@ class Connector:
|
|||
group_cache[group_dn] = groups.first()
|
||||
group = group_cache[group_dn]
|
||||
users = User.objects.filter(attributes__ldap_uniq=uniq)
|
||||
group.user_set.add(*list(users))
|
||||
group.users.add(*list(users))
|
||||
# Now that all users are added, lets write everything
|
||||
for _, group in group_cache.items():
|
||||
group.save()
|
||||
|
|
12
swagger.yaml
12
swagger.yaml
|
@ -5922,7 +5922,7 @@ definitions:
|
|||
required:
|
||||
- name
|
||||
- parent
|
||||
- user_set
|
||||
- users
|
||||
type: object
|
||||
properties:
|
||||
pk:
|
||||
|
@ -5935,11 +5935,15 @@ definitions:
|
|||
type: string
|
||||
maxLength: 80
|
||||
minLength: 1
|
||||
is_superuser:
|
||||
title: Is superuser
|
||||
description: Users added to this group will be superusers.
|
||||
type: boolean
|
||||
parent:
|
||||
title: Parent
|
||||
type: string
|
||||
format: uuid
|
||||
user_set:
|
||||
users:
|
||||
type: array
|
||||
items:
|
||||
type: integer
|
||||
|
@ -5970,6 +5974,10 @@ definitions:
|
|||
description: User's display name.
|
||||
type: string
|
||||
minLength: 1
|
||||
is_superuser:
|
||||
title: Is superuser
|
||||
type: boolean
|
||||
readOnly: true
|
||||
email:
|
||||
title: Email address
|
||||
type: string
|
||||
|
|
Reference in a new issue