2013-11-05 13:08:06 -05:00
|
|
|
# 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.
|
|
|
|
|
2012-04-11 14:04:08 -07:00
|
|
|
import os
|
Using /tmp for SECRET_KEY in tests
While using openstack_dashboard/test for the path of SECRET_KEY works
perfectly for building Horizon, including when building the pacakge for
Debian, this is a no-go for Horizon plugins in the Debian context. Indeed,
ironic-ui, manila-ui and sahara-dashboard are all doing:
from openstack_dashboard.test.settings import
While this works in devstack, as it is using a clone of the Horizon git
repository which is writable, it doesn't work in the context of Debian
(or other distro) packaging. Indeed, in this case, the folder becomes
/usr/lib/python2.7/dist-packages/openstack_dashboard/test. This folder,
in all reasonableness, is owned by root, and read only by the user who
is building the package. So at import time, doing this:
SECRET_KEY = secret_key.generate_or_read_from_file(
os.path.join(TEST_DIR, '.secret_key_store'))
just fails miserably when the horizon plugin packages are building.
Simply using /tmp instead of TEST_DIR fixes the issue. This patch makes
it in a portable way using tempfile.gettempdir() to find /tmp. Though
it isn't completely safe, as the file in /tmp is predictable (and then
there can be a symlink attack), though for unit testing we probably
don't care.
Please allow this patch to go through, so we don't have to carry it
at the distribution level.
Change-Id: Iadf0c2bffe19e2c33083a257102e846886d7680f
2016-09-29 13:04:34 +02:00
|
|
|
import tempfile
|
2012-04-11 14:04:08 -07:00
|
|
|
|
2017-05-24 03:01:11 +00:00
|
|
|
from horizon.test.settings import * # noqa: F403,H303
|
2018-04-11 18:57:28 +09:00
|
|
|
from horizon.utils.escape import monkeypatch_escape
|
2013-08-23 17:26:48 +04:00
|
|
|
from horizon.utils import secret_key
|
2012-10-04 15:43:40 -07:00
|
|
|
|
2018-04-11 18:57:28 +09:00
|
|
|
from openstack_dashboard import enabled
|
|
|
|
from openstack_dashboard import exceptions
|
2018-12-27 09:51:15 +09:00
|
|
|
from openstack_dashboard import theme_settings
|
2018-04-11 18:57:28 +09:00
|
|
|
from openstack_dashboard.utils import settings as settings_utils
|
2016-05-03 15:51:49 +10:00
|
|
|
|
|
|
|
# this is used to protect from client XSS attacks, but it's worth
|
|
|
|
# enabling in our test setup to find any issues it might cause
|
|
|
|
monkeypatch_escape()
|
|
|
|
|
2019-04-11 06:26:54 +09:00
|
|
|
# Load default values
|
2020-05-11 07:29:47 +09:00
|
|
|
from openstack_dashboard.defaults import * # noqa: E402,F403,H303
|
2019-04-11 06:26:54 +09:00
|
|
|
|
2019-04-11 09:51:31 +09:00
|
|
|
WEBROOT = '/'
|
|
|
|
|
|
|
|
# The following need to Set explicitly
|
|
|
|
# as they defaults to None in openstack_dashboard.defaults.
|
|
|
|
# TODO(amotoki): Move them to a common function.
|
|
|
|
LOGIN_URL = '/auth/login/'
|
|
|
|
LOGOUT_URL = '/auth/logout/'
|
|
|
|
LOGIN_ERROR = '/auth/error/'
|
|
|
|
LOGIN_REDIRECT_URL = '/'
|
|
|
|
MEDIA_URL = '/media/'
|
|
|
|
STATIC_URL = '/static/'
|
2018-02-14 14:46:23 +02:00
|
|
|
|
2019-04-11 09:51:31 +09:00
|
|
|
TEST_DIR = os.path.dirname(os.path.abspath(__file__))
|
2012-04-11 14:04:08 -07:00
|
|
|
ROOT_PATH = os.path.abspath(os.path.join(TEST_DIR, ".."))
|
2015-09-29 21:24:11 -07:00
|
|
|
MEDIA_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'media'))
|
2014-09-22 10:50:12 -05:00
|
|
|
STATIC_ROOT = os.path.abspath(os.path.join(ROOT_PATH, '..', 'static'))
|
2012-04-11 14:04:08 -07:00
|
|
|
|
2013-08-23 17:26:48 +04:00
|
|
|
SECRET_KEY = secret_key.generate_or_read_from_file(
|
Using /tmp for SECRET_KEY in tests
While using openstack_dashboard/test for the path of SECRET_KEY works
perfectly for building Horizon, including when building the pacakge for
Debian, this is a no-go for Horizon plugins in the Debian context. Indeed,
ironic-ui, manila-ui and sahara-dashboard are all doing:
from openstack_dashboard.test.settings import
While this works in devstack, as it is using a clone of the Horizon git
repository which is writable, it doesn't work in the context of Debian
(or other distro) packaging. Indeed, in this case, the folder becomes
/usr/lib/python2.7/dist-packages/openstack_dashboard/test. This folder,
in all reasonableness, is owned by root, and read only by the user who
is building the package. So at import time, doing this:
SECRET_KEY = secret_key.generate_or_read_from_file(
os.path.join(TEST_DIR, '.secret_key_store'))
just fails miserably when the horizon plugin packages are building.
Simply using /tmp instead of TEST_DIR fixes the issue. This patch makes
it in a portable way using tempfile.gettempdir() to find /tmp. Though
it isn't completely safe, as the file in /tmp is predictable (and then
there can be a symlink attack), though for unit testing we probably
don't care.
Please allow this patch to go through, so we don't have to carry it
at the distribution level.
Change-Id: Iadf0c2bffe19e2c33083a257102e846886d7680f
2016-09-29 13:04:34 +02:00
|
|
|
os.path.join(tempfile.gettempdir(), '.secret_key_store'))
|
2015-02-18 13:03:02 -07:00
|
|
|
ROOT_URLCONF = 'openstack_dashboard.test.urls'
|
2016-08-04 20:41:46 +01:00
|
|
|
|
|
|
|
TEMPLATES[0]['DIRS'] = [
|
|
|
|
os.path.join(TEST_DIR, 'templates')
|
|
|
|
]
|
|
|
|
|
|
|
|
TEMPLATES[0]['OPTIONS']['context_processors'].append(
|
|
|
|
'openstack_dashboard.context_processors.openstack'
|
2012-10-04 15:43:40 -07:00
|
|
|
)
|
|
|
|
|
2018-12-27 09:51:15 +09:00
|
|
|
AVAILABLE_THEMES, SELECTABLE_THEMES, DEFAULT_THEME = \
|
|
|
|
theme_settings.get_available_themes(AVAILABLE_THEMES, 'default', None)
|
2016-05-17 15:06:05 -07:00
|
|
|
|
2015-06-26 13:03:38 -07:00
|
|
|
COMPRESS_OFFLINE = False
|
|
|
|
|
2012-10-04 15:43:40 -07:00
|
|
|
INSTALLED_APPS = (
|
2013-03-27 17:16:13 -07:00
|
|
|
'django.contrib.contenttypes',
|
|
|
|
'django.contrib.auth',
|
2012-10-04 15:43:40 -07:00
|
|
|
'django.contrib.sessions',
|
|
|
|
'django.contrib.staticfiles',
|
|
|
|
'django.contrib.messages',
|
|
|
|
'django.contrib.humanize',
|
|
|
|
'openstack_auth',
|
|
|
|
'compressor',
|
|
|
|
'horizon',
|
|
|
|
'openstack_dashboard',
|
|
|
|
)
|
|
|
|
|
|
|
|
AUTHENTICATION_BACKENDS = ('openstack_auth.backend.KeystoneBackend',)
|
|
|
|
|
|
|
|
SITE_BRANDING = 'OpenStack'
|
|
|
|
|
|
|
|
HORIZON_CONFIG = {
|
|
|
|
"password_validator": {
|
|
|
|
"regex": '^.{8,18}$',
|
2013-09-06 14:13:37 +09:00
|
|
|
"help_text": "Password must be between 8 and 18 characters."
|
2012-10-04 15:43:40 -07:00
|
|
|
},
|
|
|
|
'user_home': None,
|
2018-03-20 16:19:57 +09:00
|
|
|
'help_url': "https://docs.openstack.org/",
|
2015-04-06 16:45:55 -05:00
|
|
|
'exceptions': {'recoverable': exceptions.RECOVERABLE,
|
|
|
|
'not_found': exceptions.NOT_FOUND,
|
|
|
|
'unauthorized': exceptions.UNAUTHORIZED},
|
2014-05-08 12:34:21 -06:00
|
|
|
'angular_modules': [],
|
|
|
|
'js_files': [],
|
2016-08-10 11:30:20 +01:00
|
|
|
}
|
|
|
|
|
2019-04-22 11:47:28 +09:00
|
|
|
# Use the legacy panel so unit tests are still run.
|
|
|
|
# We need to set False for panels whose default implementation
|
|
|
|
# is Angular-based.
|
|
|
|
ANGULAR_FEATURES['images_panel'] = False
|
|
|
|
ANGULAR_FEATURES['key_pairs_panel'] = False
|
|
|
|
ANGULAR_FEATURES['roles_panel'] = False
|
2012-10-04 15:43:40 -07:00
|
|
|
|
2015-07-22 11:15:45 -06:00
|
|
|
STATICFILES_DIRS = settings_utils.get_xstatic_dirs(
|
|
|
|
settings_utils.BASE_XSTATIC_MODULES, HORIZON_CONFIG
|
|
|
|
)
|
|
|
|
|
2015-06-30 13:23:41 -06:00
|
|
|
INSTALLED_APPS = list(INSTALLED_APPS) # Make sure it's mutable
|
2015-07-22 11:15:45 -06:00
|
|
|
settings_utils.update_dashboards(
|
2015-06-30 13:23:41 -06:00
|
|
|
[
|
2018-04-11 18:57:28 +09:00
|
|
|
enabled,
|
2015-06-30 13:23:41 -06:00
|
|
|
],
|
|
|
|
HORIZON_CONFIG,
|
|
|
|
INSTALLED_APPS,
|
|
|
|
)
|
|
|
|
|
2015-07-22 11:15:45 -06:00
|
|
|
settings_utils.find_static_files(HORIZON_CONFIG, AVAILABLE_THEMES,
|
|
|
|
THEME_COLLECTION_DIR, ROOT_PATH)
|
2015-08-17 23:54:29 -06:00
|
|
|
|
2018-04-03 00:40:19 +03:00
|
|
|
IMAGES_ALLOW_LOCATION = True
|
2013-01-29 04:35:18 -05:00
|
|
|
|
2012-10-04 15:43:40 -07:00
|
|
|
AVAILABLE_REGIONS = [
|
2019-12-05 11:04:48 +08:00
|
|
|
('http://localhost/identity/v3', 'local'),
|
|
|
|
('http://remote/identity/v3', 'remote'),
|
2012-10-04 15:43:40 -07:00
|
|
|
]
|
|
|
|
|
2019-12-05 11:04:48 +08:00
|
|
|
OPENSTACK_KEYSTONE_URL = "http://localhost/identity/v3"
|
2012-10-04 15:43:40 -07:00
|
|
|
|
2013-05-15 14:43:49 -07:00
|
|
|
OPENSTACK_KEYSTONE_MULTIDOMAIN_SUPPORT = True
|
|
|
|
OPENSTACK_KEYSTONE_DEFAULT_DOMAIN = 'test_domain'
|
2015-11-12 21:19:45 -08:00
|
|
|
OPENSTACK_KEYSTONE_FEDERATION_MANAGEMENT = True
|
2013-05-15 14:43:49 -07:00
|
|
|
|
2019-04-11 06:26:54 +09:00
|
|
|
OPENSTACK_CINDER_FEATURES['enable_backup'] = True
|
2014-03-28 10:50:01 -05:00
|
|
|
|
2019-04-11 06:26:54 +09:00
|
|
|
OPENSTACK_NEUTRON_NETWORK['enable_router'] = True
|
|
|
|
# network quota is Enabled in specific tests only
|
|
|
|
OPENSTACK_NEUTRON_NETWORK['enable_quotas'] = False
|
|
|
|
OPENSTACK_NEUTRON_NETWORK['enable_distributed_router'] = False
|
2013-02-07 18:15:16 -08:00
|
|
|
|
2019-04-11 06:26:54 +09:00
|
|
|
OPENSTACK_HYPERVISOR_FEATURES['can_set_password'] = True
|
2012-10-04 15:43:40 -07:00
|
|
|
|
2013-11-13 04:14:13 +09:00
|
|
|
LOGGING['loggers'].update(
|
|
|
|
{
|
|
|
|
'openstack_dashboard': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
2014-04-04 09:40:07 +01:00
|
|
|
'openstack_auth': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
2013-11-13 04:14:13 +09:00
|
|
|
'novaclient': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
|
|
|
'keystoneclient': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
|
|
|
'glanceclient': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
|
|
|
'neutronclient': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
2017-12-16 23:17:34 +09:00
|
|
|
'oslo_policy': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
|
|
|
'stevedore': {
|
|
|
|
'handlers': ['test'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
2013-11-13 04:14:13 +09:00
|
|
|
'iso8601': {
|
|
|
|
'handlers': ['null'],
|
|
|
|
'propagate': False,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
)
|
2012-10-04 15:43:40 -07:00
|
|
|
|
2013-05-02 17:28:10 +08:00
|
|
|
SECURITY_GROUP_RULES = {
|
|
|
|
'all_tcp': {
|
|
|
|
'name': 'ALL TCP',
|
|
|
|
'ip_protocol': 'tcp',
|
|
|
|
'from_port': '1',
|
|
|
|
'to_port': '65535',
|
|
|
|
},
|
|
|
|
'http': {
|
|
|
|
'name': 'HTTP',
|
|
|
|
'ip_protocol': 'tcp',
|
|
|
|
'from_port': '80',
|
|
|
|
'to_port': '80',
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
Adding RBAC policy system and checks for identity
Adding file based RBAC engine for Horizon using copies of nova and
keystone policy.json files
Policy engine builds on top of oslo incubator policy.py, fileutils
was also pulled from oslo incubator as a dependency of policy.py
When Horizon runs and a policy check is made, a path and mapping of
services to policy files is used to load the rules into the policy
engine. Each check is mapped to a service type and validated. This
extra level of mapping is required because the policy.json files
may each contain a 'default' rule or unqualified (no service name
include) rule. Additionally, maintaining separate policy.json
files per service will allow easier syncing with the service
projects.
The engine allows for compound 'and' checks at this time. E.g.,
the way the Create User action is written, multiple APIs are
called to read data (roles, projects) and more are required to
update data (grants, user).
Other workflows e.g., Edit Project, should have separate save
actions per step as they are unrelated. Only the applicable
policy checks to that step were added. The separating unrelated
steps saves will should be future work.
The underlying engine supports more rule types that are used in the
underlying policy.json files.
Policy checks were added for all actions on tables in the Identity
Panel only. And the service policy files imported are limited in
this commit to reduce scope of the change.
Additionally, changes were made to the base action class to add
support or setting policy rules and an overridable method for
determining the policy check target. This reduces the need for
redundant code in each action policy check.
Note, the benefit Horizon has is that the underlying APIs will
correct us if we get it wrong, so if a policy file is not found for
a particular service, permission is assumed and the actual API call
to the service will fail if the action isn't authorized for that user.
Finally, adding documentation regarding policy enforcement.
Implements: blueprint rbac
Change-Id: I4a4a71163186b973229a0461b165c16936bc10e5
2013-08-16 17:28:46 -06:00
|
|
|
POLICY_FILES_PATH = os.path.join(ROOT_PATH, "conf")
|
|
|
|
POLICY_FILES = {
|
|
|
|
'identity': 'keystone_policy.json',
|
|
|
|
'compute': 'nova_policy.json'
|
|
|
|
}
|
2019-04-22 11:47:28 +09:00
|
|
|
# Tthe policy check is disabled by default in our test, and it is enabled
|
|
|
|
# when we would like to test the policy check feature itself.
|
|
|
|
POLICY_CHECK_FUNCTION = None
|
2013-12-06 15:12:55 +08:00
|
|
|
|
2013-12-04 16:03:56 +08:00
|
|
|
# The openstack_auth.user.Token object isn't JSON-serializable ATM
|
|
|
|
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
|
2015-04-02 23:49:29 -06:00
|
|
|
|
|
|
|
REST_API_SETTING_1 = 'foo'
|
|
|
|
REST_API_SETTING_2 = 'bar'
|
|
|
|
REST_API_SECURITY = 'SECURITY'
|
|
|
|
REST_API_REQUIRED_SETTINGS = ['REST_API_SETTING_1']
|
|
|
|
REST_API_ADDITIONAL_SETTINGS = ['REST_API_SETTING_2']
|
2014-11-20 14:53:48 +08:00
|
|
|
|
2017-04-29 11:26:45 +00:00
|
|
|
# --------------------
|
|
|
|
# Test-only settings
|
|
|
|
# --------------------
|
|
|
|
# TEST_GLOBAL_MOCKS_ON_PANELS: defines what and how methods should be
|
|
|
|
# mocked globally for unit tests and Selenium tests.
|
|
|
|
# 'method' is required. 'return_value' and 'side_effect'
|
|
|
|
# are optional and passed to mock.patch().
|
|
|
|
TEST_GLOBAL_MOCKS_ON_PANELS = {
|
|
|
|
'aggregates': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.admin'
|
|
|
|
'.aggregates.panel.Aggregates.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-01-03 14:25:46 +01:00
|
|
|
'domains': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.identity'
|
|
|
|
'.domains.panel.Domains.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-01-08 10:43:49 +09:00
|
|
|
'qos': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.project'
|
|
|
|
'.network_qos.panel.NetworkQoS.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-11-21 14:44:30 +08:00
|
|
|
'rbac_policies': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.admin'
|
|
|
|
'.rbac_policies.panel.RBACPolicies.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2017-11-04 14:29:14 +08:00
|
|
|
'server_groups': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.project'
|
|
|
|
'.server_groups.panel.ServerGroups.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-01-25 07:54:17 +01:00
|
|
|
'trunk-project': {
|
2017-03-14 08:31:28 +01:00
|
|
|
'method': ('openstack_dashboard.dashboards.project'
|
|
|
|
'.trunks.panel.Trunks.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-01-25 07:54:17 +01:00
|
|
|
'trunk-admin': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.admin'
|
|
|
|
'.trunks.panel.Trunks.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-01-08 10:43:49 +09:00
|
|
|
'volume_groups': {
|
2017-01-11 10:34:51 +00:00
|
|
|
'method': ('openstack_dashboard.dashboards.project'
|
2018-01-08 10:43:49 +09:00
|
|
|
'.volume_groups.panel.VolumeGroups.allowed'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
|
|
|
'vg_snapshots': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.project'
|
|
|
|
'.vg_snapshots.panel.GroupSnapshots.allowed'),
|
2017-01-11 10:34:51 +00:00
|
|
|
'return_value': True,
|
|
|
|
},
|
2018-03-11 22:38:28 +01:00
|
|
|
'application_credentials': {
|
|
|
|
'method': ('openstack_dashboard.dashboards.identity'
|
|
|
|
'.application_credentials.panel'
|
|
|
|
'.ApplicationCredentialsPanel.can_access'),
|
|
|
|
'return_value': True,
|
|
|
|
},
|
2017-04-29 11:26:45 +00:00
|
|
|
}
|