From 129380e119c0c895eb148149aa7b3df3b2db9f29 Mon Sep 17 00:00:00 2001 From: Michael DeHaan Date: Sun, 24 Mar 2013 13:31:46 -0400 Subject: [PATCH] A post hook that allows user creation with passwords being set appropriately, and associated tests. --- lib/main/tests/base.py | 4 +++ lib/main/tests/organizations.py | 2 +- lib/main/tests/users.py | 53 +++++++++++++++++++++++++-------- lib/main/views.py | 21 ++++++++----- 4 files changed, 59 insertions(+), 21 deletions(-) diff --git a/lib/main/tests/base.py b/lib/main/tests/base.py index 0bd988c81e..cd1b894d71 100644 --- a/lib/main/tests/base.py +++ b/lib/main/tests/base.py @@ -16,6 +16,10 @@ from lib.main.models import * class BaseTest(django.test.TestCase): + def setUp(self): + super(BaseTest, self).setUp() + self.object_ctr = 0 + def make_user(self, username, password, super_user=False): django_user = None if super_user: diff --git a/lib/main/tests/organizations.py b/lib/main/tests/organizations.py index faa5758468..586f469c8b 100644 --- a/lib/main/tests/organizations.py +++ b/lib/main/tests/organizations.py @@ -20,7 +20,7 @@ class OrganizationsTest(BaseTest): return '/api/v1/organizations/' def setUp(self): - self.object_ctr = 0 + super(OrganizationsTest, self).setUp() self.setup_users() self.organizations = self.make_organizations(self.super_django_user, 10) diff --git a/lib/main/tests/users.py b/lib/main/tests/users.py index b275512641..05c8d80bb0 100644 --- a/lib/main/tests/users.py +++ b/lib/main/tests/users.py @@ -20,17 +20,23 @@ class UsersTest(BaseTest): return '/api/v1/users/' def setUp(self): + super(UsersTest, self).setUp() self.setup_users() + self.organizations = self.make_organizations(self.super_django_user, 1) + self.organizations[0].admins.add(self.normal_django_user) + self.organizations[0].users.add(self.other_django_user) - def test_only_super_user_can_add_users(self): + def test_only_super_user_or_org_admin_can_add_users(self): url = '/api/v1/users/' new_user = dict(username='blippy') + new_user2 = dict(username='blippy2') self.post(url, expect=401, data=new_user, auth=None) self.post(url, expect=401, data=new_user, auth=self.get_invalid_credentials()) - self.post(url, expect=403, data=new_user, auth=self.get_normal_credentials()) self.post(url, expect=403, data=new_user, auth=self.get_other_credentials()) self.post(url, expect=201, data=new_user, auth=self.get_super_credentials()) self.post(url, expect=400, data=new_user, auth=self.get_super_credentials()) + self.post(url, expect=201, data=new_user2, auth=self.get_normal_credentials()) + self.post(url, expect=400, data=new_user2, auth=self.get_normal_credentials()) def test_ordinary_user_can_modify_some_fields_about_himself_but_not_all_and_passwords_work(self): @@ -74,19 +80,40 @@ class UsersTest(BaseTest): self.assertTrue(User.objects.get(pk=self.normal_django_user.pk).password != data['password']) def test_user_created_with_password_can_login(self): - pass - def test_normal_user_cannot_modify_another_user(self): - #self.assertTrue(False) - pass + # this is something an org admin can do... + url = '/api/v1/users/' + data = dict(username='username', password='password') + data2 = dict(username='username2', password='password2') + data = self.post(url, expect=201, data=data, auth=self.get_normal_credentials()) - def test_superuser_can_modify_anything_about_anyone(self): - #self.assertTrue(False) - pass + # verify that the login works... + self.get(url, expect=200, auth=('username', 'password')) - def test_password_not_shown_in_get_operations(self): - #self.assertTrue(False) - pass + # but a regular user cannot + data = self.post(url, expect=403, data=data2, auth=self.get_other_credentials()) + + # a super user can also create new users + data = self.post(url, expect=201, data=data2, auth=self.get_super_credentials()) + + # verify that the login works + self.get(url, expect=200, auth=('username2', 'password2')) + + # verify that if you post a user with a pk, you do not alter that user's password info + mod = dict(id=1, username='change', password='change') + data = self.post(url, expect=201, data=mod, auth=self.get_super_credentials()) + orig = User.objects.get(pk=1) + self.assertTrue(orig.username != 'change') + + + def test_password_not_shown_in_get_operations_for_list_or_detail(self): + url = '/api/v1/users/1/' + data = self.get(url, expect=200, auth=self.get_super_credentials()) + self.assertTrue('password' not in data) + + url = '/api/v1/users/' + data = self.get(url, expect=200, auth=self.get_super_credentials()) + self.assertTrue('password' not in data['results'][0]) def test_user_list_filtered(self): # I can see a user if I'm on a team with them, am their org admin, am a superuser, or am them @@ -97,7 +124,7 @@ class UsersTest(BaseTest): #self.assertTrue(False) pass - def test_non_super_user_cannot_delete_any_user_including_himself(self): + def test_non_org_admin_user_cannot_delete_any_user_including_himself(self): #self.assertTrue(False) pass diff --git a/lib/main/views.py b/lib/main/views.py index 37b27d745f..7067ae21f1 100644 --- a/lib/main/views.py +++ b/lib/main/views.py @@ -160,18 +160,25 @@ class UsersList(BaseList): serializer_class = UserSerializer permission_classes = (CustomRbac,) + def post(self, request, *args, **kwargs): + password = request.DATA.get('password', None) + result = super(UsersList, self).post(request, *args, **kwargs) + if password: + pk = result.data['id'] + user = User.objects.get(pk=pk) + user.set_password(password) + user.save() + return result + def _get_queryset(self): ''' I can see user records when I'm a superuser, I'm that user, I'm their org admin, or I'm on a team with that user ''' base = User.objects if self.request.user.is_superuser: return base.all() - return base.filter( - pk = [ self.request.user.pk ] - ).distinct() | base.filter( - organizations__in = [ self.request.user.admin_of_organizations.all() ] - ).distinct() | base.filter( - teams__in = [ self.request.user.teams.all() ] - ).distinct() + mine = base.filter(pk = self.request.user.pk).distinct() + admin_of = base.filter(organizations__in = self.request.user.admin_of_organizations.all()).distinct() + same_team = base.filter(teams__in = self.request.user.teams.all()).distinct() + return mine | admin_of | same_team class UsersDetail(BaseDetail):