Skip to content

Commit

Permalink
User crud no longer available in syspanel when Keystone is using some…
Browse files Browse the repository at this point in the history
…thing

other than the native auth backend.

Fixes bug: 948310

Change-Id: Ifebf0f5a60228c84d06f11e60f752f9ff474c929
  • Loading branch information
treshenry committed Mar 9, 2012
1 parent f74abc9 commit d4d8145
Show file tree
Hide file tree
Showing 7 changed files with 114 additions and 9 deletions.
14 changes: 14 additions & 0 deletions horizon/api/keystone.py
Expand Up @@ -268,3 +268,17 @@ def create_ec2_credentials(request, user_id, tenant_id):

def get_user_ec2_credentials(request, user_id, access_token):
return keystoneclient(request).ec2.get(user_id, access_token)


def keystone_can_edit_user():
if hasattr(settings, "OPENSTACK_KEYSTONE_BACKEND"):
return settings.OPENSTACK_KEYSTONE_BACKEND['can_edit_user']
else:
return False


def keystone_backend_name():
if hasattr(settings, "OPENSTACK_KEYSTONE_BACKEND"):
return settings.OPENSTACK_KEYSTONE_BACKEND['name']
else:
return 'unknown'
14 changes: 10 additions & 4 deletions horizon/dashboards/syspanel/services/tables.py
@@ -1,12 +1,10 @@
import logging

from django import shortcuts
from django import template
from django.contrib import messages
from django.utils.translation import ugettext_lazy as _

from horizon import api
from horizon import tables
from horizon import api


LOG = logging.getLogger(__name__)
Expand Down Expand Up @@ -36,9 +34,17 @@ def get_enabled(service, reverse=False):
return options[0] if not service.disabled else options[1]


def get_service_name(service):
if(service.type == "identity"):
return _("%s (%s backend)") % (service.type,
api.keystone_backend_name())
else:
return service.type


class ServicesTable(tables.DataTable):
id = tables.Column('id', verbose_name=_('Id'), hidden=True)
service = tables.Column('type', verbose_name=_('Service'))
service = tables.Column(get_service_name, verbose_name=_('Service'))
host = tables.Column('host', verbose_name=_('Host'))
enabled = tables.Column(get_enabled,
verbose_name=_('Enabled'),
Expand Down
20 changes: 18 additions & 2 deletions horizon/dashboards/syspanel/users/forms.py
Expand Up @@ -23,6 +23,7 @@
from django import shortcuts
from django.contrib import messages
from django.utils.translation import ugettext as _
from django.forms import ValidationError

from horizon import api
from horizon import exceptions
Expand All @@ -46,13 +47,25 @@ def __init__(self, request, *args, **kwargs):
def _instantiate(cls, request, *args, **kwargs):
return cls(request, *args, **kwargs)

def clean(self):
'''Check to make sure password fields match.'''
super(forms.Form, self).clean()
if 'password' in self.cleaned_data and \
'confirm_password' in self.cleaned_data:
if self.cleaned_data['password'] != \
self.cleaned_data['confirm_password']:
raise ValidationError(_('Passwords do not match.'))
return self.cleaned_data


class CreateUserForm(BaseUserForm):
name = forms.CharField(label=_("Name"))
email = forms.EmailField(label=_("Email"))
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput(render_value=False),
required=False)
widget=forms.PasswordInput(render_value=False))
confirm_password = forms.CharField(
label=_("Confirm Password"),
widget=forms.PasswordInput(render_value=False))
tenant_id = forms.ChoiceField(label=_("Primary Project"))

def handle(self, request, data):
Expand Down Expand Up @@ -90,6 +103,9 @@ class UpdateUserForm(BaseUserForm):
password = forms.CharField(label=_("Password"),
widget=forms.PasswordInput(render_value=False),
required=False)
confirm_password = forms.CharField(
label=_("Confirm Password"),
widget=forms.PasswordInput(render_value=False))
tenant_id = forms.ChoiceField(label=_("Primary Project"))

def handle(self, request, data):
Expand Down
11 changes: 8 additions & 3 deletions horizon/dashboards/syspanel/users/tables.py
Expand Up @@ -131,6 +131,11 @@ class UsersTable(tables.DataTable):
class Meta:
name = "users"
verbose_name = _("Users")
row_actions = (EditUserLink, EnableUsersAction, DisableUsersAction,
DeleteUsersAction)
table_actions = (UserFilterAction, CreateUserLink, DeleteUsersAction)
if api.keystone_can_edit_user():
row_actions = (EditUserLink, EnableUsersAction, DisableUsersAction,
DeleteUsersAction)
table_actions = (UserFilterAction, CreateUserLink,
DeleteUsersAction)
else:
row_actions = (EnableUsersAction, DisableUsersAction)
table_actions = (UserFilterAction,)
48 changes: 48 additions & 0 deletions horizon/dashboards/syspanel/users/tests.py
Expand Up @@ -27,6 +27,7 @@


USERS_INDEX_URL = reverse('horizon:syspanel:users:index')
USER_CREATE_URL = reverse('horizon:syspanel:users:create')


class UsersViewTests(test.BaseAdminViewTests):
Expand All @@ -39,6 +40,53 @@ def test_index(self):
self.assertTemplateUsed(res, 'syspanel/users/index.html')
self.assertItemsEqual(res.context['table'].data, self.users.list())

def test_create_user(self):
user = self.users.get(id="1")
role = self.roles.first()
self.mox.StubOutWithMock(api, 'user_create')
self.mox.StubOutWithMock(api, 'tenant_list')
self.mox.StubOutWithMock(api.keystone, 'get_default_role')
self.mox.StubOutWithMock(api, 'add_tenant_user_role')
api.tenant_list(IgnoreArg(), admin=True).AndReturn(self.tenants.list())
api.user_create(IgnoreArg(),
user.name,
user.email,
user.password,
self.tenant.id,
True).AndReturn(user)
api.keystone.get_default_role(IgnoreArg()).AndReturn(role)
api.add_tenant_user_role(IgnoreArg(), self.tenant.id, user.id, role.id)
self.mox.ReplayAll()

formData = {'method': 'CreateUserForm',
'name': user.name,
'email': user.email,
'password': user.password,
'tenant_id': self.tenant.id,
'confirm_password': user.password}
res = self.client.post(USER_CREATE_URL, formData)
self.assertNoFormErrors(res)
self.assertMessageCount(success=1)

def test_create_user_password_mismatch(self):
user = self.users.get(id="1")
self.mox.StubOutWithMock(api, 'tenant_list')
api.tenant_list(IgnoreArg(), admin=True).AndReturn(self.tenants.list())
self.mox.ReplayAll()

formData = {'method': 'CreateUserForm',
'name': user.name,
'email': user.email,
'password': user.password,
'tenant_id': self.tenant.id,
'confirm_password': "doesntmatch"}

res = self.client.post(USER_CREATE_URL, formData)
self.assertFormError(res,
"form",
None,
['Passwords do not match.'])

def test_enable_user(self):
user = self.users.get(id="2")
self.mox.StubOutWithMock(api.keystone, 'user_update_enabled')
Expand Down
5 changes: 5 additions & 0 deletions horizon/tests/testsettings.py
Expand Up @@ -102,6 +102,11 @@
OPENSTACK_KEYSTONE_ADMIN_URL = "http://%s:35357/v2.0" % OPENSTACK_ADDRESS
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"

OPENSTACK_KEYSTONE_BACKEND = {
'name': 'native',
'can_edit_user': True
}

# Silence logging output during tests.
LOGGING = {
'version': 1,
Expand Down
11 changes: 11 additions & 0 deletions openstack_dashboard/local/local_settings.py.example
Expand Up @@ -39,6 +39,17 @@ OPENSTACK_KEYSTONE_URL = "http://%s:5000/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_ADMIN_URL = "http://%s:35357/v2.0" % OPENSTACK_HOST
OPENSTACK_KEYSTONE_DEFAULT_ROLE = "Member"

# The OPENSTACK_KEYSTONE_BACKEND settings can be used to identify the
# capabilities of the auth backend for Keystone.
# If Keystone has been configured to use LDAP as the auth backend then set
# can_edit_user to False and name to 'ldap'.
#
# TODO(tres): Remove these once Keystone has an API to identify auth backend.
OPENSTACK_KEYSTONE_BACKEND = {
'name': 'native',
'can_edit_user': True
}

# The number of Swift containers and objects to display on a single page before
# providing a paging element (a "more" link) to paginate results.
API_RESULT_LIMIT = 1000
Expand Down

0 comments on commit d4d8145

Please sign in to comment.