Addressing 4.3 "Admin User Password Reset Permitted"

* switching to the keystone v3 api
* various fixes to tests after user_store changes
* minor pep8 cleanup

Change-Id: Ie40cfcae0e392aef9a3e92da4acd4f0a21a627b0
This commit is contained in:
adriant 2016-02-04 18:19:05 +13:00
parent 854c6f6322
commit 1e75d348f9
12 changed files with 281 additions and 139 deletions

View File

@ -51,7 +51,8 @@ KEYSTONE:
username: admin username: admin
password: openstack password: openstack
project_name: admin project_name: admin
auth_url: http://localhost:5000/v2.0 # MUST BE V3 API:
auth_url: http://localhost:5000/v3
DEFAULT_REGION: RegionOne DEFAULT_REGION: RegionOne
TOKEN_SUBMISSION_URL: http://192.168.122.160:8080/token/ TOKEN_SUBMISSION_URL: http://192.168.122.160:8080/token/
@ -174,11 +175,14 @@ TASK_SETTINGS:
ACTION_SETTINGS: ACTION_SETTINGS:
NewUser: NewUser:
allowed_roles: allowed_roles:
- Member
- project_owner - project_owner
- project_mod - project_mod
- heat_stack_owner - heat_stack_owner
- _member_ - _member_
ResetUser:
blacklisted_roles:
- Admin
- admin
DefaultProjectResources: DefaultProjectResources:
RegionOne: RegionOne:
network_name: somenetwork network_name: somenetwork

View File

@ -12,13 +12,16 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from logging import getLogger
from django.conf import settings
from django.db import models from django.db import models
from django.utils import timezone from django.utils import timezone
from stacktask.actions import user_store
from stacktask.actions import serializers
from django.conf import settings
from jsonfield import JSONField from jsonfield import JSONField
from logging import getLogger
from stacktask.actions import serializers
from stacktask.actions import user_store
class Action(models.Model): class Action(models.Model):
@ -475,8 +478,8 @@ class NewProject(UserNameAction):
def _submit(self, token_data): def _submit(self, token_data):
""" """
The submit action is prformed when a token is submitted. The submit action is prformed when a token is submitted.
This is done for a user account only, and so should now only set up the user, This is done for a user account only, and so should now only
not the project, which was done in approve. set up the user, not the project, which was done in approve.
""" """
id_manager = user_store.IdentityManager() id_manager = user_store.IdentityManager()
@ -552,13 +555,25 @@ class ResetUser(UserNameAction):
'email' 'email'
] ]
blacklist = settings.ACTION_SETTINGS.get(
'ResetUser', {}).get("blacklisted_roles", {})
def _validate(self): def _validate(self):
id_manager = user_store.IdentityManager() id_manager = user_store.IdentityManager()
user = id_manager.find_user(self.username) user = id_manager.find_user(self.username)
if user: if user:
if user.email == self.email: roles = id_manager.get_all_roles(user)
user_roles = []
for project, roles in roles.iteritems():
user_roles.extend(role.name for role in roles)
if set(self.blacklist) & set(user_roles):
valid = False
self.add_note('Cannot reset users with blacklisted roles.')
elif user.email == self.email:
valid = True valid = True
self.action.need_token = True self.action.need_token = True
self.set_token_fields(["password"]) self.set_token_fields(["password"])
@ -693,7 +708,6 @@ class EditUserRoles(UserIdAction):
if self.action.state == "default": if self.action.state == "default":
try: try:
#user = id_manager.find_user(self.username)
user = self._get_target_user() user = self._get_target_user()
roles = [] roles = []
@ -738,7 +752,8 @@ class EditUserRoles(UserIdAction):
% (self.user_id, self.roles, self.project_id)) % (self.user_id, self.roles, self.project_id))
# Update settings dict with tuples in the format: (<ActionClass>, <ActionSerializer>) # Update settings dict with tuples in the format:
# (<ActionClass>, <ActionSerializer>)
def register_action_class(action_class, serializer_class): def register_action_class(action_class, serializer_class):
data = {} data = {}
data[action_class.__name__] = (action_class, serializer_class) data[action_class.__name__] = (action_class, serializer_class)

View File

@ -12,19 +12,20 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from keystoneclient.v2_0 import client
from neutronclient.v2_0 import client as neutron_client
from django.conf import settings from django.conf import settings
from keystoneclient.v3 import client as client_v3
from neutronclient.v2_0 import client as neutron_client
def get_keystoneclient(): def get_keystoneclient():
# TODO(Adriant): Add region support. auth = client_v3.Client(
auth = client.Client(
username=settings.KEYSTONE['username'], username=settings.KEYSTONE['username'],
password=settings.KEYSTONE['password'], password=settings.KEYSTONE['password'],
tenant_name=settings.KEYSTONE['project_name'], project_name=settings.KEYSTONE['project_name'],
auth_url=settings.KEYSTONE['auth_url'], auth_url=settings.KEYSTONE['auth_url_v3'],
region_name=settings.DEFAULT_REGION region_name=settings.DEFAULT_REGION
) )
return auth return auth

View File

@ -13,13 +13,15 @@
# under the License. # under the License.
from django.test import TestCase from django.test import TestCase
from stacktask.api.models import Task
from stacktask.api.v1.tests import FakeManager, setup_temp_cache
from stacktask.api.v1 import tests
from stacktask.actions.tenant_setup.models import (
DefaultProjectResources, AddAdminToProject)
import mock import mock
from stacktask.actions.tenant_setup.models import (
AddAdminToProject, DefaultProjectResources)
from stacktask.api.models import Task
from stacktask.api.v1 import tests
from stacktask.api.v1.tests import FakeManager, setup_temp_cache
neutron_cache = {} neutron_cache = {}
@ -263,7 +265,7 @@ class TenantSetupActionTests(TestCase):
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
project = tests.temp_cache['projects']['test_project'] project = tests.temp_cache['projects']['test_project']
self.assertEquals(project.roles['admin'], ['admin']) self.assertEquals(project.roles['user_id_0'], ['admin'])
@mock.patch('stacktask.actions.tenant_setup.models.IdentityManager', @mock.patch('stacktask.actions.tenant_setup.models.IdentityManager',
FakeManager) FakeManager)
@ -292,10 +294,10 @@ class TenantSetupActionTests(TestCase):
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
project = tests.temp_cache['projects']['test_project'] project = tests.temp_cache['projects']['test_project']
self.assertEquals(project.roles['admin'], ['admin']) self.assertEquals(project.roles['user_id_0'], ['admin'])
action.post_approve() action.post_approve()
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
project = tests.temp_cache['projects']['test_project'] project = tests.temp_cache['projects']['test_project']
self.assertEquals(project.roles['admin'], ['admin']) self.assertEquals(project.roles['user_id_0'], ['admin'])

View File

@ -13,13 +13,15 @@
# under the License. # under the License.
from django.test import TestCase from django.test import TestCase
from stacktask.api.models import Task
from stacktask.api.v1.tests import FakeManager, setup_temp_cache
from stacktask.api.v1 import tests
from stacktask.actions.models import (
NewUser, NewProject, ResetUser, EditUserRoles)
import mock import mock
from stacktask.actions.models import (
EditUserRoles, NewProject, NewUser, ResetUser)
from stacktask.api.models import Task
from stacktask.api.v1 import tests
from stacktask.api.v1.tests import FakeManager, setup_temp_cache
class ActionTests(TestCase): class ActionTests(TestCase):
@ -60,14 +62,15 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(len(tests.temp_cache['users']), 2) self.assertEquals(len(tests.temp_cache['users']), 2)
# The new user id in this case will be "user_id_1"
self.assertEquals( self.assertEquals(
tests.temp_cache['users']['test@example.com'].email, tests.temp_cache['users']["user_id_1"].email,
'test@example.com') 'test@example.com')
self.assertEquals( self.assertEquals(
tests.temp_cache['users']['test@example.com'].password, tests.temp_cache['users']["user_id_1"].password,
'123456') '123456')
self.assertEquals(project.roles['test@example.com'], ['Member']) self.assertEquals(project.roles["user_id_1"], ['Member'])
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
FakeManager) FakeManager)
@ -82,10 +85,10 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
setup_temp_cache({'test_project': project}, {user.username: user}) setup_temp_cache({'test_project': project}, {user.id: user})
task = Task.objects.create( task = Task.objects.create(
ip_address="0.0.0.0", keystone_user={ ip_address="0.0.0.0", keystone_user={
@ -110,7 +113,7 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(project.roles[user.username], ['Member']) self.assertEquals(project.roles[user.id], ['Member'])
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
FakeManager) FakeManager)
@ -124,15 +127,15 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
project = mock.Mock() project = mock.Mock()
project.id = 'test_project_id' project.id = 'test_project_id'
project.name = 'test_project' project.name = 'test_project'
project.roles = {user.username: ['Member']} project.roles = {user.id: ['Member']}
setup_temp_cache({'test_project': project}, {user.username: user}) setup_temp_cache({'test_project': project}, {user.id: user})
task = Task.objects.create( task = Task.objects.create(
ip_address="0.0.0.0", keystone_user={ ip_address="0.0.0.0", keystone_user={
@ -158,7 +161,7 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(project.roles[user.username], ['Member']) self.assertEquals(project.roles[user.id], ['Member'])
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
FakeManager) FakeManager)
@ -192,8 +195,6 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, False) self.assertEquals(action.valid, False)
self.assertEquals('admin' in tests.temp_cache['users'], True)
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
FakeManager) FakeManager)
def test_new_project(self): def test_new_project(self):
@ -226,19 +227,18 @@ class ActionTests(TestCase):
self.assertEquals( self.assertEquals(
tests.temp_cache['projects']['test_project'].name, tests.temp_cache['projects']['test_project'].name,
'test_project') 'test_project')
self.assertEquals('admin' in tests.temp_cache['users'], True) self.assertEquals(task.cache, {'project_id': "project_id_1"})
self.assertEquals(task.cache, {'project_id': 2})
token_data = {'password': '123456'} token_data = {'password': '123456'}
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
print tests.temp_cache['users']
self.assertEquals( self.assertEquals(
tests.temp_cache['users']['test@example.com'].email, tests.temp_cache['users']["user_id_1"].email,
'test@example.com') 'test@example.com')
project = tests.temp_cache['projects']['test_project'] project = tests.temp_cache['projects']['test_project']
self.assertEquals( self.assertEquals(
sorted(project.roles['test@example.com']), sorted(project.roles["user_id_1"]),
sorted(['Member', '_member_', 'project_owner', sorted(['Member', '_member_', 'project_owner',
'project_mod', 'heat_stack_owner'])) 'project_mod', 'heat_stack_owner']))
@ -272,27 +272,25 @@ class ActionTests(TestCase):
self.assertEquals( self.assertEquals(
tests.temp_cache['projects']['test_project'].name, tests.temp_cache['projects']['test_project'].name,
'test_project') 'test_project')
self.assertEquals('admin' in tests.temp_cache['users'], True) self.assertEquals(task.cache, {'project_id': "project_id_1"})
self.assertEquals(task.cache, {'project_id': 2})
action.post_approve() action.post_approve()
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals( self.assertEquals(
tests.temp_cache['projects']['test_project'].name, tests.temp_cache['projects']['test_project'].name,
'test_project') 'test_project')
self.assertEquals('admin' in tests.temp_cache['users'], True) self.assertEquals(task.cache, {'project_id': "project_id_1"})
self.assertEquals(task.cache, {'project_id': 2})
token_data = {'password': '123456'} token_data = {'password': '123456'}
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals( self.assertEquals(
tests.temp_cache['users']['test@example.com'].email, tests.temp_cache['users']["user_id_1"].email,
'test@example.com') 'test@example.com')
project = tests.temp_cache['projects']['test_project'] project = tests.temp_cache['projects']['test_project']
self.assertEquals( self.assertEquals(
sorted(project.roles['test@example.com']), sorted(project.roles["user_id_1"]),
sorted(['Member', '_member_', 'project_owner', sorted(['Member', '_member_', 'project_owner',
'project_mod', 'heat_stack_owner'])) 'project_mod', 'heat_stack_owner']))
@ -305,10 +303,10 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
task = Task.objects.create( task = Task.objects.create(
ip_address="0.0.0.0", keystone_user={ ip_address="0.0.0.0", keystone_user={
@ -330,18 +328,18 @@ class ActionTests(TestCase):
self.assertEquals( self.assertEquals(
tests.temp_cache['projects']['test_project'].name, tests.temp_cache['projects']['test_project'].name,
'test_project') 'test_project')
self.assertEquals(task.cache, {'project_id': 2}) self.assertEquals(task.cache, {'project_id': "project_id_1"})
token_data = {'password': '123456'} token_data = {'password': '123456'}
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals( self.assertEquals(
tests.temp_cache['users']['test@example.com'].email, tests.temp_cache['users'][user.id].email,
'test@example.com') 'test@example.com')
project = tests.temp_cache['projects']['test_project'] project = tests.temp_cache['projects']['test_project']
self.assertEquals( self.assertEquals(
sorted(project.roles['test@example.com']), sorted(project.roles[user.id]),
sorted(['Member', '_member_', 'project_owner', sorted(['Member', '_member_', 'project_owner',
'project_mod', 'heat_stack_owner'])) 'project_mod', 'heat_stack_owner']))
@ -386,11 +384,11 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "gibberish" user.password = "gibberish"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
task = Task.objects.create( task = Task.objects.create(
ip_address="0.0.0.0", keystone_user={ ip_address="0.0.0.0", keystone_user={
@ -415,7 +413,7 @@ class ActionTests(TestCase):
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals( self.assertEquals(
tests.temp_cache['users']['test@example.com'].password, tests.temp_cache['users'][user.id].password,
'123456') '123456')
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
@ -462,7 +460,7 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
setup_temp_cache({'test_project': project}, {user.id: user}) setup_temp_cache({'test_project': project}, {user.id: user})
@ -491,8 +489,8 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(len(project.roles[user.username]), 2) self.assertEquals(len(project.roles[user.id]), 2)
self.assertEquals(set(project.roles[user.username]), self.assertEquals(set(project.roles[user.id]),
set(['Member', 'project_mod'])) set(['Member', 'project_mod']))
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
@ -503,13 +501,13 @@ class ActionTests(TestCase):
""" """
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
project = mock.Mock() project = mock.Mock()
project.id = 'test_project_id' project.id = 'test_project_id'
project.name = 'test_project' project.name = 'test_project'
project.roles = {user.username: ['Member', 'project_mod']} project.roles = {user.id: ['Member', 'project_mod']}
setup_temp_cache({'test_project': project}, {user.id: user}) setup_temp_cache({'test_project': project}, {user.id: user})
@ -538,8 +536,8 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(len(project.roles[user.username]), 2) self.assertEquals(len(project.roles[user.id]), 2)
self.assertEquals(set(project.roles[user.username]), self.assertEquals(set(project.roles[user.id]),
set(['Member', 'project_mod'])) set(['Member', 'project_mod']))
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
@ -551,13 +549,13 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
project = mock.Mock() project = mock.Mock()
project.id = 'test_project_id' project.id = 'test_project_id'
project.name = 'test_project' project.name = 'test_project'
project.roles = {user.username: ['Member', 'project_mod']} project.roles = {user.id: ['Member', 'project_mod']}
setup_temp_cache({'test_project': project}, {user.id: user}) setup_temp_cache({'test_project': project}, {user.id: user})
@ -585,7 +583,7 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(project.roles[user.username], ['Member']) self.assertEquals(project.roles[user.id], ['Member'])
@mock.patch('stacktask.actions.models.user_store.IdentityManager', @mock.patch('stacktask.actions.models.user_store.IdentityManager',
FakeManager) FakeManager)
@ -596,13 +594,13 @@ class ActionTests(TestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
project = mock.Mock() project = mock.Mock()
project.id = 'test_project_id' project.id = 'test_project_id'
project.name = 'test_project' project.name = 'test_project'
project.roles = {user.username: ['Member']} project.roles = {user.id: ['Member']}
setup_temp_cache({'test_project': project}, {user.id: user}) setup_temp_cache({'test_project': project}, {user.id: user})
@ -631,4 +629,4 @@ class ActionTests(TestCase):
action.submit(token_data) action.submit(token_data)
self.assertEquals(action.valid, True) self.assertEquals(action.valid, True)
self.assertEquals(project.roles[user.username], ['Member']) self.assertEquals(project.roles[user.id], ['Member'])

View File

@ -12,11 +12,15 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from openstack_clients import get_keystoneclient from collections import defaultdict
from django.conf import settings
from keystoneclient.openstack.common.apiclient import ( from keystoneclient.openstack.common.apiclient import (
exceptions as ks_exceptions exceptions as ks_exceptions
) )
from django.conf import settings
from openstack_clients import get_keystoneclient
def get_managable_roles(user_roles): def get_managable_roles(user_roles):
@ -58,14 +62,38 @@ class IdentityManager(object):
user = None user = None
return user return user
def list_users(self, project):
try:
roles = self.ks_client.roles.list()
role_dict = {role.id: role for role in roles}
users = {}
user_assignments = self.ks_client.role_assignments.list(
project=project)
for assignment in user_assignments:
try:
user = users.get(assignment.user['id'], None)
if user:
user.roles.append(role_dict[assignment.role['id']])
else:
user = self.ks_client.users.get(assignment.user['id'])
user.roles = [role_dict[assignment.role['id']], ]
users[user.id] = user
except AttributeError:
# Just means the assignment is a group, so ignore it.
pass
except ks_exceptions.NotFound:
users = []
return users.values()
def create_user(self, name, password, email, project_id): def create_user(self, name, password, email, project_id):
user = self.ks_client.users.create( user = self.ks_client.users.create(
name=name, password=password, name=name, password=password,
email=email, tenant_id=project_id) email=email, project_id=project_id)
return user return user
def update_user_password(self, user, password): def update_user_password(self, user, password):
self.ks_client.users.update_password(user, password) self.ks_client.users.update(user, password=password)
def find_role(self, name): def find_role(self, name):
try: try:
@ -75,33 +103,48 @@ class IdentityManager(object):
return role return role
def get_roles(self, user, project): def get_roles(self, user, project):
return self.ks_client.roles.roles_for_user(user, tenant=project) return self.ks_client.roles.list(user=user, project=project)
def get_all_roles(self, user):
"""
Returns roles for a given user across all projects.
"""
roles = self.ks_client.roles.list()
role_dict = {role.id: role for role in roles}
user_assignments = self.ks_client.role_assignments.list(user=user)
projects = defaultdict([])
for assignment in user_assignments:
project = assignment.scope['project']['id']
projects[project].append(role_dict[assignment.role['id']])
return projects
def add_user_role(self, user, role, project_id): def add_user_role(self, user, role, project_id):
try: try:
self.ks_client.roles.add_user_role(user, role, project_id) self.ks_client.roles.grant(role, user=user, project=project_id)
except ks_exceptions.Conflict: except ks_exceptions.Conflict:
# Conflict is ok, it means the user already has this role. # Conflict is ok, it means the user already has this role.
pass pass
def remove_user_role(self, user, role, project_id): def remove_user_role(self, user, role, project_id):
self.ks_client.roles.remove_user_role(user, role, project_id) self.ks_client.roles.revoke(role, user=user, project=project_id)
def find_project(self, project_name): def find_project(self, project_name):
try: try:
project = self.ks_client.tenants.find(name=project_name) project = self.ks_client.projects.find(name=project_name)
except ks_exceptions.NotFound: except ks_exceptions.NotFound:
project = None project = None
return project return project
def get_project(self, project_id): def get_project(self, project_id):
try: try:
project = self.ks_client.tenants.get(project_id) project = self.ks_client.projects.get(project_id)
except ks_exceptions.NotFound: except ks_exceptions.NotFound:
project = None project = None
return project return project
def create_project(self, project_name, created_on): def create_project(self, project_name, created_on):
project = self.ks_client.tenants.create(project_name, project = self.ks_client.projects.create(project_name,
created_on=created_on) created_on=created_on)
return project return project

View File

@ -12,14 +12,15 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
from django.utils import timezone
from django.conf import settings from django.conf import settings
from django.utils import timezone
from rest_framework.response import Response from rest_framework.response import Response
from stacktask.api.v1 import tasks
from stacktask.api import utils
from stacktask.api import models
from stacktask.actions import user_store from stacktask.actions import user_store
from stacktask.api import models
from stacktask.api import utils
from stacktask.api.v1 import tasks
class UserList(tasks.InviteUser): class UserList(tasks.InviteUser):
@ -35,11 +36,10 @@ class UserList(tasks.InviteUser):
project = id_manager.get_project(project_id) project = id_manager.get_project(project_id)
active_emails = set() active_emails = set()
for user in project.list_users(): for user in id_manager.list_users(project):
skip = False skip = False
self.logger.info(user)
roles = [] roles = []
for role in id_manager.get_roles(user, project): for role in user.roles:
if role.name in role_blacklist: if role.name in role_blacklist:
skip = True skip = True
continue continue
@ -52,7 +52,7 @@ class UserList(tasks.InviteUser):
user_status = 'Active' if enabled else 'Account Disabled' user_status = 'Active' if enabled else 'Account Disabled'
active_emails.add(email) active_emails.add(email)
user_list.append({'id': user.id, user_list.append({'id': user.id,
'name': user.username, 'name': user.name,
'email': email, 'email': email,
'roles': roles, 'roles': roles,
'cohort': 'Member', 'cohort': 'Member',
@ -124,7 +124,7 @@ class UserDetail(tasks.TaskView):
if not roles or roles_blacklisted: if not roles or roles_blacklisted:
return Response(no_user, status=404) return Response(no_user, status=404)
return Response({'id': user.id, return Response({'id': user.id,
"username": user.username, "username": user.name,
"email": getattr(user, 'email', ''), "email": getattr(user, 'email', ''),
'roles': roles}) 'roles': roles})

View File

@ -20,12 +20,12 @@ temp_cache = {}
def setup_temp_cache(projects, users): def setup_temp_cache(projects, users):
admin_user = mock.Mock() admin_user = mock.Mock()
admin_user.id = 0 admin_user.id = 'user_id_0'
admin_user.username = 'admin' admin_user.name = 'admin'
admin_user.password = 'password' admin_user.password = 'password'
admin_user.email = 'admin@example.com' admin_user.email = 'admin@example.com'
users.update({admin_user.username: admin_user}) users.update({admin_user.id: admin_user})
global temp_cache global temp_cache
@ -59,7 +59,7 @@ class FakeProject():
usernames.append(username) usernames.append(username)
users = [] users = []
for user in temp_cache['users'].values(): for user in temp_cache['users'].values():
if user.username in usernames: if user.name in usernames:
users.append(user) users.append(user)
return users return users
@ -68,38 +68,61 @@ class FakeManager(object):
def find_user(self, name): def find_user(self, name):
global temp_cache global temp_cache
return temp_cache['users'].get(name, None) for user in temp_cache['users'].values():
if user.name == name:
return user
return None
def get_user(self, user_id): def get_user(self, user_id):
global temp_cache global temp_cache
return temp_cache['users'].get(user_id, None) return temp_cache['users'].get(user_id, None)
def list_users(self, project):
global temp_cache
roles = temp_cache['projects'][project.name].roles
users = []
for user_id, roles in roles.iteritems():
user = self.get_user(user_id)
user.roles = []
for role in roles:
r = mock.Mock()
r.name = role
user.roles.append(r)
return users
def create_user(self, name, password, email, project_id): def create_user(self, name, password, email, project_id):
global temp_cache global temp_cache
user = mock.Mock() user = mock.Mock()
temp_cache['i'] += 1 user.id = "user_id_%s" % int(temp_cache['i'])
user.id = temp_cache['i'] user.name = name
user.username = name
user.password = password user.password = password
user.email = email user.email = email
user.default_project = project_id user.default_project = project_id
temp_cache['users'][name] = user temp_cache['users'][user.id] = user
temp_cache['i'] += 0.5
return user return user
def update_user_password(self, user, password): def update_user_password(self, user, password):
global temp_cache global temp_cache
user = temp_cache['users'][user.username] user = temp_cache['users'][user.id]
user.password = password user.password = password
def find_role(self, name): def find_role(self, name):
global temp_cache global temp_cache
return temp_cache['roles'].get(name, None) if temp_cache['roles'].get(name, None):
role = mock.Mock()
role.name = name
return role
return None
def get_roles(self, user, project): def get_roles(self, user, project):
global temp_cache global temp_cache
try: try:
roles = [] roles = []
for role in project.roles[user.username]: for role in project.roles[user.id]:
r = mock.Mock() r = mock.Mock()
r.name = role r.name = role
roles.append(r) roles.append(r)
@ -107,17 +130,29 @@ class FakeManager(object):
except KeyError: except KeyError:
return [] return []
def get_all_roles(self, user):
global temp_cache
projects = {}
for project in temp_cache['projects'].values():
projects[project.id] = []
for role in project.roles[user.id]:
r = mock.Mock()
r.name = role
projects[project.id].append(r)
return projects
def add_user_role(self, user, role, project_id): def add_user_role(self, user, role, project_id):
project = self.get_project(project_id) project = self.get_project(project_id)
try: try:
project.roles[user.username].append(role) project.roles[user.id].append(role.name)
except KeyError: except KeyError:
project.roles[user.username] = [role] project.roles[user.id] = [role.name]
def remove_user_role(self, user, role, project_id): def remove_user_role(self, user, role, project_id):
project = self.get_project(project_id) project = self.get_project(project_id)
try: try:
project.roles[user.username].remove(role) project.roles[user.id].remove(role.name)
except KeyError: except KeyError:
pass pass
@ -137,8 +172,8 @@ class FakeManager(object):
if p_id: if p_id:
project.id = p_id project.id = p_id
else: else:
temp_cache['i'] += 1 temp_cache['i'] += 0.5
project.id = temp_cache['i'] project.id = "project_id_%s" % int(temp_cache['i'])
project.name = project_name project.name = project_name
project.roles = {} project.roles = {}
temp_cache['projects'][project_name] = project temp_cache['projects'][project_name] = project

View File

@ -12,13 +12,19 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import json
from datetime import timedelta
from django.utils import timezone
import mock
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from stacktask.api.models import Task, Token from stacktask.api.models import Task, Token
import mock
from django.utils import timezone
from datetime import timedelta
import json
from stacktask.api.v1.tests import FakeManager, setup_temp_cache from stacktask.api.v1.tests import FakeManager, setup_temp_cache
@ -121,11 +127,11 @@ class AdminAPITests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
url = "/v1/actions/ResetPassword" url = "/v1/actions/ResetPassword"
data = {'email': "test@example.com"} data = {'email': "test@example.com"}
@ -154,11 +160,11 @@ class AdminAPITests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
url = "/v1/actions/ResetPassword" url = "/v1/actions/ResetPassword"
data = {'email': "test@example.com"} data = {'email': "test@example.com"}
@ -373,7 +379,7 @@ class AdminAPITests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
@ -383,7 +389,7 @@ class AdminAPITests(APITestCase):
user2.email = "test2@example.com" user2.email = "test2@example.com"
user2.password = "test_password" user2.password = "test_password"
setup_temp_cache({}, {user.username: user, user2.name: user2}) setup_temp_cache({}, {user.id: user, user2.name: user2})
url = "/v1/actions/ResetPassword" url = "/v1/actions/ResetPassword"
data = {'email': "test@example.com"} data = {'email': "test@example.com"}
@ -429,11 +435,11 @@ class AdminAPITests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
url = "/v1/actions/ResetPassword" url = "/v1/actions/ResetPassword"
data = {'email': "test@example.com"} data = {'email': "test@example.com"}
@ -982,3 +988,33 @@ class AdminAPITests(APITestCase):
url, params, format='json', headers=headers url, params, format='json', headers=headers
) )
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST) self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST)
@mock.patch(
'stacktask.actions.models.user_store.IdentityManager', FakeManager)
@mock.patch(
'stacktask.actions.tenant_setup.models.IdentityManager', FakeManager)
def test_reset_admin(self):
"""
Ensure that you cannot issue a password reset for an
admin user.
"""
user = mock.Mock()
user.id = 'user_id'
user.name = "test@example.com"
user.email = "test@example.com"
user.password = "test_password"
project = mock.Mock()
project.id = 'test_project_id'
project.name = 'test_project'
project.roles = {user.id: ['admin']}
setup_temp_cache({'test_project': project}, {user.id: user})
url = "/v1/actions/ResetPassword"
data = {'email': "test@example.com"}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data, None)
self.assertEqual(0, Token.objects.count())

View File

@ -12,10 +12,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import mock
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from stacktask.api.models import Token from stacktask.api.models import Token
import mock
from stacktask.api.v1.tests import FakeManager, setup_temp_cache from stacktask.api.v1.tests import FakeManager, setup_temp_cache
@ -118,11 +120,11 @@ class OpenstackAPITests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
headers = { headers = {
'project_name': "test_project", 'project_name': "test_project",

View File

@ -12,10 +12,12 @@
# License for the specific language governing permissions and limitations # License for the specific language governing permissions and limitations
# under the License. # under the License.
import mock
from rest_framework import status from rest_framework import status
from rest_framework.test import APITestCase from rest_framework.test import APITestCase
from stacktask.api.models import Task, Token from stacktask.api.models import Task, Token
import mock
from stacktask.api.v1.tests import FakeManager, setup_temp_cache from stacktask.api.v1.tests import FakeManager, setup_temp_cache
@ -140,10 +142,10 @@ class TaskViewTests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
setup_temp_cache({'test_project': project}, {user.username: user}) setup_temp_cache({'test_project': project}, {user.id: user})
url = "/v1/actions/InviteUser" url = "/v1/actions/InviteUser"
headers = { headers = {
@ -176,15 +178,15 @@ class TaskViewTests(APITestCase):
""" """
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
project = mock.Mock() project = mock.Mock()
project.id = 'test_project_id' project.id = 'test_project_id'
project.name = 'test_project' project.name = 'test_project'
project.roles = {user.username: ['Member']} project.roles = {user.id: ['Member']}
setup_temp_cache({'test_project': project}, {user.username: user}) setup_temp_cache({'test_project': project}, {user.id: user})
url = "/v1/actions/InviteUser" url = "/v1/actions/InviteUser"
headers = { headers = {
@ -297,10 +299,10 @@ class TaskViewTests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
url = "/v1/actions/InviteUser" url = "/v1/actions/InviteUser"
headers = { headers = {
@ -344,11 +346,11 @@ class TaskViewTests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
url = "/v1/actions/ResetPassword" url = "/v1/actions/ResetPassword"
data = {'email': "test@example.com"} data = {'email': "test@example.com"}
@ -374,11 +376,11 @@ class TaskViewTests(APITestCase):
user = mock.Mock() user = mock.Mock()
user.id = 'user_id' user.id = 'user_id'
user.username = "test@example.com" user.name = "test@example.com"
user.email = "test@example.com" user.email = "test@example.com"
user.password = "test_password" user.password = "test_password"
setup_temp_cache({}, {user.username: user}) setup_temp_cache({}, {user.id: user})
# Submit password reset # Submit password reset
url = "/v1/actions/ResetPassword" url = "/v1/actions/ResetPassword"

View File

@ -63,7 +63,8 @@ KEYSTONE = {
'username': 'admin', 'username': 'admin',
'password': 'openstack', 'password': 'openstack',
'project_name': 'admin', 'project_name': 'admin',
'auth_url': "http://localhost:5000/v2.0" 'auth_url': "http://localhost:5000/v2.0",
'auth_url_v3': "http://localhost:5000/v3"
} }
DEFAULT_REGION = 'RegionOne' DEFAULT_REGION = 'RegionOne'
@ -135,6 +136,9 @@ ACTION_SETTINGS = {
'NewUser': { 'NewUser': {
'allowed_roles': ['project_mod', 'project_owner', "Member"] 'allowed_roles': ['project_mod', 'project_owner', "Member"]
}, },
'ResetUser': {
'blacklisted_roles': ['admin', "Admin"]
},
'DefaultProjectResources': { 'DefaultProjectResources': {
'RegionOne': { 'RegionOne': {
'DNS_NAMESERVERS': ['193.168.1.2', '193.168.1.3'], 'DNS_NAMESERVERS': ['193.168.1.2', '193.168.1.3'],