Drop deprecated Keystone V2 API support
Keystone V2 API was deprecated in Stein release in Horizon and removed from Keystone in Queens release. Change-Id: I917e273d3174adf0874e516b3d635ccb8ba58a27
This commit is contained in:
parent
7c897b677c
commit
f33e5fd8ac
@ -492,7 +492,7 @@ OpenStack dashboard to use a specific API version for a given service API.
|
|||||||
|
|
||||||
The version should be formatted as it appears in the URL for the
|
The version should be formatted as it appears in the URL for the
|
||||||
service API. For example, the identity service APIs have inconsistent
|
service API. For example, the identity service APIs have inconsistent
|
||||||
use of the decimal point, so valid options would be "2.0" or "3".
|
use of the decimal point, so valid options would be "3".
|
||||||
For example:
|
For example:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
@ -1313,7 +1313,7 @@ Default: ``["admin"]``
|
|||||||
|
|
||||||
The list of roles that have administrator privileges in this OpenStack
|
The list of roles that have administrator privileges in this OpenStack
|
||||||
installation. This check is very basic and essentially only works with
|
installation. This check is very basic and essentially only works with
|
||||||
keystone v2.0 and v3 with the default policy file. The setting assumes there
|
keystone v3 with the default policy file. The setting assumes there
|
||||||
is a common ``admin`` like role(s) across services. Example uses of this
|
is a common ``admin`` like role(s) across services. Example uses of this
|
||||||
setting are:
|
setting are:
|
||||||
|
|
||||||
|
@ -149,9 +149,7 @@ class KeystoneBackend(object):
|
|||||||
scoped_auth = domain_auth
|
scoped_auth = domain_auth
|
||||||
scoped_auth_ref = domain_auth_ref
|
scoped_auth_ref = domain_auth_ref
|
||||||
elif not scoped_auth_ref and not domain_auth_ref:
|
elif not scoped_auth_ref and not domain_auth_ref:
|
||||||
msg = _('You are not authorized for any projects.')
|
msg = _('You are not authorized for any projects or domains.')
|
||||||
if utils.get_keystone_version() >= 3:
|
|
||||||
msg = _('You are not authorized for any projects or domains.')
|
|
||||||
raise exceptions.KeystoneAuthException(msg)
|
raise exceptions.KeystoneAuthException(msg)
|
||||||
|
|
||||||
# Check expiry for our new scoped token.
|
# Check expiry for our new scoped token.
|
||||||
@ -170,16 +168,10 @@ class KeystoneBackend(object):
|
|||||||
|
|
||||||
interface = settings.OPENSTACK_ENDPOINT_TYPE
|
interface = settings.OPENSTACK_ENDPOINT_TYPE
|
||||||
|
|
||||||
endpoint, url_fixed = utils.fix_auth_url_version_prefix(
|
endpoint = scoped_auth_ref.service_catalog.url_for(
|
||||||
scoped_auth_ref.service_catalog.url_for(
|
service_type='identity',
|
||||||
service_type='identity',
|
interface=interface,
|
||||||
interface=interface,
|
region_name=region_name)
|
||||||
region_name=region_name))
|
|
||||||
if url_fixed:
|
|
||||||
LOG.warning("The Keystone URL in service catalog points to a v2.0 "
|
|
||||||
"Keystone endpoint, but v3 is specified as the API "
|
|
||||||
"version to use by Horizon. Using v3 endpoint for "
|
|
||||||
"authentication.")
|
|
||||||
|
|
||||||
# If we made it here we succeeded. Create our User!
|
# If we made it here we succeeded. Create our User!
|
||||||
unscoped_token = unscoped_auth_ref.auth_token
|
unscoped_token = unscoped_auth_ref.auth_token
|
||||||
|
@ -15,7 +15,6 @@ import logging
|
|||||||
|
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
from keystoneauth1 import exceptions as keystone_exceptions
|
from keystoneauth1 import exceptions as keystone_exceptions
|
||||||
from keystoneclient.v2_0 import client as v2_client
|
|
||||||
from keystoneclient.v3 import client as v3_client
|
from keystoneclient.v3 import client as v3_client
|
||||||
import six
|
import six
|
||||||
|
|
||||||
@ -82,16 +81,11 @@ class BasePlugin(object):
|
|||||||
or v3 keystoneclient projects objects.
|
or v3 keystoneclient projects objects.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
if self.keystone_version >= 3:
|
client = v3_client.Client(session=session, auth=auth_plugin)
|
||||||
client = v3_client.Client(session=session, auth=auth_plugin)
|
if auth_ref.is_federated:
|
||||||
if auth_ref.is_federated:
|
return client.federation.projects.list()
|
||||||
return client.federation.projects.list()
|
|
||||||
else:
|
|
||||||
return client.projects.list(user=auth_ref.user_id)
|
|
||||||
|
|
||||||
else:
|
else:
|
||||||
client = v2_client.Client(session=session, auth=auth_plugin)
|
return client.projects.list(user=auth_ref.user_id)
|
||||||
return client.tenants.list()
|
|
||||||
|
|
||||||
except (keystone_exceptions.ClientException,
|
except (keystone_exceptions.ClientException,
|
||||||
keystone_exceptions.AuthorizationFailure):
|
keystone_exceptions.AuthorizationFailure):
|
||||||
@ -100,11 +94,8 @@ class BasePlugin(object):
|
|||||||
|
|
||||||
def list_domains(self, session, auth_plugin, auth_ref=None):
|
def list_domains(self, session, auth_plugin, auth_ref=None):
|
||||||
try:
|
try:
|
||||||
if self.keystone_version >= 3:
|
client = v3_client.Client(session=session, auth=auth_plugin)
|
||||||
client = v3_client.Client(session=session, auth=auth_plugin)
|
return client.auth.domains()
|
||||||
return client.auth.domains()
|
|
||||||
else:
|
|
||||||
return []
|
|
||||||
except (keystone_exceptions.ClientException,
|
except (keystone_exceptions.ClientException,
|
||||||
keystone_exceptions.AuthorizationFailure):
|
keystone_exceptions.AuthorizationFailure):
|
||||||
msg = _('Unable to retrieve authorized domains.')
|
msg = _('Unable to retrieve authorized domains.')
|
||||||
@ -203,8 +194,6 @@ class BasePlugin(object):
|
|||||||
session = utils.get_session()
|
session = utils.get_session()
|
||||||
auth_url = unscoped_auth.auth_url
|
auth_url = unscoped_auth.auth_url
|
||||||
|
|
||||||
if utils.get_keystone_version() < 3:
|
|
||||||
return None, None
|
|
||||||
if domain_name:
|
if domain_name:
|
||||||
domains = [domain_name]
|
domains = [domain_name]
|
||||||
else:
|
else:
|
||||||
|
@ -44,10 +44,8 @@ class K2KAuthPlugin(base.BasePlugin):
|
|||||||
|
|
||||||
# Avoid mutable default arg for plugins
|
# Avoid mutable default arg for plugins
|
||||||
plugins = plugins or []
|
plugins = plugins or []
|
||||||
|
if not service_provider:
|
||||||
# service_provider being None prevents infinite recursion
|
return
|
||||||
if utils.get_keystone_version() < 3 or not service_provider:
|
|
||||||
return None
|
|
||||||
|
|
||||||
keystone_idp_id = settings.KEYSTONE_PROVIDER_IDP_ID
|
keystone_idp_id = settings.KEYSTONE_PROVIDER_IDP_ID
|
||||||
if service_provider == keystone_idp_id:
|
if service_provider == keystone_idp_id:
|
||||||
|
@ -12,11 +12,9 @@
|
|||||||
|
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
from keystoneauth1.identity import v2 as v2_auth
|
|
||||||
from keystoneauth1.identity import v3 as v3_auth
|
from keystoneauth1.identity import v3 as v3_auth
|
||||||
|
|
||||||
from openstack_auth.plugin import base
|
from openstack_auth.plugin import base
|
||||||
from openstack_auth import utils
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
@ -38,14 +36,8 @@ class PasswordPlugin(base.BasePlugin):
|
|||||||
|
|
||||||
LOG.debug('Attempting to authenticate for %s', username)
|
LOG.debug('Attempting to authenticate for %s', username)
|
||||||
|
|
||||||
if utils.get_keystone_version() >= 3:
|
return v3_auth.Password(auth_url=auth_url,
|
||||||
return v3_auth.Password(auth_url=auth_url,
|
username=username,
|
||||||
username=username,
|
password=password,
|
||||||
password=password,
|
user_domain_name=user_domain_name,
|
||||||
user_domain_name=user_domain_name,
|
unscoped=True)
|
||||||
unscoped=True)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return v2_auth.Password(auth_url=auth_url,
|
|
||||||
username=username,
|
|
||||||
password=password)
|
|
||||||
|
@ -10,11 +10,9 @@
|
|||||||
# 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 keystoneauth1.identity import v2 as v2_auth
|
|
||||||
from keystoneauth1.identity import v3 as v3_auth
|
from keystoneauth1.identity import v3 as v3_auth
|
||||||
|
|
||||||
from openstack_auth.plugin import base
|
from openstack_auth.plugin import base
|
||||||
from openstack_auth import utils
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ['TokenPlugin']
|
__all__ = ['TokenPlugin']
|
||||||
@ -28,14 +26,7 @@ class TokenPlugin(base.BasePlugin):
|
|||||||
if not all((auth_url, token)):
|
if not all((auth_url, token)):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
if utils.get_keystone_version() >= 3:
|
return v3_auth.Token(auth_url=auth_url,
|
||||||
return v3_auth.Token(auth_url=auth_url,
|
token=token,
|
||||||
token=token,
|
project_id=project_id,
|
||||||
project_id=project_id,
|
reauthenticate=False)
|
||||||
reauthenticate=False)
|
|
||||||
|
|
||||||
else:
|
|
||||||
return v2_auth.Token(auth_url=auth_url,
|
|
||||||
token=token,
|
|
||||||
tenant_id=project_id,
|
|
||||||
reauthenticate=False)
|
|
||||||
|
@ -1,143 +0,0 @@
|
|||||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
# you may not use this file except in compliance with the License.
|
|
||||||
# You may obtain a copy of the License at
|
|
||||||
#
|
|
||||||
# http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
#
|
|
||||||
# Unless required by applicable law or agreed to in writing, software
|
|
||||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
# implied.
|
|
||||||
# See the License for the specific language governing permissions and
|
|
||||||
# limitations under the License.
|
|
||||||
|
|
||||||
import datetime
|
|
||||||
import uuid
|
|
||||||
|
|
||||||
from django.utils import datetime_safe
|
|
||||||
from keystoneauth1.access import access
|
|
||||||
from keystoneauth1.access import service_catalog
|
|
||||||
from keystoneclient.v2_0 import roles
|
|
||||||
from keystoneclient.v2_0 import tenants
|
|
||||||
from keystoneclient.v2_0 import users
|
|
||||||
|
|
||||||
|
|
||||||
class TestDataContainer(object):
|
|
||||||
"""Arbitrary holder for test data in an object-oriented fashion."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
def generate_test_data():
|
|
||||||
'''Builds a set of test_data data as returned by Keystone V2.'''
|
|
||||||
test_data = TestDataContainer()
|
|
||||||
|
|
||||||
keystone_service = {
|
|
||||||
'type': 'identity',
|
|
||||||
'name': 'keystone',
|
|
||||||
'endpoints_links': [],
|
|
||||||
'endpoints': [
|
|
||||||
{
|
|
||||||
'region': 'RegionOne',
|
|
||||||
'adminURL': 'http://admin.localhost:35357/v2.0',
|
|
||||||
'internalURL': 'http://internal.localhost:5000/v2.0',
|
|
||||||
'publicURL': 'http://public.localhost:5000/v2.0'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Users
|
|
||||||
user_dict = {'id': uuid.uuid4().hex,
|
|
||||||
'name': 'gabriel',
|
|
||||||
'email': 'gabriel@example.com',
|
|
||||||
'password': 'swordfish',
|
|
||||||
'token': '',
|
|
||||||
'enabled': True}
|
|
||||||
test_data.user = users.User(None, user_dict, loaded=True)
|
|
||||||
|
|
||||||
# Tenants
|
|
||||||
tenant_dict_1 = {'id': uuid.uuid4().hex,
|
|
||||||
'name': 'tenant_one',
|
|
||||||
'description': '',
|
|
||||||
'enabled': True}
|
|
||||||
tenant_dict_2 = {'id': uuid.uuid4().hex,
|
|
||||||
'name': 'tenant_two',
|
|
||||||
'description': '',
|
|
||||||
'enabled': False}
|
|
||||||
test_data.tenant_one = tenants.Tenant(None, tenant_dict_1, loaded=True)
|
|
||||||
test_data.tenant_two = tenants.Tenant(None, tenant_dict_2, loaded=True)
|
|
||||||
|
|
||||||
nova_service = {
|
|
||||||
'type': 'compute',
|
|
||||||
'name': 'nova',
|
|
||||||
'endpoint_links': [],
|
|
||||||
'endpoints': [
|
|
||||||
{
|
|
||||||
'region': 'RegionOne',
|
|
||||||
'adminURL': ('http://nova-admin.localhost:8774/v2.0/%s'
|
|
||||||
% (tenant_dict_1['id'])),
|
|
||||||
'internalURL': ('http://nova-internal.localhost:8774/v2.0/%s'
|
|
||||||
% (tenant_dict_1['id'])),
|
|
||||||
'publicURL': ('http://nova-public.localhost:8774/v2.0/%s'
|
|
||||||
% (tenant_dict_1['id']))
|
|
||||||
},
|
|
||||||
{
|
|
||||||
'region': 'RegionTwo',
|
|
||||||
'adminURL': ('http://nova2-admin.localhost:8774/v2.0/%s'
|
|
||||||
% (tenant_dict_1['id'])),
|
|
||||||
'internalURL': ('http://nova2-internal.localhost:8774/v2.0/%s'
|
|
||||||
% (tenant_dict_1['id'])),
|
|
||||||
'publicURL': ('http://nova2-public.localhost:8774/v2.0/%s'
|
|
||||||
% (tenant_dict_1['id']))
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
|
|
||||||
# Roles
|
|
||||||
role_dict = {'id': uuid.uuid4().hex,
|
|
||||||
'name': 'Member'}
|
|
||||||
test_data.role = roles.Role(roles.RoleManager, role_dict)
|
|
||||||
|
|
||||||
# Tokens
|
|
||||||
tomorrow = datetime_safe.datetime.now() + datetime.timedelta(days=1)
|
|
||||||
expiration = datetime_safe.datetime.isoformat(tomorrow)
|
|
||||||
|
|
||||||
scoped_token_dict = {
|
|
||||||
'access': {
|
|
||||||
'token': {
|
|
||||||
'id': uuid.uuid4().hex,
|
|
||||||
'expires': expiration,
|
|
||||||
'tenant': tenant_dict_1,
|
|
||||||
'tenants': [tenant_dict_1, tenant_dict_2]},
|
|
||||||
'user': {
|
|
||||||
'id': user_dict['id'],
|
|
||||||
'name': user_dict['name'],
|
|
||||||
'roles': [role_dict]},
|
|
||||||
'serviceCatalog': [keystone_service, nova_service]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
test_data.scoped_access_info = access.create(
|
|
||||||
resp=None,
|
|
||||||
body=scoped_token_dict)
|
|
||||||
|
|
||||||
unscoped_token_dict = {
|
|
||||||
'access': {
|
|
||||||
'token': {
|
|
||||||
'id': uuid.uuid4().hex,
|
|
||||||
'expires': expiration},
|
|
||||||
'user': {
|
|
||||||
'id': user_dict['id'],
|
|
||||||
'name': user_dict['name'],
|
|
||||||
'roles': [role_dict]},
|
|
||||||
'serviceCatalog': [keystone_service]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
test_data.unscoped_access_info = access.create(
|
|
||||||
resp=None,
|
|
||||||
body=unscoped_token_dict)
|
|
||||||
|
|
||||||
# Service Catalog
|
|
||||||
test_data.service_catalog = service_catalog.ServiceCatalogV2(
|
|
||||||
[keystone_service, nova_service])
|
|
||||||
|
|
||||||
return test_data
|
|
@ -19,16 +19,13 @@ from django import test
|
|||||||
from django.test.utils import override_settings
|
from django.test.utils import override_settings
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from keystoneauth1 import exceptions as keystone_exceptions
|
from keystoneauth1 import exceptions as keystone_exceptions
|
||||||
from keystoneauth1.identity import v2 as v2_auth
|
|
||||||
from keystoneauth1.identity import v3 as v3_auth
|
from keystoneauth1.identity import v3 as v3_auth
|
||||||
from keystoneauth1 import session
|
from keystoneauth1 import session
|
||||||
from keystoneauth1 import token_endpoint
|
from keystoneauth1 import token_endpoint
|
||||||
from keystoneclient.v2_0 import client as client_v2
|
|
||||||
from keystoneclient.v3 import client as client_v3
|
from keystoneclient.v3 import client as client_v3
|
||||||
from mox3 import mox
|
from mox3 import mox
|
||||||
from testscenarios import load_tests_apply_scenarios
|
from testscenarios import load_tests_apply_scenarios
|
||||||
|
|
||||||
from openstack_auth.tests import data_v2
|
|
||||||
from openstack_auth.tests import data_v3
|
from openstack_auth.tests import data_v3
|
||||||
from openstack_auth import utils
|
from openstack_auth import utils
|
||||||
|
|
||||||
@ -143,333 +140,6 @@ class OpenStackAuthFederatedTestsMixin(object):
|
|||||||
self._mock_unscoped_list_domains(client, domains)
|
self._mock_unscoped_list_domains(client, domains)
|
||||||
|
|
||||||
|
|
||||||
class OpenStackAuthTestsV2(OpenStackAuthTestsMixin, test.TestCase):
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
super(OpenStackAuthTestsV2, self).setUp()
|
|
||||||
|
|
||||||
if getattr(self, 'interface', None):
|
|
||||||
override = self.settings(OPENSTACK_ENDPOINT_TYPE=self.interface)
|
|
||||||
override.enable()
|
|
||||||
self.addCleanup(override.disable)
|
|
||||||
|
|
||||||
self.mox = mox.Mox()
|
|
||||||
self.addCleanup(self.mox.VerifyAll)
|
|
||||||
self.addCleanup(self.mox.UnsetStubs)
|
|
||||||
|
|
||||||
self.data = data_v2.generate_test_data()
|
|
||||||
self.ks_client_module = client_v2
|
|
||||||
|
|
||||||
settings.OPENSTACK_API_VERSIONS['identity'] = 2.0
|
|
||||||
settings.OPENSTACK_KEYSTONE_URL = "http://localhost:5000/v2.0"
|
|
||||||
|
|
||||||
self.mox.StubOutClassWithMocks(token_endpoint, 'Token')
|
|
||||||
self.mox.StubOutClassWithMocks(v2_auth, 'Token')
|
|
||||||
self.mox.StubOutClassWithMocks(v2_auth, 'Password')
|
|
||||||
self.mox.StubOutClassWithMocks(client_v2, 'Client')
|
|
||||||
|
|
||||||
def _mock_unscoped_list_tenants(self, client, tenants):
|
|
||||||
client.tenants = self.mox.CreateMockAnything()
|
|
||||||
client.tenants.list().AndReturn(tenants)
|
|
||||||
|
|
||||||
def _mock_unscoped_client_list_tenants(self, user, tenants):
|
|
||||||
client = self._mock_unscoped_client(user)
|
|
||||||
self._mock_unscoped_list_tenants(client, tenants)
|
|
||||||
|
|
||||||
def _create_password_auth(self, username=None, password=None, url=None):
|
|
||||||
if not username:
|
|
||||||
username = self.data.user.name
|
|
||||||
|
|
||||||
if not password:
|
|
||||||
password = self.data.user.password
|
|
||||||
|
|
||||||
if not url:
|
|
||||||
url = settings.OPENSTACK_KEYSTONE_URL
|
|
||||||
|
|
||||||
return v2_auth.Password(auth_url=url,
|
|
||||||
password=password,
|
|
||||||
username=username)
|
|
||||||
|
|
||||||
def _create_token_auth(self, project_id, token=None, url=None):
|
|
||||||
if not token:
|
|
||||||
token = self.data.unscoped_access_info.auth_token
|
|
||||||
|
|
||||||
if not url:
|
|
||||||
url = settings.OPENSTACK_KEYSTONE_URL
|
|
||||||
|
|
||||||
return v2_auth.Token(auth_url=url,
|
|
||||||
token=token,
|
|
||||||
tenant_id=project_id,
|
|
||||||
reauthenticate=False)
|
|
||||||
|
|
||||||
def _login(self):
|
|
||||||
tenants = [self.data.tenant_one, self.data.tenant_two]
|
|
||||||
user = self.data.user
|
|
||||||
unscoped = self.data.unscoped_access_info
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
self._mock_unscoped_client_list_tenants(user, tenants)
|
|
||||||
self._mock_scoped_client_for_tenant(unscoped, self.data.tenant_one.id)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
# GET the page to set the test cookie.
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
# POST to the page to log in.
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
|
|
||||||
|
|
||||||
def test_login(self):
|
|
||||||
self._login()
|
|
||||||
|
|
||||||
def test_login_with_disabled_tenant(self):
|
|
||||||
# Test to validate that authentication will not try to get
|
|
||||||
# scoped token for disabled project.
|
|
||||||
tenants = [self.data.tenant_two, self.data.tenant_one]
|
|
||||||
user = self.data.user
|
|
||||||
unscoped = self.data.unscoped_access_info
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
self._mock_unscoped_client_list_tenants(user, tenants)
|
|
||||||
self._mock_scoped_client_for_tenant(unscoped, self.data.tenant_one.id)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
# GET the page to set the test cookie.
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
# POST to the page to log in.
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
|
|
||||||
|
|
||||||
def test_login_w_bad_region_cookie(self):
|
|
||||||
self.client.cookies['services_region'] = "bad_region"
|
|
||||||
self._login()
|
|
||||||
self.assertNotEqual("bad_region",
|
|
||||||
self.client.session['services_region'])
|
|
||||||
self.assertEqual("RegionOne",
|
|
||||||
self.client.session['services_region'])
|
|
||||||
|
|
||||||
def test_no_enabled_tenants(self):
|
|
||||||
tenants = [self.data.tenant_two]
|
|
||||||
user = self.data.user
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
self._mock_unscoped_client_list_tenants(user, tenants)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
# GET the page to set the test cookie.
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
# POST to the page to log in.
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertTemplateUsed(response, 'auth/login.html')
|
|
||||||
self.assertContains(response,
|
|
||||||
'You are not authorized for any projects.')
|
|
||||||
|
|
||||||
def test_no_tenants(self):
|
|
||||||
user = self.data.user
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
self._mock_unscoped_client_list_tenants(user, [])
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
# GET the page to set the test cookie.
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
# POST to the page to log in.
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertTemplateUsed(response, 'auth/login.html')
|
|
||||||
self.assertContains(response,
|
|
||||||
'You are not authorized for any projects.')
|
|
||||||
|
|
||||||
def test_invalid_credentials(self):
|
|
||||||
user = self.data.user
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
form_data['password'] = "invalid"
|
|
||||||
|
|
||||||
exc = keystone_exceptions.Unauthorized(401)
|
|
||||||
self._mock_client_password_auth_failure(user.name, "invalid", exc)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
# GET the page to set the test cookie.
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
# POST to the page to log in.
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertTemplateUsed(response, 'auth/login.html')
|
|
||||||
self.assertContains(response, "Invalid credentials.")
|
|
||||||
|
|
||||||
def test_exception(self):
|
|
||||||
user = self.data.user
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
exc = keystone_exceptions.ClientException(500)
|
|
||||||
self._mock_client_password_auth_failure(user.name, user.password, exc)
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
# GET the page to set the test cookie.
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
# POST to the page to log in.
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
|
|
||||||
self.assertTemplateUsed(response, 'auth/login.html')
|
|
||||||
self.assertContains(response,
|
|
||||||
("An error occurred authenticating. Please try "
|
|
||||||
"again later."))
|
|
||||||
|
|
||||||
def test_redirect_when_already_logged_in(self):
|
|
||||||
self._login()
|
|
||||||
|
|
||||||
response = self.client.get(reverse('login'))
|
|
||||||
self.assertEqual(response.status_code, 302)
|
|
||||||
self.assertNotIn(reverse('login'), response['location'])
|
|
||||||
|
|
||||||
def test_dont_redirect_when_already_logged_in_if_next_is_set(self):
|
|
||||||
self._login()
|
|
||||||
|
|
||||||
expected_url = "%s?%s=/%s/" % (reverse('login'),
|
|
||||||
auth.REDIRECT_FIELD_NAME,
|
|
||||||
'special')
|
|
||||||
|
|
||||||
response = self.client.get(expected_url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertTemplateUsed(response, 'auth/login.html')
|
|
||||||
|
|
||||||
def test_switch(self, next=None):
|
|
||||||
tenant = self.data.tenant_two
|
|
||||||
tenants = [self.data.tenant_one, self.data.tenant_two]
|
|
||||||
user = self.data.user
|
|
||||||
unscoped = self.data.unscoped_access_info
|
|
||||||
scoped = self.data.scoped_access_info
|
|
||||||
sc = self.data.service_catalog
|
|
||||||
et = getattr(settings, 'OPENSTACK_ENDPOINT_TYPE', 'publicURL')
|
|
||||||
endpoint = sc.url_for(service_type='identity', interface=et)
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
|
|
||||||
self._mock_unscoped_client_list_tenants(user, tenants)
|
|
||||||
self._mock_scoped_client_for_tenant(unscoped, self.data.tenant_one.id)
|
|
||||||
self._mock_scoped_client_for_tenant(scoped, tenant.id, url=endpoint,
|
|
||||||
client=False)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
|
|
||||||
|
|
||||||
url = reverse('switch_tenants', args=[tenant.id])
|
|
||||||
|
|
||||||
scoped._token['tenant']['id'] = self.data.tenant_two.id
|
|
||||||
|
|
||||||
if next:
|
|
||||||
form_data.update({auth.REDIRECT_FIELD_NAME: next})
|
|
||||||
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
|
|
||||||
if next:
|
|
||||||
expected_url = next
|
|
||||||
self.assertEqual(response['location'], expected_url)
|
|
||||||
else:
|
|
||||||
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
|
|
||||||
|
|
||||||
self.assertEqual(self.client.session['token'].tenant['id'],
|
|
||||||
scoped.tenant_id)
|
|
||||||
|
|
||||||
def test_switch_with_next(self):
|
|
||||||
self.test_switch(next='/next_url')
|
|
||||||
|
|
||||||
def test_switch_region(self, next=None):
|
|
||||||
tenants = [self.data.tenant_one, self.data.tenant_two]
|
|
||||||
user = self.data.user
|
|
||||||
scoped = self.data.scoped_access_info
|
|
||||||
sc = self.data.service_catalog
|
|
||||||
|
|
||||||
form_data = self.get_form_data(user)
|
|
||||||
|
|
||||||
self._mock_unscoped_client_list_tenants(user, tenants)
|
|
||||||
self._mock_scoped_client_for_tenant(scoped, self.data.tenant_one.id)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
url = reverse('login')
|
|
||||||
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
|
|
||||||
response = self.client.post(url, form_data)
|
|
||||||
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
|
|
||||||
|
|
||||||
old_region = sc.get_endpoints()['compute'][0]['region']
|
|
||||||
self.assertEqual(self.client.session['services_region'], old_region)
|
|
||||||
|
|
||||||
region = sc.get_endpoints()['compute'][1]['region']
|
|
||||||
url = reverse('switch_services_region', args=[region])
|
|
||||||
|
|
||||||
form_data['region_name'] = region
|
|
||||||
|
|
||||||
if next:
|
|
||||||
form_data.update({auth.REDIRECT_FIELD_NAME: next})
|
|
||||||
|
|
||||||
response = self.client.get(url, form_data)
|
|
||||||
|
|
||||||
if next:
|
|
||||||
expected_url = next
|
|
||||||
self.assertEqual(response['location'], expected_url)
|
|
||||||
else:
|
|
||||||
self.assertRedirects(response, settings.LOGIN_REDIRECT_URL)
|
|
||||||
|
|
||||||
self.assertEqual(self.client.session['services_region'], region)
|
|
||||||
self.assertEqual(self.client.cookies['services_region'].value, region)
|
|
||||||
|
|
||||||
def test_switch_region_with_next(self, next=None):
|
|
||||||
self.test_switch_region(next='/next_url')
|
|
||||||
|
|
||||||
def test_tenant_sorting(self):
|
|
||||||
tenants = [self.data.tenant_two, self.data.tenant_one]
|
|
||||||
expected_tenants = [self.data.tenant_one, self.data.tenant_two]
|
|
||||||
user = self.data.user
|
|
||||||
unscoped = self.data.unscoped_access_info
|
|
||||||
|
|
||||||
client = self._mock_unscoped_client_with_token(user, unscoped)
|
|
||||||
self._mock_unscoped_list_tenants(client, tenants)
|
|
||||||
|
|
||||||
self.mox.ReplayAll()
|
|
||||||
|
|
||||||
tenant_list = utils.get_project_list(
|
|
||||||
user_id=user.id,
|
|
||||||
auth_url=settings.OPENSTACK_KEYSTONE_URL,
|
|
||||||
token=unscoped.auth_token)
|
|
||||||
self.assertEqual(tenant_list, expected_tenants)
|
|
||||||
|
|
||||||
|
|
||||||
class OpenStackAuthTestsV3(OpenStackAuthTestsMixin,
|
class OpenStackAuthTestsV3(OpenStackAuthTestsMixin,
|
||||||
OpenStackAuthFederatedTestsMixin,
|
OpenStackAuthFederatedTestsMixin,
|
||||||
test.TestCase):
|
test.TestCase):
|
||||||
|
@ -11,7 +11,6 @@
|
|||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
|
||||||
from django.conf import settings
|
|
||||||
from django import http
|
from django import http
|
||||||
from django import test
|
from django import test
|
||||||
from django.test import client
|
from django.test import client
|
||||||
@ -55,41 +54,6 @@ class RoleTestCaseAdmin(test.TestCase):
|
|||||||
|
|
||||||
class UtilsTestCase(test.TestCase):
|
class UtilsTestCase(test.TestCase):
|
||||||
|
|
||||||
def test_fix_auth_url_version_v20(self):
|
|
||||||
settings.OPENSTACK_API_VERSIONS['identity'] = 2.0
|
|
||||||
test_urls = [
|
|
||||||
("http://a/", ("http://a/v2.0", False)),
|
|
||||||
("http://a", ("http://a/v2.0", False)),
|
|
||||||
("http://a:8080/", ("http://a:8080/v2.0", False)),
|
|
||||||
("http://a/v2.0", ("http://a/v2.0", False)),
|
|
||||||
("http://a/v2.0/", ("http://a/v2.0/", False)),
|
|
||||||
("http://a/identity", ("http://a/identity/v2.0", False)),
|
|
||||||
("http://a/identity/", ("http://a/identity/v2.0", False)),
|
|
||||||
("http://a:5000/identity/v2.0",
|
|
||||||
("http://a:5000/identity/v2.0", False)),
|
|
||||||
("http://a/identity/v2.0/", ("http://a/identity/v2.0/", False))
|
|
||||||
]
|
|
||||||
for src, expected in test_urls:
|
|
||||||
self.assertEqual(expected, utils.fix_auth_url_version_prefix(src))
|
|
||||||
|
|
||||||
def test_fix_auth_url_version_v3(self):
|
|
||||||
settings.OPENSTACK_API_VERSIONS['identity'] = 3
|
|
||||||
test_urls = [
|
|
||||||
("http://a/", ("http://a/v3", False)),
|
|
||||||
("http://a", ("http://a/v3", False)),
|
|
||||||
("http://a:8080/", ("http://a:8080/v3", False)),
|
|
||||||
("http://a/v3", ("http://a/v3", False)),
|
|
||||||
("http://a/v3/", ("http://a/v3/", False)),
|
|
||||||
("http://a/v2.0/", ("http://a/v3/", True)),
|
|
||||||
("http://a/v2.0", ("http://a/v3", True)),
|
|
||||||
("http://a/identity", ("http://a/identity/v3", False)),
|
|
||||||
("http://a:5000/identity/", ("http://a:5000/identity/v3", False)),
|
|
||||||
("http://a/identity/v3", ("http://a/identity/v3", False)),
|
|
||||||
("http://a/identity/v3/", ("http://a/identity/v3/", False))
|
|
||||||
]
|
|
||||||
for src, expected in test_urls:
|
|
||||||
self.assertEqual(expected, utils.fix_auth_url_version_prefix(src))
|
|
||||||
|
|
||||||
@override_settings(DEFAULT_SERVICE_REGIONS={
|
@override_settings(DEFAULT_SERVICE_REGIONS={
|
||||||
'http://example.com': 'RegionThree', '*': 'RegionFour'})
|
'http://example.com': 'RegionThree', '*': 'RegionFour'})
|
||||||
def test_default_services_region_precedence(self):
|
def test_default_services_region_precedence(self):
|
||||||
|
@ -19,11 +19,9 @@ from django.conf import settings
|
|||||||
from django.contrib import auth
|
from django.contrib import auth
|
||||||
from django.contrib.auth import models
|
from django.contrib.auth import models
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from keystoneauth1.identity import v2 as v2_auth
|
|
||||||
from keystoneauth1.identity import v3 as v3_auth
|
from keystoneauth1.identity import v3 as v3_auth
|
||||||
from keystoneauth1 import session
|
from keystoneauth1 import session
|
||||||
from keystoneauth1 import token_endpoint
|
from keystoneauth1 import token_endpoint
|
||||||
from keystoneclient.v2_0 import client as client_v2
|
|
||||||
from keystoneclient.v3 import client as client_v3
|
from keystoneclient.v3 import client as client_v3
|
||||||
from six.moves.urllib import parse as urlparse
|
from six.moves.urllib import parse as urlparse
|
||||||
|
|
||||||
@ -116,17 +114,12 @@ def get_session():
|
|||||||
|
|
||||||
|
|
||||||
def get_keystone_client():
|
def get_keystone_client():
|
||||||
if get_keystone_version() < 3:
|
return client_v3
|
||||||
return client_v2
|
|
||||||
else:
|
|
||||||
return client_v3
|
|
||||||
|
|
||||||
|
|
||||||
def is_websso_enabled():
|
def is_websso_enabled():
|
||||||
"""Websso is supported in Keystone version 3."""
|
"""Websso is supported in Keystone version 3."""
|
||||||
websso_enabled = settings.WEBSSO_ENABLED
|
return settings.WEBSSO_ENABLED
|
||||||
keystonev3_plus = (get_keystone_version() >= 3)
|
|
||||||
return websso_enabled and keystonev3_plus
|
|
||||||
|
|
||||||
|
|
||||||
def is_websso_default_redirect():
|
def is_websso_default_redirect():
|
||||||
@ -275,26 +268,24 @@ def _augment_url_with_version(auth_url):
|
|||||||
the identity URLs returned by Keystone might no longer contain API
|
the identity URLs returned by Keystone might no longer contain API
|
||||||
versions, leaving the version choice up to the user.
|
versions, leaving the version choice up to the user.
|
||||||
"""
|
"""
|
||||||
if has_in_url_path(auth_url, ["/v2.0", "/v3"]):
|
if has_in_url_path(auth_url, ["/v3"]):
|
||||||
return auth_url
|
return auth_url
|
||||||
|
|
||||||
if get_keystone_version() >= 3:
|
return url_path_append(auth_url, "/v3")
|
||||||
return url_path_append(auth_url, "/v3")
|
|
||||||
else:
|
|
||||||
return url_path_append(auth_url, "/v2.0")
|
|
||||||
|
|
||||||
|
|
||||||
def fix_auth_url_version_prefix(auth_url):
|
def fix_auth_url_version_prefix(auth_url):
|
||||||
"""Fix up the auth url if an invalid or no version prefix was given.
|
"""Fix up the auth url if an invalid or no version prefix was given.
|
||||||
|
|
||||||
People still give a v2 auth_url even when they specify that they want v3
|
Fix the URL to say v3 in this case and add version if it is
|
||||||
authentication. Fix the URL to say v3 in this case and add version if it is
|
|
||||||
missing entirely. This should be smarter and use discovery.
|
missing entirely. This should be smarter and use discovery.
|
||||||
|
Until version discovery is implemented we need this method to get
|
||||||
|
everything working.
|
||||||
"""
|
"""
|
||||||
auth_url = _augment_url_with_version(auth_url)
|
auth_url = _augment_url_with_version(auth_url)
|
||||||
|
|
||||||
url_fixed = False
|
url_fixed = False
|
||||||
if get_keystone_version() >= 3 and has_in_url_path(auth_url, ["/v2.0"]):
|
if has_in_url_path(auth_url, ["/v2.0"]):
|
||||||
url_fixed = True
|
url_fixed = True
|
||||||
auth_url = url_path_replace(auth_url, "/v2.0", "/v3", 1)
|
auth_url = url_path_replace(auth_url, "/v2.0", "/v3", 1)
|
||||||
|
|
||||||
@ -312,21 +303,15 @@ def clean_up_auth_url(auth_url):
|
|||||||
|
|
||||||
|
|
||||||
def get_token_auth_plugin(auth_url, token, project_id=None, domain_name=None):
|
def get_token_auth_plugin(auth_url, token, project_id=None, domain_name=None):
|
||||||
if get_keystone_version() >= 3:
|
if domain_name:
|
||||||
if domain_name:
|
return v3_auth.Token(auth_url=auth_url,
|
||||||
return v3_auth.Token(auth_url=auth_url,
|
|
||||||
token=token,
|
|
||||||
domain_name=domain_name,
|
|
||||||
reauthenticate=False)
|
|
||||||
else:
|
|
||||||
return v3_auth.Token(auth_url=auth_url,
|
|
||||||
token=token,
|
|
||||||
project_id=project_id,
|
|
||||||
reauthenticate=False)
|
|
||||||
else:
|
|
||||||
return v2_auth.Token(auth_url=auth_url,
|
|
||||||
token=token,
|
token=token,
|
||||||
tenant_id=project_id,
|
domain_name=domain_name,
|
||||||
|
reauthenticate=False)
|
||||||
|
else:
|
||||||
|
return v3_auth.Token(auth_url=auth_url,
|
||||||
|
token=token,
|
||||||
|
project_id=project_id,
|
||||||
reauthenticate=False)
|
reauthenticate=False)
|
||||||
|
|
||||||
|
|
||||||
|
@ -33,12 +33,10 @@ from openstack_auth import backend
|
|||||||
from openstack_auth import utils as auth_utils
|
from openstack_auth import utils as auth_utils
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import messages
|
|
||||||
|
|
||||||
from openstack_dashboard.api import base
|
from openstack_dashboard.api import base
|
||||||
from openstack_dashboard.contrib.developer.profiler import api as profiler
|
from openstack_dashboard.contrib.developer.profiler import api as profiler
|
||||||
from openstack_dashboard import policy
|
from openstack_dashboard import policy
|
||||||
from openstack_dashboard.utils import settings as utils
|
|
||||||
|
|
||||||
|
|
||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
@ -56,25 +54,13 @@ class IdentityAPIVersionManager(base.APIVersionManager):
|
|||||||
return user
|
return user
|
||||||
|
|
||||||
def get_project_manager(self, *args, **kwargs):
|
def get_project_manager(self, *args, **kwargs):
|
||||||
if VERSIONS.active < 3:
|
return keystoneclient(*args, **kwargs).projects
|
||||||
manager = keystoneclient(*args, **kwargs).tenants
|
|
||||||
else:
|
|
||||||
manager = keystoneclient(*args, **kwargs).projects
|
|
||||||
return manager
|
|
||||||
|
|
||||||
|
|
||||||
VERSIONS = IdentityAPIVersionManager(
|
VERSIONS = IdentityAPIVersionManager(
|
||||||
"identity", preferred_version=auth_utils.get_keystone_version())
|
"identity", preferred_version=auth_utils.get_keystone_version())
|
||||||
|
|
||||||
|
|
||||||
# Import from oldest to newest so that "preferred" takes correct precedence.
|
|
||||||
try:
|
|
||||||
# pylint: disable=ungrouped-imports
|
|
||||||
from keystoneclient.v2_0 import client as keystone_client_v2
|
|
||||||
VERSIONS.load_supported_version(2.0, {"client": keystone_client_v2})
|
|
||||||
except ImportError:
|
|
||||||
pass
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
# pylint: disable=ungrouped-imports
|
# pylint: disable=ungrouped-imports
|
||||||
from keystoneclient.v3 import client as keystone_client_v3
|
from keystoneclient.v3 import client as keystone_client_v3
|
||||||
@ -266,12 +252,9 @@ def tenant_create(request, name, description=None, enabled=None,
|
|||||||
domain=None, **kwargs):
|
domain=None, **kwargs):
|
||||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||||
try:
|
try:
|
||||||
if VERSIONS.active < 3:
|
return manager.create(name, domain,
|
||||||
return manager.create(name, description, enabled, **kwargs)
|
description=description,
|
||||||
else:
|
enabled=enabled, **kwargs)
|
||||||
return manager.create(name, domain,
|
|
||||||
description=description,
|
|
||||||
enabled=enabled, **kwargs)
|
|
||||||
except keystone_exceptions.Conflict:
|
except keystone_exceptions.Conflict:
|
||||||
raise exceptions.Conflict()
|
raise exceptions.Conflict()
|
||||||
|
|
||||||
@ -364,25 +347,13 @@ def tenant_delete(request, project):
|
|||||||
def tenant_list(request, paginate=False, marker=None, domain=None, user=None,
|
def tenant_list(request, paginate=False, marker=None, domain=None, user=None,
|
||||||
admin=True, filters=None):
|
admin=True, filters=None):
|
||||||
manager = VERSIONS.get_project_manager(request, admin=admin)
|
manager = VERSIONS.get_project_manager(request, admin=admin)
|
||||||
page_size = utils.get_page_size(request)
|
|
||||||
tenants = []
|
tenants = []
|
||||||
limit = None
|
|
||||||
if paginate:
|
|
||||||
limit = page_size + 1
|
|
||||||
|
|
||||||
has_more_data = False
|
has_more_data = False
|
||||||
|
|
||||||
# if requesting the projects for the current user,
|
# if requesting the projects for the current user,
|
||||||
# return the list from the cache
|
# return the list from the cache
|
||||||
if user == request.user.id:
|
if user == request.user.id:
|
||||||
tenants = request.user.authorized_tenants
|
tenants = request.user.authorized_tenants
|
||||||
|
|
||||||
elif VERSIONS.active < 3:
|
|
||||||
tenants = manager.list(limit, marker)
|
|
||||||
if paginate and len(tenants) > page_size:
|
|
||||||
tenants.pop(-1)
|
|
||||||
has_more_data = True
|
|
||||||
# V3 API
|
|
||||||
else:
|
else:
|
||||||
domain_id = get_effective_domain_id(request)
|
domain_id = get_effective_domain_id(request)
|
||||||
kwargs = {
|
kwargs = {
|
||||||
@ -408,12 +379,8 @@ def tenant_update(request, project, name=None, description=None,
|
|||||||
enabled=None, domain=None, **kwargs):
|
enabled=None, domain=None, **kwargs):
|
||||||
manager = VERSIONS.get_project_manager(request, admin=True)
|
manager = VERSIONS.get_project_manager(request, admin=True)
|
||||||
try:
|
try:
|
||||||
if VERSIONS.active < 3:
|
return manager.update(project, name=name, description=description,
|
||||||
return manager.update(project, name, description, enabled,
|
enabled=enabled, domain=domain, **kwargs)
|
||||||
**kwargs)
|
|
||||||
else:
|
|
||||||
return manager.update(project, name=name, description=description,
|
|
||||||
enabled=enabled, domain=domain, **kwargs)
|
|
||||||
except keystone_exceptions.Conflict:
|
except keystone_exceptions.Conflict:
|
||||||
raise exceptions.Conflict()
|
raise exceptions.Conflict()
|
||||||
|
|
||||||
@ -421,16 +388,13 @@ def tenant_update(request, project, name=None, description=None,
|
|||||||
@profiler.trace
|
@profiler.trace
|
||||||
def user_list(request, project=None, domain=None, group=None, filters=None):
|
def user_list(request, project=None, domain=None, group=None, filters=None):
|
||||||
users = []
|
users = []
|
||||||
if VERSIONS.active < 3:
|
kwargs = {
|
||||||
kwargs = {"tenant_id": project}
|
"project": project,
|
||||||
else:
|
"domain": domain,
|
||||||
kwargs = {
|
"group": group
|
||||||
"project": project,
|
}
|
||||||
"domain": domain,
|
if filters is not None:
|
||||||
"group": group
|
kwargs.update(filters)
|
||||||
}
|
|
||||||
if filters is not None:
|
|
||||||
kwargs.update(filters)
|
|
||||||
if 'id' in kwargs:
|
if 'id' in kwargs:
|
||||||
try:
|
try:
|
||||||
users = [user_get(request, kwargs['id'])]
|
users = [user_get(request, kwargs['id'])]
|
||||||
@ -446,14 +410,10 @@ def user_create(request, name=None, email=None, password=None, project=None,
|
|||||||
enabled=None, domain=None, description=None, **data):
|
enabled=None, domain=None, description=None, **data):
|
||||||
manager = keystoneclient(request, admin=True).users
|
manager = keystoneclient(request, admin=True).users
|
||||||
try:
|
try:
|
||||||
if VERSIONS.active < 3:
|
return manager.create(name, password=password, email=email,
|
||||||
user = manager.create(name, password, email, project, enabled)
|
default_project=project, enabled=enabled,
|
||||||
return VERSIONS.upgrade_v2_user(user)
|
domain=domain, description=description,
|
||||||
else:
|
**data)
|
||||||
return manager.create(name, password=password, email=email,
|
|
||||||
default_project=project, enabled=enabled,
|
|
||||||
domain=domain, description=description,
|
|
||||||
**data)
|
|
||||||
except keystone_exceptions.Conflict:
|
except keystone_exceptions.Conflict:
|
||||||
raise exceptions.Conflict()
|
raise exceptions.Conflict()
|
||||||
|
|
||||||
@ -472,59 +432,20 @@ def user_get(request, user_id, admin=True):
|
|||||||
@profiler.trace
|
@profiler.trace
|
||||||
def user_update(request, user, **data):
|
def user_update(request, user, **data):
|
||||||
manager = keystoneclient(request, admin=True).users
|
manager = keystoneclient(request, admin=True).users
|
||||||
error = None
|
|
||||||
|
|
||||||
if not keystone_can_edit_user():
|
if not keystone_can_edit_user():
|
||||||
raise keystone_exceptions.ClientException(
|
raise keystone_exceptions.ClientException(
|
||||||
405, _("Identity service does not allow editing user data."))
|
405, _("Identity service does not allow editing user data."))
|
||||||
|
try:
|
||||||
# The v2 API updates user model and default project separately
|
user = manager.update(user, **data)
|
||||||
if VERSIONS.active < 3:
|
except keystone_exceptions.Conflict:
|
||||||
# Update user details
|
raise exceptions.Conflict()
|
||||||
try:
|
|
||||||
user = manager.update(user, **data)
|
|
||||||
except keystone_exceptions.Conflict:
|
|
||||||
raise exceptions.Conflict()
|
|
||||||
except Exception:
|
|
||||||
error = exceptions.handle(request, ignore=True)
|
|
||||||
|
|
||||||
if "project" in data:
|
|
||||||
project = data.pop('project')
|
|
||||||
|
|
||||||
# Update default tenant
|
|
||||||
try:
|
|
||||||
user_update_tenant(request, user, project)
|
|
||||||
user.tenantId = project
|
|
||||||
except Exception:
|
|
||||||
error = exceptions.handle(request, ignore=True)
|
|
||||||
|
|
||||||
# Check for existing roles
|
|
||||||
# Show a warning if no role exists for the project
|
|
||||||
user_roles = roles_for_user(request, user, project)
|
|
||||||
if not user_roles:
|
|
||||||
messages.warning(request,
|
|
||||||
_('User %s has no role defined for '
|
|
||||||
'that project.')
|
|
||||||
% data.get('name', None))
|
|
||||||
|
|
||||||
if error is not None:
|
|
||||||
raise error
|
|
||||||
|
|
||||||
# v3 API is so much simpler...
|
|
||||||
else:
|
|
||||||
try:
|
|
||||||
user = manager.update(user, **data)
|
|
||||||
except keystone_exceptions.Conflict:
|
|
||||||
raise exceptions.Conflict()
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def user_update_enabled(request, user, enabled):
|
def user_update_enabled(request, user, enabled):
|
||||||
manager = keystoneclient(request, admin=True).users
|
manager = keystoneclient(request, admin=True).users
|
||||||
if VERSIONS.active < 3:
|
manager.update(user, enabled=enabled)
|
||||||
manager.update_enabled(user, enabled)
|
|
||||||
else:
|
|
||||||
manager.update(user, enabled=enabled)
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
@ -535,16 +456,13 @@ def user_update_password(request, user, password, admin=True):
|
|||||||
405, _("Identity service does not allow editing user password."))
|
405, _("Identity service does not allow editing user password."))
|
||||||
|
|
||||||
manager = keystoneclient(request, admin=admin).users
|
manager = keystoneclient(request, admin=admin).users
|
||||||
if VERSIONS.active < 3:
|
manager.update(user, password=password)
|
||||||
manager.update_password(user, password)
|
|
||||||
else:
|
|
||||||
manager.update(user, password=password)
|
|
||||||
|
|
||||||
|
|
||||||
def user_verify_admin_password(request, admin_password):
|
def user_verify_admin_password(request, admin_password):
|
||||||
# attempt to create a new client instance with admin password to
|
# attempt to create a new client instance with admin password to
|
||||||
# verify if it's correct.
|
# verify if it's correct.
|
||||||
client = keystone_client_v2 if VERSIONS.active < 3 else keystone_client_v3
|
client = keystone_client_v3
|
||||||
try:
|
try:
|
||||||
endpoint = _get_endpoint_url(request, 'publicURL')
|
endpoint = _get_endpoint_url(request, 'publicURL')
|
||||||
insecure = settings.OPENSTACK_SSL_NO_VERIFY
|
insecure = settings.OPENSTACK_SSL_NO_VERIFY
|
||||||
@ -565,21 +483,14 @@ def user_verify_admin_password(request, admin_password):
|
|||||||
@profiler.trace
|
@profiler.trace
|
||||||
def user_update_own_password(request, origpassword, password):
|
def user_update_own_password(request, origpassword, password):
|
||||||
client = keystoneclient(request, admin=False)
|
client = keystoneclient(request, admin=False)
|
||||||
if VERSIONS.active < 3:
|
client.users.client.session.auth.user_id = request.user.id
|
||||||
client.user_id = request.user.id
|
return client.users.update_password(origpassword, password)
|
||||||
return client.users.update_own_password(origpassword, password)
|
|
||||||
else:
|
|
||||||
client.users.client.session.auth.user_id = request.user.id
|
|
||||||
return client.users.update_password(origpassword, password)
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
def user_update_tenant(request, user, project, admin=True):
|
def user_update_tenant(request, user, project, admin=True):
|
||||||
manager = keystoneclient(request, admin=admin).users
|
manager = keystoneclient(request, admin=admin).users
|
||||||
if VERSIONS.active < 3:
|
return manager.update(user, project=project)
|
||||||
return manager.update_tenant(user, project)
|
|
||||||
else:
|
|
||||||
return manager.update(user, project=project)
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
@ -689,9 +600,6 @@ def get_project_groups_roles(request, project):
|
|||||||
def role_assignments_list(request, project=None, user=None, role=None,
|
def role_assignments_list(request, project=None, user=None, role=None,
|
||||||
group=None, domain=None, effective=False,
|
group=None, domain=None, effective=False,
|
||||||
include_subtree=True, include_names=False):
|
include_subtree=True, include_names=False):
|
||||||
if VERSIONS.active < 3:
|
|
||||||
raise exceptions.NotAvailable
|
|
||||||
|
|
||||||
if include_subtree:
|
if include_subtree:
|
||||||
domain = None
|
domain = None
|
||||||
|
|
||||||
@ -751,10 +659,7 @@ def role_list(request, filters=None):
|
|||||||
def roles_for_user(request, user, project=None, domain=None):
|
def roles_for_user(request, user, project=None, domain=None):
|
||||||
"""Returns a list of user roles scoped to a project or domain."""
|
"""Returns a list of user roles scoped to a project or domain."""
|
||||||
manager = keystoneclient(request, admin=True).roles
|
manager = keystoneclient(request, admin=True).roles
|
||||||
if VERSIONS.active < 3:
|
return manager.list(user=user, domain=domain, project=project)
|
||||||
return manager.roles_for_user(user, project)
|
|
||||||
else:
|
|
||||||
return manager.list(user=user, domain=domain, project=project)
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
@ -793,26 +698,18 @@ def remove_domain_user_role(request, user, role, domain=None):
|
|||||||
@profiler.trace
|
@profiler.trace
|
||||||
def get_project_users_roles(request, project):
|
def get_project_users_roles(request, project):
|
||||||
users_roles = collections.defaultdict(list)
|
users_roles = collections.defaultdict(list)
|
||||||
if VERSIONS.active < 3:
|
project_role_assignments = role_assignments_list(request,
|
||||||
project_users = user_list(request, project=project)
|
project=project)
|
||||||
|
for role_assignment in project_role_assignments:
|
||||||
|
if not hasattr(role_assignment, 'user'):
|
||||||
|
continue
|
||||||
|
user_id = role_assignment.user['id']
|
||||||
|
role_id = role_assignment.role['id']
|
||||||
|
|
||||||
for user in project_users:
|
# filter by project_id
|
||||||
roles = roles_for_user(request, user.id, project)
|
if ('project' in role_assignment.scope and
|
||||||
roles_ids = [role.id for role in roles]
|
role_assignment.scope['project']['id'] == project):
|
||||||
users_roles[user.id].extend(roles_ids)
|
users_roles[user_id].append(role_id)
|
||||||
else:
|
|
||||||
project_role_assignments = role_assignments_list(request,
|
|
||||||
project=project)
|
|
||||||
for role_assignment in project_role_assignments:
|
|
||||||
if not hasattr(role_assignment, 'user'):
|
|
||||||
continue
|
|
||||||
user_id = role_assignment.user['id']
|
|
||||||
role_id = role_assignment.role['id']
|
|
||||||
|
|
||||||
# filter by project_id
|
|
||||||
if ('project' in role_assignment.scope and
|
|
||||||
role_assignment.scope['project']['id'] == project):
|
|
||||||
users_roles[user_id].append(role_id)
|
|
||||||
return users_roles
|
return users_roles
|
||||||
|
|
||||||
|
|
||||||
@ -821,11 +718,8 @@ def add_tenant_user_role(request, project=None, user=None, role=None,
|
|||||||
group=None, domain=None):
|
group=None, domain=None):
|
||||||
"""Adds a role for a user on a tenant."""
|
"""Adds a role for a user on a tenant."""
|
||||||
manager = keystoneclient(request, admin=True).roles
|
manager = keystoneclient(request, admin=True).roles
|
||||||
if VERSIONS.active < 3:
|
manager.grant(role, user=user, project=project,
|
||||||
manager.add_user_role(user, role, project)
|
group=group, domain=domain)
|
||||||
else:
|
|
||||||
manager.grant(role, user=user, project=project,
|
|
||||||
group=group, domain=domain)
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
@ -833,11 +727,8 @@ def remove_tenant_user_role(request, project=None, user=None, role=None,
|
|||||||
group=None, domain=None):
|
group=None, domain=None):
|
||||||
"""Removes a given single role for a user from a tenant."""
|
"""Removes a given single role for a user from a tenant."""
|
||||||
manager = keystoneclient(request, admin=True).roles
|
manager = keystoneclient(request, admin=True).roles
|
||||||
if VERSIONS.active < 3:
|
return manager.revoke(role, user=user, project=project,
|
||||||
return manager.remove_user_role(user, role, project)
|
group=group, domain=domain)
|
||||||
else:
|
|
||||||
return manager.revoke(role, user=user, project=project,
|
|
||||||
group=group, domain=domain)
|
|
||||||
|
|
||||||
|
|
||||||
def remove_tenant_user(request, project=None, user=None, domain=None):
|
def remove_tenant_user(request, project=None, user=None, domain=None):
|
||||||
@ -907,9 +798,8 @@ def ec2_manager(request):
|
|||||||
if hasattr(client, 'ec2'):
|
if hasattr(client, 'ec2'):
|
||||||
return client.ec2
|
return client.ec2
|
||||||
|
|
||||||
# Keystoneclient 4.0 was released without the ec2 creds manager.
|
from keystoneclient.v3 import ec2
|
||||||
from keystoneclient.v2_0 import ec2
|
return ec2.EC2Manager(client)
|
||||||
return ec2.CredentialsManager(client)
|
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
|
@ -128,7 +128,7 @@ def swift_api(request):
|
|||||||
preauthurl=endpoint,
|
preauthurl=endpoint,
|
||||||
cacert=cacert,
|
cacert=cacert,
|
||||||
insecure=insecure,
|
insecure=insecure,
|
||||||
auth_version="2.0")
|
auth_version="3")
|
||||||
|
|
||||||
|
|
||||||
@profiler.trace
|
@profiler.trace
|
||||||
|
@ -19,8 +19,6 @@ from django.urls import reverse
|
|||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openstack_auth import utils
|
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
@ -121,7 +119,6 @@ def _get_context(request):
|
|||||||
auth_url = api.base.url_for(request,
|
auth_url = api.base.url_for(request,
|
||||||
'identity',
|
'identity',
|
||||||
endpoint_type='publicURL')
|
endpoint_type='publicURL')
|
||||||
auth_url, url_fixed = utils.fix_auth_url_version_prefix(auth_url)
|
|
||||||
interface = 'public'
|
interface = 'public'
|
||||||
region = getattr(request.user, 'services_region', '')
|
region = getattr(request.user, 'services_region', '')
|
||||||
app_cred = request.session['application_credential']
|
app_cred = request.session['application_credential']
|
||||||
|
@ -30,9 +30,6 @@ class Domains(horizon.Panel):
|
|||||||
return keystone.VERSIONS.active >= 3
|
return keystone.VERSIONS.active >= 3
|
||||||
|
|
||||||
def can_access(self, context):
|
def can_access(self, context):
|
||||||
if keystone.VERSIONS.active < 3:
|
|
||||||
return super(Domains, self).can_access(context)
|
|
||||||
|
|
||||||
request = context['request']
|
request = context['request']
|
||||||
domain_token = request.session.get('domain_token')
|
domain_token = request.session.get('domain_token')
|
||||||
return super(Domains, self).can_access(context) and domain_token
|
return super(Domains, self).can_access(context) and domain_token
|
||||||
|
@ -149,11 +149,8 @@ class ModifyQuotas(tables.LinkAction):
|
|||||||
policy_rules = (('compute', "os_compute_api:os-quota-sets:update"),)
|
policy_rules = (('compute', "os_compute_api:os-quota-sets:update"),)
|
||||||
|
|
||||||
def allowed(self, request, datum):
|
def allowed(self, request, datum):
|
||||||
if api.keystone.VERSIONS.active < 3:
|
return (api.keystone.is_cloud_admin(request) and
|
||||||
return True
|
quotas.enabled_quotas(request))
|
||||||
else:
|
|
||||||
return (api.keystone.is_cloud_admin(request) and
|
|
||||||
quotas.enabled_quotas(request))
|
|
||||||
|
|
||||||
def get_link_url(self, project):
|
def get_link_url(self, project):
|
||||||
step = 'update_quotas'
|
step = 'update_quotas'
|
||||||
@ -198,13 +195,10 @@ class DeleteTenantsAction(policy.PolicyTargetMixin, tables.DeleteAction):
|
|||||||
|
|
||||||
|
|
||||||
class TenantFilterAction(tables.FilterAction):
|
class TenantFilterAction(tables.FilterAction):
|
||||||
if api.keystone.VERSIONS.active < 3:
|
filter_type = "server"
|
||||||
filter_type = "query"
|
filter_choices = (('name', _("Project Name ="), True),
|
||||||
else:
|
('id', _("Project ID ="), True),
|
||||||
filter_type = "server"
|
('enabled', _("Enabled ="), True, _('e.g. Yes/No')))
|
||||||
filter_choices = (('name', _("Project Name ="), True),
|
|
||||||
('id', _("Project ID ="), True),
|
|
||||||
('enabled', _("Enabled ="), True, _('e.g. Yes/No')))
|
|
||||||
|
|
||||||
|
|
||||||
class UpdateRow(tables.Row):
|
class UpdateRow(tables.Row):
|
||||||
|
@ -21,7 +21,6 @@ from openstack_dashboard import policy
|
|||||||
|
|
||||||
ENABLE = 0
|
ENABLE = 0
|
||||||
DISABLE = 1
|
DISABLE = 1
|
||||||
KEYSTONE_V2_ENABLED = api.keystone.VERSIONS.active < 3
|
|
||||||
|
|
||||||
|
|
||||||
class CreateUserLink(tables.LinkAction):
|
class CreateUserLink(tables.LinkAction):
|
||||||
@ -186,7 +185,6 @@ class UsersTable(tables.DataTable):
|
|||||||
form_field=forms.CharField(required=False))
|
form_field=forms.CharField(required=False))
|
||||||
description = tables.Column(lambda obj: getattr(obj, 'description', None),
|
description = tables.Column(lambda obj: getattr(obj, 'description', None),
|
||||||
verbose_name=_('Description'),
|
verbose_name=_('Description'),
|
||||||
hidden=KEYSTONE_V2_ENABLED,
|
|
||||||
form_field=forms.CharField(
|
form_field=forms.CharField(
|
||||||
widget=forms.Textarea(attrs={'rows': 4}),
|
widget=forms.Textarea(attrs={'rows': 4}),
|
||||||
required=False))
|
required=False))
|
||||||
|
@ -16,8 +16,6 @@ from django.conf import settings
|
|||||||
from django.template.defaultfilters import title
|
from django.template.defaultfilters import title
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openstack_auth import utils
|
|
||||||
|
|
||||||
from horizon import tables
|
from horizon import tables
|
||||||
from openstack_dashboard import api
|
from openstack_dashboard import api
|
||||||
from openstack_dashboard.dashboards.project.api_access import forms
|
from openstack_dashboard.dashboards.project.api_access import forms
|
||||||
@ -63,8 +61,7 @@ class DownloadOpenRC(tables.LinkAction):
|
|||||||
url = "horizon:project:api_access:openrc"
|
url = "horizon:project:api_access:openrc"
|
||||||
|
|
||||||
def allowed(self, request, datum=None):
|
def allowed(self, request, datum=None):
|
||||||
return (settings.SHOW_OPENRC_FILE and
|
return settings.SHOW_OPENRC_FILE
|
||||||
utils.get_keystone_version() >= 3)
|
|
||||||
|
|
||||||
|
|
||||||
class ViewCredentials(tables.LinkAction):
|
class ViewCredentials(tables.LinkAction):
|
||||||
|
@ -24,8 +24,6 @@ from django.template.loader import render_to_string
|
|||||||
from django.urls import reverse_lazy
|
from django.urls import reverse_lazy
|
||||||
from django.utils.translation import ugettext_lazy as _
|
from django.utils.translation import ugettext_lazy as _
|
||||||
|
|
||||||
from openstack_auth import utils
|
|
||||||
|
|
||||||
from horizon import exceptions
|
from horizon import exceptions
|
||||||
from horizon import forms
|
from horizon import forms
|
||||||
from horizon import messages
|
from horizon import messages
|
||||||
@ -131,9 +129,6 @@ def download_rc_file(request):
|
|||||||
except KeyError:
|
except KeyError:
|
||||||
project_domain_id = ''
|
project_domain_id = ''
|
||||||
context['project_domain_id'] = project_domain_id
|
context['project_domain_id'] = project_domain_id
|
||||||
# sanity fix for removing v2.0 from the url if present
|
|
||||||
context['auth_url'], _ = utils.fix_auth_url_version_prefix(
|
|
||||||
context['auth_url'])
|
|
||||||
context['os_identity_api_version'] = 3
|
context['os_identity_api_version'] = 3
|
||||||
context['os_auth_version'] = 3
|
context['os_auth_version'] = 3
|
||||||
return _download_rc_file_for_template(request, context, template)
|
return _download_rc_file_for_template(request, context, template)
|
||||||
@ -150,14 +145,9 @@ def download_clouds_yaml_file(request):
|
|||||||
region_tuple[1] for region_tuple in settings.AVAILABLE_REGIONS
|
region_tuple[1] for region_tuple in settings.AVAILABLE_REGIONS
|
||||||
]
|
]
|
||||||
|
|
||||||
if utils.get_keystone_version() >= 3:
|
context['user_domain_name'] = request.user.user_domain_name
|
||||||
# make v3 specific changes
|
context['os_identity_api_version'] = 3
|
||||||
context['user_domain_name'] = request.user.user_domain_name
|
context['os_auth_version'] = 3
|
||||||
# sanity fix for removing v2.0 from the url if present
|
|
||||||
context['auth_url'], _ = utils.fix_auth_url_version_prefix(
|
|
||||||
context['auth_url'])
|
|
||||||
context['os_identity_api_version'] = 3
|
|
||||||
context['os_auth_version'] = 3
|
|
||||||
|
|
||||||
return _download_rc_file_for_template(request, context, template,
|
return _download_rc_file_for_template(request, context, template,
|
||||||
'clouds.yaml')
|
'clouds.yaml')
|
||||||
|
@ -15,7 +15,6 @@ from os.path import join
|
|||||||
from os import remove
|
from os import remove
|
||||||
|
|
||||||
from horizon.test import firefox_binary
|
from horizon.test import firefox_binary
|
||||||
from openstack_dashboard.test.integration_tests import decorators
|
|
||||||
from openstack_dashboard.test.integration_tests import helpers
|
from openstack_dashboard.test.integration_tests import helpers
|
||||||
|
|
||||||
|
|
||||||
@ -41,27 +40,6 @@ class TestDownloadRCFile(helpers.AdminTestCase):
|
|||||||
|
|
||||||
self.addCleanup(cleanup)
|
self.addCleanup(cleanup)
|
||||||
|
|
||||||
@decorators.skip_because(bugs=['1792028'])
|
|
||||||
def test_download_rc_v2_file(self):
|
|
||||||
"""This is a basic scenario test:
|
|
||||||
|
|
||||||
Steps:
|
|
||||||
1) Login to Horizon Dashboard as admin user
|
|
||||||
2) Navigate to Project > API Access tab
|
|
||||||
3) Click on "Download OpenStack RC File" dropdown button
|
|
||||||
4) Click on "OpenStack RC File (Identity API v2.0" button
|
|
||||||
5) File named by template "<tenant_name>-openrc.sh" must be downloaded
|
|
||||||
6) Check that username, tenant name and tenant id correspond to current
|
|
||||||
username, tenant name and tenant id
|
|
||||||
"""
|
|
||||||
api_access_page = self.home_pg.\
|
|
||||||
go_to_project_apiaccesspage()
|
|
||||||
api_access_page.download_openstack_rc_file(
|
|
||||||
2, self._directory, self._openrc_template)
|
|
||||||
cred_dict = api_access_page.get_credentials_from_file(
|
|
||||||
2, self._directory, self._openrc_template)
|
|
||||||
self.assertEqual(cred_dict, self.actual_dict)
|
|
||||||
|
|
||||||
def test_download_rc_v3_file(self):
|
def test_download_rc_v3_file(self):
|
||||||
"""This is a basic scenario test:
|
"""This is a basic scenario test:
|
||||||
|
|
||||||
|
@ -29,10 +29,10 @@ class KeystoneRestTestCase(test.TestCase):
|
|||||||
@test.create_mocks({api.keystone: ['get_version']})
|
@test.create_mocks({api.keystone: ['get_version']})
|
||||||
def test_version_get(self):
|
def test_version_get(self):
|
||||||
request = self.mock_rest_request()
|
request = self.mock_rest_request()
|
||||||
self.mock_get_version.return_value = '2.0'
|
self.mock_get_version.return_value = '3'
|
||||||
response = keystone.Version().get(request)
|
response = keystone.Version().get(request)
|
||||||
self.assertStatusCode(response, 200)
|
self.assertStatusCode(response, 200)
|
||||||
self.assertEqual(response.json, {"version": "2.0"})
|
self.assertEqual(response.json, {"version": "3"})
|
||||||
self.mock_get_version.assert_called_once_with()
|
self.mock_get_version.assert_called_once_with()
|
||||||
|
|
||||||
#
|
#
|
||||||
|
@ -237,7 +237,7 @@ class ApiVersionTests(test.TestCase):
|
|||||||
self.previous_settings = settings.OPENSTACK_API_VERSIONS
|
self.previous_settings = settings.OPENSTACK_API_VERSIONS
|
||||||
settings.OPENSTACK_API_VERSIONS = {
|
settings.OPENSTACK_API_VERSIONS = {
|
||||||
"data-processing": 1.1,
|
"data-processing": 1.1,
|
||||||
"identity": "2.0",
|
"identity": "3",
|
||||||
"volume": 1
|
"volume": 1
|
||||||
}
|
}
|
||||||
# Make sure cached data from other tests doesn't interfere
|
# Make sure cached data from other tests doesn't interfere
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
upgrade:
|
||||||
|
- |
|
||||||
|
Keystone API V2 support has been dropped in Train release. Keystone V2 API
|
||||||
|
support was deprecated in Stein release. If you use Keystone V2 before, you
|
||||||
|
should update the `OPENSTACK_API_VERSIONS` configuration option to use
|
||||||
|
Keystone V3 API.
|
Loading…
Reference in New Issue
Block a user