Merge next branch
This commit is contained in:
commit
4d99449780
@ -78,10 +78,10 @@ options:
|
|||||||
default: 'Admin'
|
default: 'Admin'
|
||||||
type: string
|
type: string
|
||||||
description: 'Admin role to be associated with admin and service users'
|
description: 'Admin role to be associated with admin and service users'
|
||||||
token-expiry:
|
token-expiration:
|
||||||
default: "2017-02-05T00:00"
|
default: 3600
|
||||||
type: string
|
type: int
|
||||||
description: "Expiration date of generated admin tokens"
|
description: "Amount of time a token should remain valid (in seconds)."
|
||||||
service-tenant:
|
service-tenant:
|
||||||
default: "services"
|
default: "services"
|
||||||
type: string
|
type: string
|
||||||
|
@ -202,6 +202,7 @@ class KeystoneContext(context.OSContextGenerator):
|
|||||||
ctxt['debug'] = debug and bool_from_string(debug)
|
ctxt['debug'] = debug and bool_from_string(debug)
|
||||||
verbose = config('verbose')
|
verbose = config('verbose')
|
||||||
ctxt['verbose'] = verbose and bool_from_string(verbose)
|
ctxt['verbose'] = verbose and bool_from_string(verbose)
|
||||||
|
ctxt['token_expiration'] = config('token-expiration')
|
||||||
|
|
||||||
ctxt['identity_backend'] = config('identity-backend')
|
ctxt['identity_backend'] = config('identity-backend')
|
||||||
ctxt['assignment_backend'] = config('assignment-backend')
|
ctxt['assignment_backend'] = config('assignment-backend')
|
||||||
|
@ -472,12 +472,14 @@ def create_service_entry(service_name, service_type, service_desc, owner=None):
|
|||||||
token=get_admin_token())
|
token=get_admin_token())
|
||||||
for service in [s._info for s in manager.api.services.list()]:
|
for service in [s._info for s in manager.api.services.list()]:
|
||||||
if service['name'] == service_name:
|
if service['name'] == service_name:
|
||||||
log("Service entry for '%s' already exists." % service_name)
|
log("Service entry for '%s' already exists." % service_name,
|
||||||
|
level=DEBUG)
|
||||||
return
|
return
|
||||||
|
|
||||||
manager.api.services.create(name=service_name,
|
manager.api.services.create(name=service_name,
|
||||||
service_type=service_type,
|
service_type=service_type,
|
||||||
description=service_desc)
|
description=service_desc)
|
||||||
log("Created new service entry '%s'" % service_name)
|
log("Created new service entry '%s'" % service_name, level=DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def create_endpoint_template(region, service, publicurl, adminurl,
|
def create_endpoint_template(region, service, publicurl, adminurl,
|
||||||
@ -510,7 +512,8 @@ def create_endpoint_template(region, service, publicurl, adminurl,
|
|||||||
publicurl=publicurl,
|
publicurl=publicurl,
|
||||||
adminurl=adminurl,
|
adminurl=adminurl,
|
||||||
internalurl=internalurl)
|
internalurl=internalurl)
|
||||||
log("Created new endpoint template for '%s' in '%s'" % (region, service))
|
log("Created new endpoint template for '%s' in '%s'" % (region, service),
|
||||||
|
level=DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def create_tenant(name):
|
def create_tenant(name):
|
||||||
@ -522,9 +525,21 @@ def create_tenant(name):
|
|||||||
if not tenants or name not in [t['name'] for t in tenants]:
|
if not tenants or name not in [t['name'] for t in tenants]:
|
||||||
manager.api.tenants.create(tenant_name=name,
|
manager.api.tenants.create(tenant_name=name,
|
||||||
description='Created by Juju')
|
description='Created by Juju')
|
||||||
log("Created new tenant: %s" % name)
|
log("Created new tenant: %s" % name, level=DEBUG)
|
||||||
return
|
return
|
||||||
log("Tenant '%s' already exists." % name)
|
|
||||||
|
log("Tenant '%s' already exists." % name, level=DEBUG)
|
||||||
|
|
||||||
|
|
||||||
|
def user_exists(name):
|
||||||
|
import manager
|
||||||
|
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
|
||||||
|
token=get_admin_token())
|
||||||
|
users = [u._info for u in manager.api.users.list()]
|
||||||
|
if not users or name not in [u['name'] for u in users]:
|
||||||
|
return False
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def create_user(name, password, tenant):
|
def create_user(name, password, tenant):
|
||||||
@ -532,18 +547,20 @@ def create_user(name, password, tenant):
|
|||||||
import manager
|
import manager
|
||||||
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
|
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
|
||||||
token=get_admin_token())
|
token=get_admin_token())
|
||||||
users = [u._info for u in manager.api.users.list()]
|
if user_exists(name):
|
||||||
if not users or name not in [u['name'] for u in users]:
|
log("A user named '%s' already exists" % name, level=DEBUG)
|
||||||
|
return
|
||||||
|
|
||||||
tenant_id = manager.resolve_tenant_id(tenant)
|
tenant_id = manager.resolve_tenant_id(tenant)
|
||||||
if not tenant_id:
|
if not tenant_id:
|
||||||
error_out('Could not resolve tenant_id for tenant %s' % tenant)
|
error_out('Could not resolve tenant_id for tenant %s' % tenant)
|
||||||
|
|
||||||
manager.api.users.create(name=name,
|
manager.api.users.create(name=name,
|
||||||
password=password,
|
password=password,
|
||||||
email='juju@localhost',
|
email='juju@localhost',
|
||||||
tenant_id=tenant_id)
|
tenant_id=tenant_id)
|
||||||
log("Created new user '%s' tenant: %s" % (name, tenant_id))
|
log("Created new user '%s' tenant: %s" % (name, tenant_id),
|
||||||
return
|
level=DEBUG)
|
||||||
log("A user named '%s' already exists" % name)
|
|
||||||
|
|
||||||
|
|
||||||
def create_role(name, user=None, tenant=None):
|
def create_role(name, user=None, tenant=None):
|
||||||
@ -554,9 +571,9 @@ def create_role(name, user=None, tenant=None):
|
|||||||
roles = [r._info for r in manager.api.roles.list()]
|
roles = [r._info for r in manager.api.roles.list()]
|
||||||
if not roles or name not in [r['name'] for r in roles]:
|
if not roles or name not in [r['name'] for r in roles]:
|
||||||
manager.api.roles.create(name=name)
|
manager.api.roles.create(name=name)
|
||||||
log("Created new role '%s'" % name)
|
log("Created new role '%s'" % name, level=DEBUG)
|
||||||
else:
|
else:
|
||||||
log("A role named '%s' already exists" % name)
|
log("A role named '%s' already exists" % name, level=DEBUG)
|
||||||
|
|
||||||
if not user and not tenant:
|
if not user and not tenant:
|
||||||
return
|
return
|
||||||
@ -590,10 +607,10 @@ def grant_role(user, role, tenant):
|
|||||||
role=role_id,
|
role=role_id,
|
||||||
tenant=tenant_id)
|
tenant=tenant_id)
|
||||||
log("Granted user '%s' role '%s' on tenant '%s'" %
|
log("Granted user '%s' role '%s' on tenant '%s'" %
|
||||||
(user, role, tenant))
|
(user, role, tenant), level=DEBUG)
|
||||||
else:
|
else:
|
||||||
log("User '%s' already has role '%s' on tenant '%s'" %
|
log("User '%s' already has role '%s' on tenant '%s'" %
|
||||||
(user, role, tenant))
|
(user, role, tenant), level=DEBUG)
|
||||||
|
|
||||||
|
|
||||||
def store_admin_passwd(passwd):
|
def store_admin_passwd(passwd):
|
||||||
@ -663,10 +680,9 @@ def ensure_initial_admin(config):
|
|||||||
'ldap' and config('ldap-readonly')):
|
'ldap' and config('ldap-readonly')):
|
||||||
passwd = get_admin_passwd()
|
passwd = get_admin_passwd()
|
||||||
if passwd:
|
if passwd:
|
||||||
create_user(config('admin-user'), passwd, tenant='admin')
|
create_user_credentials(config('admin-user'), 'admin', passwd,
|
||||||
update_user_password(config('admin-user'), passwd)
|
new_roles=[config('admin-role')])
|
||||||
create_role(config('admin-role'), config('admin-user'),
|
|
||||||
'admin')
|
|
||||||
create_service_entry("keystone", "identity",
|
create_service_entry("keystone", "identity",
|
||||||
"Keystone Identity Service")
|
"Keystone Identity Service")
|
||||||
|
|
||||||
@ -1260,6 +1276,50 @@ def relation_list(rid):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def create_user_credentials(user, tenant, passwd, new_roles=None, grants=None):
|
||||||
|
"""Create user credentials.
|
||||||
|
|
||||||
|
Optionally adds role grants to user and/or creates new roles.
|
||||||
|
"""
|
||||||
|
log("Creating service credentials for '%s'" % user, level=DEBUG)
|
||||||
|
if user_exists(user):
|
||||||
|
log("User '%s' already exists - updating password" % (user),
|
||||||
|
level=DEBUG)
|
||||||
|
update_user_password(user, passwd)
|
||||||
|
else:
|
||||||
|
create_user(user, passwd, tenant)
|
||||||
|
|
||||||
|
if grants:
|
||||||
|
for role in grants:
|
||||||
|
grant_role(user, role, tenant)
|
||||||
|
else:
|
||||||
|
log("No role grants requested for user '%s'" % (user), level=DEBUG)
|
||||||
|
|
||||||
|
if new_roles:
|
||||||
|
# Allow the remote service to request creation of any additional roles.
|
||||||
|
# Currently used by Swift and Ceilometer.
|
||||||
|
for role in new_roles:
|
||||||
|
log("Creating requested role '%s'" % role, level=DEBUG)
|
||||||
|
create_role(role, user, tenant)
|
||||||
|
|
||||||
|
return passwd
|
||||||
|
|
||||||
|
|
||||||
|
def create_service_credentials(user, new_roles=None):
|
||||||
|
"""Create credentials for service with given username.
|
||||||
|
|
||||||
|
Services are given a user under config('service-tenant') and are given the
|
||||||
|
config('admin-role') role. Tenant is assumed to already exist,
|
||||||
|
"""
|
||||||
|
tenant = config('service-tenant')
|
||||||
|
if not tenant:
|
||||||
|
raise Exception("No service tenant provided in config")
|
||||||
|
|
||||||
|
return create_user_credentials(user, tenant, get_service_password(user),
|
||||||
|
new_roles=new_roles,
|
||||||
|
grants=[config('admin-role')])
|
||||||
|
|
||||||
|
|
||||||
def add_service_to_keystone(relation_id=None, remote_unit=None):
|
def add_service_to_keystone(relation_id=None, remote_unit=None):
|
||||||
import manager
|
import manager
|
||||||
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
|
manager = manager.KeystoneManager(endpoint=get_local_endpoint(),
|
||||||
@ -1390,18 +1450,9 @@ def add_service_to_keystone(relation_id=None, remote_unit=None):
|
|||||||
return
|
return
|
||||||
|
|
||||||
token = get_admin_token()
|
token = get_admin_token()
|
||||||
log("Creating service credentials for '%s'" % service_username)
|
roles = get_requested_roles(settings)
|
||||||
|
service_password = create_service_credentials(service_username,
|
||||||
service_password = get_service_password(service_username)
|
new_roles=roles)
|
||||||
create_user(service_username, service_password, config('service-tenant'))
|
|
||||||
grant_role(service_username, config('admin-role'),
|
|
||||||
config('service-tenant'))
|
|
||||||
|
|
||||||
# Allow the remote service to request creation of any additional roles.
|
|
||||||
# Currently used by Swift and Ceilometer.
|
|
||||||
for role in get_requested_roles(settings):
|
|
||||||
log("Creating requested role: %s" % role)
|
|
||||||
create_role(role, service_username, config('service-tenant'))
|
|
||||||
|
|
||||||
# As of https://review.openstack.org/#change,4675, all nodes hosting
|
# As of https://review.openstack.org/#change,4675, all nodes hosting
|
||||||
# an endpoint(s) needs a service username and password assigned to
|
# an endpoint(s) needs a service username and password assigned to
|
||||||
|
@ -49,7 +49,8 @@ provider = keystone.token.providers.pki.Provider
|
|||||||
provider = keystone.token.providers.pkiz.Provider
|
provider = keystone.token.providers.pkiz.Provider
|
||||||
{% else -%}
|
{% else -%}
|
||||||
provider = keystone.token.providers.uuid.Provider
|
provider = keystone.token.providers.uuid.Provider
|
||||||
{% endif %}
|
{% endif -%}
|
||||||
|
expiration = {{ token_expiration }}
|
||||||
|
|
||||||
{% include "parts/section-signing" %}
|
{% include "parts/section-signing" %}
|
||||||
|
|
||||||
|
@ -45,7 +45,16 @@ driver = keystone.catalog.backends.sql.Catalog
|
|||||||
|
|
||||||
[token]
|
[token]
|
||||||
driver = keystone.token.persistence.backends.sql.Token
|
driver = keystone.token.persistence.backends.sql.Token
|
||||||
|
{% if token_provider == 'pki' -%}
|
||||||
|
provider = keystone.token.providers.pki.Provider
|
||||||
|
{% elif token_provider == 'pkiz' -%}
|
||||||
|
provider = keystone.token.providers.pkiz.Provider
|
||||||
|
{% else -%}
|
||||||
provider = keystone.token.providers.uuid.Provider
|
provider = keystone.token.providers.uuid.Provider
|
||||||
|
{% endif -%}
|
||||||
|
expiration = {{ token_expiration }}
|
||||||
|
|
||||||
|
{% include "parts/section-signing" %}
|
||||||
|
|
||||||
[cache]
|
[cache]
|
||||||
|
|
||||||
|
@ -303,6 +303,63 @@ class TestKeystoneUtils(CharmTestCase):
|
|||||||
adminurl='10.0.0.2',
|
adminurl='10.0.0.2',
|
||||||
internalurl='192.168.1.2')
|
internalurl='192.168.1.2')
|
||||||
|
|
||||||
|
@patch.object(utils, 'user_exists')
|
||||||
|
@patch.object(utils, 'grant_role')
|
||||||
|
@patch.object(utils, 'create_role')
|
||||||
|
@patch.object(utils, 'create_user')
|
||||||
|
def test_create_user_credentials_no_roles(self, mock_create_user,
|
||||||
|
mock_create_role,
|
||||||
|
mock_grant_role,
|
||||||
|
mock_user_exists):
|
||||||
|
mock_user_exists.return_value = False
|
||||||
|
utils.create_user_credentials('userA', 'tenantA', 'passA')
|
||||||
|
mock_create_user.assert_has_calls([call('userA', 'passA', 'tenantA')])
|
||||||
|
mock_create_role.assert_has_calls([])
|
||||||
|
mock_grant_role.assert_has_calls([])
|
||||||
|
|
||||||
|
@patch.object(utils, 'user_exists')
|
||||||
|
@patch.object(utils, 'grant_role')
|
||||||
|
@patch.object(utils, 'create_role')
|
||||||
|
@patch.object(utils, 'create_user')
|
||||||
|
def test_create_user_credentials(self, mock_create_user, mock_create_role,
|
||||||
|
mock_grant_role, mock_user_exists):
|
||||||
|
mock_user_exists.return_value = False
|
||||||
|
utils.create_user_credentials('userA', 'tenantA', 'passA',
|
||||||
|
grants=['roleA'], new_roles=['roleB'])
|
||||||
|
mock_create_user.assert_has_calls([call('userA', 'passA', 'tenantA')])
|
||||||
|
mock_create_role.assert_has_calls([call('roleB', 'userA', 'tenantA')])
|
||||||
|
mock_grant_role.assert_has_calls([call('userA', 'roleA', 'tenantA')])
|
||||||
|
|
||||||
|
@patch.object(utils, 'update_user_password')
|
||||||
|
@patch.object(utils, 'user_exists')
|
||||||
|
@patch.object(utils, 'grant_role')
|
||||||
|
@patch.object(utils, 'create_role')
|
||||||
|
@patch.object(utils, 'create_user')
|
||||||
|
def test_create_user_credentials_user_exists(self, mock_create_user,
|
||||||
|
mock_create_role,
|
||||||
|
mock_grant_role,
|
||||||
|
mock_user_exists,
|
||||||
|
mock_update_user_password):
|
||||||
|
mock_user_exists.return_value = True
|
||||||
|
utils.create_user_credentials('userA', 'tenantA', 'passA',
|
||||||
|
grants=['roleA'], new_roles=['roleB'])
|
||||||
|
mock_create_user.assert_has_calls([])
|
||||||
|
mock_create_role.assert_has_calls([call('roleB', 'userA', 'tenantA')])
|
||||||
|
mock_grant_role.assert_has_calls([call('userA', 'roleA', 'tenantA')])
|
||||||
|
mock_update_user_password.assert_has_calls([call('userA', 'passA')])
|
||||||
|
|
||||||
|
@patch.object(utils, 'get_service_password')
|
||||||
|
@patch.object(utils, 'create_user_credentials')
|
||||||
|
def test_create_service_credentials(self, mock_create_user_credentials,
|
||||||
|
mock_get_service_password):
|
||||||
|
mock_get_service_password.return_value = 'passA'
|
||||||
|
cfg = {'service-tenant': 'tenantA', 'admin-role': 'Admin'}
|
||||||
|
self.config.side_effect = lambda key: cfg.get(key, None)
|
||||||
|
calls = [call('serviceA', 'tenantA', 'passA', grants=['Admin'],
|
||||||
|
new_roles=None)]
|
||||||
|
utils.create_service_credentials('serviceA')
|
||||||
|
mock_create_user_credentials.assert_has_calls(calls)
|
||||||
|
|
||||||
def test_ensure_valid_service_incorrect(self):
|
def test_ensure_valid_service_incorrect(self):
|
||||||
utils.ensure_valid_service('fakeservice')
|
utils.ensure_valid_service('fakeservice')
|
||||||
self.log.assert_called_with("Invalid service requested: 'fakeservice'")
|
self.log.assert_called_with("Invalid service requested: 'fakeservice'")
|
||||||
|
Loading…
Reference in New Issue
Block a user