diff --git a/etc/keystone.conf.sample b/etc/keystone.conf.sample index 3b67b30042..489f83d7ef 100644 --- a/etc/keystone.conf.sample +++ b/etc/keystone.conf.sample @@ -76,6 +76,14 @@ [identity] # driver = keystone.identity.backends.sql.Identity +# This references the domain to use for all Identity API v2 requests (which are +# not aware of domains). A domain with this ID will be created for you by +# keystone-manage db_sync in migration 008. The domain referenced by this ID +# cannot be deleted on the v3 API, to prevent accidentally breaking the v2 API. +# There is nothing special about this domain, other than the fact that it must +# exist to order to maintain support for your v2 clients. +# default_domain_id = default + [catalog] # dynamic, sql-based backend (supports API/CLI-based management commands) # driver = keystone.catalog.backends.sql.Catalog diff --git a/keystone/common/sql/migrate_repo/versions/008_create_default_domain.py b/keystone/common/sql/migrate_repo/versions/008_create_default_domain.py new file mode 100644 index 0000000000..27d4b28b31 --- /dev/null +++ b/keystone/common/sql/migrate_repo/versions/008_create_default_domain.py @@ -0,0 +1,63 @@ +# vim: tabstop=4 shiftwidth=4 softtabstop=4 + +# Copyright 2012 OpenStack LLC +# +# 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 json + +import sqlalchemy as sql +from sqlalchemy import orm +from keystone import config + + +CONF = config.CONF +DEFAULT_DOMAIN_ID = CONF['identity']['default_domain_id'] + + +def upgrade(migrate_engine): + """Creates the default domain.""" + meta = sql.MetaData() + meta.bind = migrate_engine + + domain_table = sql.Table('domain', meta, autoload=True) + + domain = { + 'id': DEFAULT_DOMAIN_ID, + 'name': 'Default', + 'enabled': True, + 'extra': json.dumps({ + 'description': 'Owns users and tenants (i.e. projects) available ' + 'on Identity API v2.'})} + + session = orm.sessionmaker(bind=migrate_engine)() + + session.execute( + 'INSERT INTO `%s` (%s) VALUES (%s)' % ( + domain_table.name, + ', '.join(['`%s`' % k for k in domain.keys()]), + ', '.join([':%s' % k for k in domain.keys()])), + domain) + session.commit() + + +def downgrade(migrate_engine): + """Delete the default domain.""" + meta = sql.MetaData() + meta.bind = migrate_engine + + sql.Table('domain', meta, autoload=True) + session = orm.sessionmaker(bind=migrate_engine)() + session.execute( + 'DELETE FROM `domain` WHERE `id`=:id', {'id': DEFAULT_DOMAIN_ID}) + session.commit() diff --git a/keystone/common/sql/migrate_repo/versions/008_normalize_identity.py b/keystone/common/sql/migrate_repo/versions/009_normalize_identity.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/008_normalize_identity.py rename to keystone/common/sql/migrate_repo/versions/009_normalize_identity.py diff --git a/keystone/common/sql/migrate_repo/versions/009_normalize_identity_migration.py b/keystone/common/sql/migrate_repo/versions/010_normalize_identity_migration.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/009_normalize_identity_migration.py rename to keystone/common/sql/migrate_repo/versions/010_normalize_identity_migration.py diff --git a/keystone/common/sql/migrate_repo/versions/010_endpoints_v3.py b/keystone/common/sql/migrate_repo/versions/011_endpoints_v3.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/010_endpoints_v3.py rename to keystone/common/sql/migrate_repo/versions/011_endpoints_v3.py diff --git a/keystone/common/sql/migrate_repo/versions/011_populate_endpoint_type.py b/keystone/common/sql/migrate_repo/versions/012_populate_endpoint_type.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/011_populate_endpoint_type.py rename to keystone/common/sql/migrate_repo/versions/012_populate_endpoint_type.py diff --git a/keystone/common/sql/migrate_repo/versions/012_drop_legacy_endpoints.py b/keystone/common/sql/migrate_repo/versions/013_drop_legacy_endpoints.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/012_drop_legacy_endpoints.py rename to keystone/common/sql/migrate_repo/versions/013_drop_legacy_endpoints.py diff --git a/keystone/common/sql/migrate_repo/versions/013_add_group_tables.py b/keystone/common/sql/migrate_repo/versions/014_add_group_tables.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/013_add_group_tables.py rename to keystone/common/sql/migrate_repo/versions/014_add_group_tables.py diff --git a/keystone/common/sql/migrate_repo/versions/014_tenant_to_project.py b/keystone/common/sql/migrate_repo/versions/015_tenant_to_project.py similarity index 100% rename from keystone/common/sql/migrate_repo/versions/014_tenant_to_project.py rename to keystone/common/sql/migrate_repo/versions/015_tenant_to_project.py diff --git a/keystone/config.py b/keystone/config.py index ce79ddd53c..e7f3139448 100644 --- a/keystone/config.py +++ b/keystone/config.py @@ -142,6 +142,9 @@ register_str('policy_default_rule', default=None) #default max request size is 112k register_int('max_request_body_size', default=114688) +# identity +register_str('default_domain_id', group='identity', default='default') + #ssl options register_bool('enable', group='ssl', default=False) register_str('certfile', group='ssl', default=None) diff --git a/keystone/identity/controllers.py b/keystone/identity/controllers.py index 4751a69197..9e8d9f3fc7 100644 --- a/keystone/identity/controllers.py +++ b/keystone/identity/controllers.py @@ -22,9 +22,12 @@ import uuid from keystone.common import controller from keystone.common import logging +from keystone import config from keystone import exception +CONF = config.CONF +DEFAULT_DOMAIN_ID = CONF['identity']['default_domain_id'] LOG = logging.getLogger(__name__) @@ -442,6 +445,12 @@ class DomainV3(controller.V3Controller): @controller.protected def delete_domain(self, context, domain_id): + # explicitly forbid deleting the default domain (this should be a + # carefully orchestrated manual process involving configuration + # changes, etc) + if domain_id == DEFAULT_DOMAIN_ID: + raise exception.ForbiddenAction(action='delete the default domain') + return self.identity_api.delete_domain(context, domain_id) diff --git a/tests/test_sql_upgrade.py b/tests/test_sql_upgrade.py index 4acda07b4d..e04fc3e5cc 100644 --- a/tests/test_sql_upgrade.py +++ b/tests/test_sql_upgrade.py @@ -119,11 +119,11 @@ class SqlUpgradeTests(test.TestCase): self.assertTableExists('policy') self.assertTableColumns('policy', ['id', 'type', 'blob', 'extra']) - def test_upgrade_7_to_9(self): - self.upgrade(7) + def test_upgrade_8_to_10(self): + self.upgrade(8) self.populate_user_table() self.populate_tenant_table() - self.upgrade(9) + self.upgrade(10) self.assertTableColumns("user", ["id", "name", "extra", "password", "enabled"]) @@ -149,15 +149,15 @@ class SqlUpgradeTests(test.TestCase): self.assertEqual(a_tenant.description, 'description') session.commit() - def test_downgrade_9_to_7(self): - self.upgrade(7) + def test_downgrade_10_to_8(self): + self.upgrade(8) self.populate_user_table() self.populate_tenant_table() - self.upgrade(9) - self.downgrade(7) + self.upgrade(10) + self.downgrade(8) - def test_upgrade_9_to_12(self): - self.upgrade(9) + def test_upgrade_10_to_13(self): + self.upgrade(10) service_extra = { 'name': uuid.uuid4().hex, @@ -184,7 +184,7 @@ class SqlUpgradeTests(test.TestCase): self.insert_dict(session, 'endpoint', endpoint) session.commit() - self.upgrade(12) + self.upgrade(13) self.assertTableColumns( 'service', @@ -225,35 +225,35 @@ class SqlUpgradeTests(test.TestCase): self.assertTableDoesNotExist('user_tenant_membership') def test_upgrade_tenant_to_project(self): - self.upgrade(13) - self.assertTenantTables() self.upgrade(14) + self.assertTenantTables() + self.upgrade(15) self.assertProjectTables() def test_downgrade_project_to_tenant(self): - self.upgrade(14) + self.upgrade(15) self.assertProjectTables() - self.downgrade(13) + self.downgrade(14) self.assertTenantTables() - def test_upgrade_12_to_13(self): - self.upgrade(12) + def test_upgrade_13_to_14(self): self.upgrade(13) + self.upgrade(14) self.assertTableExists('group') self.assertTableExists('group_project_metadata') self.assertTableExists('group_domain_metadata') self.assertTableExists('user_group_membership') - def test_downgrade_13_to_12(self): - self.upgrade(13) - self.downgrade(12) + def test_downgrade_14_to_13(self): + self.upgrade(14) + self.downgrade(13) self.assertTableDoesNotExist('group') self.assertTableDoesNotExist('group_project_metadata') self.assertTableDoesNotExist('group_domain_metadata') self.assertTableDoesNotExist('user_group_membership') - def test_downgrade_12_to_9(self): - self.upgrade(12) + def test_downgrade_13_to_10(self): + self.upgrade(13) service_extra = { 'name': uuid.uuid4().hex, @@ -295,7 +295,7 @@ class SqlUpgradeTests(test.TestCase): self.insert_dict(session, 'endpoint', endpoint) session.commit() - self.downgrade(8) + self.downgrade(9) self.assertTableColumns( 'service',