summaryrefslogtreecommitdiffstats
path: root/keystone
diff options
context:
space:
mode:
authorJames E. Blair <jeblair@hp.com>2012-02-14 15:54:59 -0800
committerJames E. Blair <jeblair@hp.com>2012-02-14 15:57:37 -0800
commiteef1f0d93ae19f04601b75cd7a2514e81b4005b9 (patch)
tree2b1b8b4a45f884414bd89c4bec7e31056a20a351 /keystone
parent9452cf04bc8b0a4dc66dc640615d5ace1ca715f2 (diff)
parent90068b0143af788869116d08533d5ebc99874a17 (diff)
downloadkeystone-eef1f0d93ae19f04601b75cd7a2514e81b4005b9.tar.gz
keystone-eef1f0d93ae19f04601b75cd7a2514e81b4005b9.tar.xz
keystone-eef1f0d93ae19f04601b75cd7a2514e81b4005b9.zip
Merge redux branch (keystone light)
Change-Id: I2cb5b198a06848f42f919ea49e338443131e263e
Diffstat (limited to 'keystone')
-rw-r--r--keystone/__init__.py19
-rwxr-xr-xkeystone/backends/__init__.py56
-rwxr-xr-xkeystone/backends/api.py439
-rw-r--r--keystone/backends/backendutils.py60
-rw-r--r--keystone/backends/ldap/__init__.py33
-rw-r--r--keystone/backends/ldap/api/__init__.py111
-rw-r--r--keystone/backends/ldap/api/base.py183
-rw-r--r--keystone/backends/ldap/api/role.py288
-rw-r--r--keystone/backends/ldap/api/tenant.py109
-rw-r--r--keystone/backends/ldap/api/user.py124
-rw-r--r--keystone/backends/ldap/fakeldap.py315
-rw-r--r--keystone/backends/ldap/keystone.ldif74
-rw-r--r--keystone/backends/ldap/keystone.schema83
-rw-r--r--keystone/backends/ldap/models.py52
-rwxr-xr-xkeystone/backends/memcache/__init__.py81
-rw-r--r--keystone/backends/memcache/api/__init__.py18
-rwxr-xr-xkeystone/backends/memcache/api/token.py74
-rwxr-xr-xkeystone/backends/memcache/models.py19
-rwxr-xr-xkeystone/backends/models.py60
-rwxr-xr-xkeystone/backends/sqlalchemy/__init__.py169
-rwxr-xr-xkeystone/backends/sqlalchemy/api/credentials.py137
-rwxr-xr-xkeystone/backends/sqlalchemy/api/endpoint_template.py381
-rwxr-xr-xkeystone/backends/sqlalchemy/api/role.py463
-rw-r--r--keystone/backends/sqlalchemy/api/service.py194
-rwxr-xr-xkeystone/backends/sqlalchemy/api/tenant.py377
-rwxr-xr-xkeystone/backends/sqlalchemy/api/token.py149
-rwxr-xr-xkeystone/backends/sqlalchemy/api/user.py458
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/001_initial_migration.py196
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/002_rename_token_table.py26
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/003_add_endpoint_template_versions.py64
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/004_add_service_owner.py39
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/005_add_tenants_uid.py38
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/006_populate_tenants_uid.py40
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/007_make_tenants_uid_unique.py59
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/008_add_users_uid.py40
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/009_populate_users_uid.py42
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/010_make_users_uid_unique.py60
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/011_is_enabled_boolean.py58
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_downgrade.sql5
-rw-r--r--keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_upgrade.sql5
-rw-r--r--keystone/backends/sqlalchemy/migration.py172
-rwxr-xr-xkeystone/backends/sqlalchemy/models.py187
-rw-r--r--keystone/catalog/__init__.py1
-rw-r--r--[-rwxr-xr-x]keystone/catalog/backends/__init__.py (renamed from keystone/backends/sqlalchemy/api/__init__.py)0
-rw-r--r--keystone/catalog/backends/kvs.py39
-rw-r--r--keystone/catalog/backends/templated.py95
-rw-r--r--keystone/catalog/core.py57
-rw-r--r--keystone/cli.py129
-rw-r--r--keystone/client.py193
-rw-r--r--keystone/common/bufferedhttp.py57
-rw-r--r--keystone/common/cfg.py (renamed from keystone/cfg.py)127
-rwxr-xr-xkeystone/common/config.py386
-rw-r--r--keystone/common/crypt.py74
-rwxr-xr-xkeystone/common/exception.py100
-rw-r--r--keystone/common/kvs.py24
-rw-r--r--keystone/common/logging.py55
-rw-r--r--keystone/common/manager.py36
-rw-r--r--keystone/common/sql/__init__.py1
-rw-r--r--keystone/common/sql/core.py119
-rw-r--r--keystone/common/sql/legacy.py141
-rw-r--r--keystone/common/sql/migrate_repo/README (renamed from keystone/backends/sqlalchemy/migrate_repo/README)0
-rw-r--r--keystone/common/sql/migrate_repo/__init__.py (renamed from keystone/backends/sqlalchemy/migrate_repo/__init__.py)0
-rw-r--r--[-rwxr-xr-x]keystone/common/sql/migrate_repo/manage.py (renamed from keystone/backends/sqlalchemy/migrate_repo/manage.py)4
-rw-r--r--keystone/common/sql/migrate_repo/migrate.cfg (renamed from keystone/backends/sqlalchemy/migrate_repo/migrate.cfg)7
-rw-r--r--keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py20
-rw-r--r--keystone/common/sql/migrate_repo/versions/__init__.py (renamed from keystone/backends/sqlalchemy/migrate_repo/versions/__init__.py)0
-rw-r--r--keystone/common/sql/migration.py80
-rw-r--r--keystone/common/sql/util.py18
-rw-r--r--keystone/common/template.py373
-rw-r--r--keystone/common/utils.py227
-rw-r--r--[-rwxr-xr-x]keystone/common/wsgi.py667
-rw-r--r--keystone/config.py190
-rw-r--r--keystone/content/admin/HP-IDM-admin-devguide.pdfbin95635 -> 0 bytes
-rw-r--r--keystone/content/admin/HP-IDM-admin.wadl150
-rw-r--r--keystone/content/admin/OS-KSADM-admin-devguide.pdfbin257371 -> 0 bytes
-rw-r--r--keystone/content/admin/OS-KSADM-admin.wadl793
-rw-r--r--keystone/content/admin/OS-KSCATALOG-admin-devguide.pdfbin136602 -> 0 bytes
-rw-r--r--keystone/content/admin/OS-KSCATALOG-admin.wadl295
-rw-r--r--keystone/content/admin/OS-KSEC2-admin-devguide.pdfbin126891 -> 0 bytes
-rw-r--r--keystone/content/admin/OS-KSEC2-admin.wadl212
-rw-r--r--keystone/content/admin/OS-KSS3-admin.wadl212
-rw-r--r--keystone/content/admin/OS-KSVALIDATE-admin.wadl192
-rw-r--r--keystone/content/admin/RAX-KSGRP-admin.wadl74
-rw-r--r--keystone/content/admin/RAX-KSKEY-admin-devguide.pdfbin127941 -> 0 bytes
-rw-r--r--keystone/content/admin/RAX-KSKEY-admin.wadl212
-rw-r--r--keystone/content/admin/RAX-KSQA-admin.wadl106
-rw-r--r--keystone/content/admin/extensions.json5
-rw-r--r--keystone/content/admin/extensions.xml5
-rw-r--r--keystone/content/admin/identity-admin.wadl508
-rw-r--r--keystone/content/admin/identityadminguide.pdfbin274329 -> 0 bytes
-rw-r--r--keystone/content/admin/version.atom.tpl29
-rw-r--r--keystone/content/admin/version.json.tpl32
-rw-r--r--keystone/content/admin/version.xml.tpl29
-rw-r--r--keystone/content/common/common.ent56
-rw-r--r--keystone/content/common/js/shjs/sh_java.js337
-rw-r--r--keystone/content/common/js/shjs/sh_javascript.js347
-rw-r--r--keystone/content/common/js/shjs/sh_main.js538
-rw-r--r--keystone/content/common/js/shjs/sh_xml.js115
-rw-r--r--keystone/content/common/js/trc/schema/controller.js184
-rw-r--r--keystone/content/common/js/trc/schema/layoutManager.js137
-rw-r--r--keystone/content/common/js/trc/schema/sampleManager.js342
-rw-r--r--keystone/content/common/js/trc/util.js564
-rw-r--r--keystone/content/common/samples/RAX-KSADM-userWithPassword.json8
-rw-r--r--keystone/content/common/samples/RAX-KSADM-userWithPassword.xml6
-rw-r--r--keystone/content/common/samples/RAX-KSGRP-groups.json9
-rw-r--r--keystone/content/common/samples/RAX-KSGRP-groups.xml5
-rw-r--r--keystone/content/common/samples/RAX-KSQA-secretQA.json6
-rw-r--r--keystone/content/common/samples/RAX-KSQA-secretQA.xml7
-rw-r--r--keystone/content/common/samples/apiKeyCredentials.json6
-rw-r--r--keystone/content/common/samples/apiKeyCredentials.xml6
-rw-r--r--keystone/content/common/samples/auth.json98
-rw-r--r--keystone/content/common/samples/auth.xml75
-rw-r--r--keystone/content/common/samples/auth_credentials-OS-KSEC2.json10
-rw-r--r--keystone/content/common/samples/auth_credentials-OS-KSEC2.xml10
-rw-r--r--keystone/content/common/samples/auth_credentials-RAX-KSKEY.json9
-rw-r--r--keystone/content/common/samples/auth_credentials-RAX-KSKEY.xml7
-rw-r--r--keystone/content/common/samples/auth_credentials.json9
-rw-r--r--keystone/content/common/samples/auth_credentials.xml6
-rw-r--r--keystone/content/common/samples/auth_with_token.json8
-rw-r--r--keystone/content/common/samples/auth_with_token.xml7
-rw-r--r--keystone/content/common/samples/authwithgroups.json94
-rw-r--r--keystone/content/common/samples/authwithgroups.xml70
-rw-r--r--keystone/content/common/samples/choices.json71
-rw-r--r--keystone/content/common/samples/choices.xml38
-rw-r--r--keystone/content/common/samples/credentials.json11
-rw-r--r--keystone/content/common/samples/credentials.xml5
-rw-r--r--keystone/content/common/samples/credentialswithapikey.json17
-rw-r--r--keystone/content/common/samples/credentialswithapikey.xml9
-rw-r--r--keystone/content/common/samples/credentialswithec2.json18
-rw-r--r--keystone/content/common/samples/credentialswithec2.xml7
-rw-r--r--keystone/content/common/samples/credentialswiths3.json17
-rw-r--r--keystone/content/common/samples/credentialswiths3.xml7
-rw-r--r--keystone/content/common/samples/ec2Credentials.json7
-rw-r--r--keystone/content/common/samples/ec2Credentials.xml7
-rw-r--r--keystone/content/common/samples/endpoint.json14
-rw-r--r--keystone/content/common/samples/endpoint.xml18
-rw-r--r--keystone/content/common/samples/endpointTemplate.json15
-rw-r--r--keystone/content/common/samples/endpointTemplate.xml18
-rw-r--r--keystone/content/common/samples/endpointTemplateWithOnlyId.json5
-rw-r--r--keystone/content/common/samples/endpointTemplateWithOnlyId.xml6
-rw-r--r--keystone/content/common/samples/endpointTemplates.json59
-rw-r--r--keystone/content/common/samples/endpointTemplates.xml67
-rw-r--r--keystone/content/common/samples/endpoints.json65
-rw-r--r--keystone/content/common/samples/endpoints.xml76
-rw-r--r--keystone/content/common/samples/ext-getuser.json21
-rw-r--r--keystone/content/common/samples/ext-getuser.xml13
-rw-r--r--keystone/content/common/samples/extension.json21
-rw-r--r--keystone/content/common/samples/extension.xml23
-rw-r--r--keystone/content/common/samples/extensions.json44
-rw-r--r--keystone/content/common/samples/extensions.xml39
-rw-r--r--keystone/content/common/samples/getuser-1.json24
-rw-r--r--keystone/content/common/samples/getuser-1.xml13
-rw-r--r--keystone/content/common/samples/identity_fault.json7
-rw-r--r--keystone/content/common/samples/identity_fault.xml6
-rw-r--r--keystone/content/common/samples/item_not_found.json7
-rw-r--r--keystone/content/common/samples/item_not_found.xml6
-rw-r--r--keystone/content/common/samples/norequestbody.txt1
-rw-r--r--keystone/content/common/samples/noresponsebody.txt1
-rw-r--r--keystone/content/common/samples/passwordcredentials.json6
-rw-r--r--keystone/content/common/samples/passwordcredentials.xml4
-rw-r--r--keystone/content/common/samples/role.json7
-rw-r--r--keystone/content/common/samples/role.xml4
-rw-r--r--keystone/content/common/samples/roles.json10
-rw-r--r--keystone/content/common/samples/roles.xml6
-rw-r--r--keystone/content/common/samples/s3Credentials.json7
-rw-r--r--keystone/content/common/samples/s3Credentials.xml7
-rw-r--r--keystone/content/common/samples/samplerequestheader.txt4
-rw-r--r--keystone/content/common/samples/sampleresponseheader.txt4
-rw-r--r--keystone/content/common/samples/service.json8
-rw-r--r--keystone/content/common/samples/service.xml4
-rw-r--r--keystone/content/common/samples/services.json17
-rw-r--r--keystone/content/common/samples/services.xml6
-rw-r--r--keystone/content/common/samples/tenant.json8
-rw-r--r--keystone/content/common/samples/tenant.xml5
-rw-r--r--keystone/content/common/samples/tenantlock.json5
-rw-r--r--keystone/content/common/samples/tenantlock.xml4
-rw-r--r--keystone/content/common/samples/tenants-1.json16
-rw-r--r--keystone/content/common/samples/tenants-1.xml10
-rw-r--r--keystone/content/common/samples/tenants-2.json20
-rw-r--r--keystone/content/common/samples/tenants-2.xml13
-rw-r--r--keystone/content/common/samples/tenants-3.json16
-rw-r--r--keystone/content/common/samples/tenants-3.xml10
-rw-r--r--keystone/content/common/samples/tenants-request.txt5
-rw-r--r--keystone/content/common/samples/tenants.json17
-rw-r--r--keystone/content/common/samples/tenants.xml14
-rw-r--r--keystone/content/common/samples/tenantwithoutid.json7
-rw-r--r--keystone/content/common/samples/tenantwithoutid.xml5
-rw-r--r--keystone/content/common/samples/updatedtenant.json8
-rw-r--r--keystone/content/common/samples/updatedtenant.xml5
-rw-r--r--keystone/content/common/samples/user.json8
-rw-r--r--keystone/content/common/samples/user.xml4
-rw-r--r--keystone/content/common/samples/users.json17
-rw-r--r--keystone/content/common/samples/users.xml9
-rw-r--r--keystone/content/common/samples/userwithenabledonly.json5
-rw-r--r--keystone/content/common/samples/userwithenabledonly.xml5
-rw-r--r--keystone/content/common/samples/userwithoutid.json7
-rw-r--r--keystone/content/common/samples/userwithoutid.xml4
-rw-r--r--keystone/content/common/samples/validatetoken.json28
-rw-r--r--keystone/content/common/samples/validatetoken.xml12
-rw-r--r--keystone/content/common/samples/version-atom.xml19
-rw-r--r--keystone/content/common/samples/version.json33
-rw-r--r--keystone/content/common/samples/version.xml23
-rw-r--r--keystone/content/common/samples/versions-atom.xml29
-rw-r--r--keystone/content/common/samples/versions.json38
-rw-r--r--keystone/content/common/samples/versions.xml24
-rw-r--r--keystone/content/common/style/schema.css82
-rw-r--r--keystone/content/common/style/shjs/sh_acid.css151
-rw-r--r--keystone/content/common/style/shjs/sh_darkblue.css151
-rw-r--r--keystone/content/common/style/shjs/sh_emacs.css139
-rw-r--r--keystone/content/common/style/shjs/sh_night.css151
-rw-r--r--keystone/content/common/style/shjs/sh_pablo.css151
-rw-r--r--keystone/content/common/style/shjs/sh_print.css145
-rw-r--r--keystone/content/common/style/shjs/sh_style.css66
-rw-r--r--keystone/content/common/style/shjs/sh_whitengrey.css139
-rw-r--r--keystone/content/common/xsd/OS-KSADM.xsd108
-rw-r--r--keystone/content/common/xsd/OS-KSCATALOG.xsd193
-rw-r--r--keystone/content/common/xsd/OS-KSEC2-credentials.xsd35
-rw-r--r--keystone/content/common/xsd/OS-KSS3-credentials.xsd35
-rw-r--r--keystone/content/common/xsd/RAX-KSADM-credentials.xsd33
-rw-r--r--keystone/content/common/xsd/RAX-KSADM-users.xsd53
-rw-r--r--keystone/content/common/xsd/RAX-KSGRP-groups.xsd53
-rw-r--r--keystone/content/common/xsd/RAX-KSKEY-credentials.xsd52
-rw-r--r--keystone/content/common/xsd/RAX-KSQA-secretQA.xsd51
-rw-r--r--keystone/content/common/xsd/api-common.xsd55
-rw-r--r--keystone/content/common/xsd/api.xsd22
-rw-r--r--keystone/content/common/xsd/atom/atom.xsd115
-rw-r--r--keystone/content/common/xsd/atom/xml.xsd287
-rw-r--r--keystone/content/common/xsd/credentials.xsd105
-rw-r--r--keystone/content/common/xsd/endpoints.xsd161
-rw-r--r--keystone/content/common/xsd/extensions.xsd60
-rw-r--r--keystone/content/common/xsd/fault.xsd138
-rw-r--r--keystone/content/common/xsd/roles.xsd66
-rw-r--r--keystone/content/common/xsd/services.xsd103
-rw-r--r--keystone/content/common/xsd/tenant.xsd151
-rw-r--r--keystone/content/common/xsd/token.xsd298
-rw-r--r--keystone/content/common/xsd/user.xsd131
-rw-r--r--keystone/content/common/xsd/version.xsd357
-rw-r--r--keystone/content/common/xslt/schema.xslt1342
-rw-r--r--keystone/content/multiple_choice.json.tpl26
-rw-r--r--keystone/content/multiple_choice.xml.tpl16
-rw-r--r--keystone/content/service/OS-KSEC2-service-devguide.pdfbin95313 -> 0 bytes
-rw-r--r--keystone/content/service/RAX-KSGRP-service-devguide.pdfbin97711 -> 0 bytes
-rw-r--r--keystone/content/service/RAX-KSKEY-service-devguide.pdfbin96715 -> 0 bytes
-rw-r--r--keystone/content/service/extensions.json5
-rw-r--r--keystone/content/service/extensions.xml5
-rw-r--r--keystone/content/service/identity.wadl182
-rw-r--r--keystone/content/service/identitydevguide.pdfbin274329 -> 0 bytes
-rw-r--r--keystone/content/service/version.atom.tpl29
-rw-r--r--keystone/content/service/version.json.tpl32
-rw-r--r--keystone/content/service/version.xml.tpl29
-rw-r--r--keystone/contrib/admin_crud/__init__.py1
-rw-r--r--keystone/contrib/admin_crud/core.py150
-rw-r--r--keystone/contrib/ec2/__init__.py1
-rw-r--r--keystone/contrib/ec2/backends/__init__.py (renamed from keystone/contrib/extensions/admin/osec2/__init__.py)0
-rw-r--r--keystone/contrib/ec2/backends/kvs.py31
-rw-r--r--keystone/contrib/ec2/backends/sql.py52
-rw-r--r--keystone/contrib/ec2/core.py288
-rw-r--r--keystone/contrib/extensions/__init__.py52
-rw-r--r--keystone/contrib/extensions/admin/__init__.py36
-rw-r--r--keystone/contrib/extensions/admin/extension.py20
-rw-r--r--keystone/contrib/extensions/admin/hpidm/__init__.py25
-rw-r--r--keystone/contrib/extensions/admin/hpidm/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/hpidm/extension.xml21
-rw-r--r--keystone/contrib/extensions/admin/osec2/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/osec2/extension.xml19
-rw-r--r--keystone/contrib/extensions/admin/osksadm/__init__.py149
-rw-r--r--keystone/contrib/extensions/admin/osksadm/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/osksadm/extension.xml15
-rw-r--r--keystone/contrib/extensions/admin/oskscatalog/__init__.py63
-rw-r--r--keystone/contrib/extensions/admin/oskscatalog/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/oskscatalog/extension.xml15
-rw-r--r--keystone/contrib/extensions/admin/osksvalidate/__init__.py37
-rw-r--r--keystone/contrib/extensions/admin/osksvalidate/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/osksvalidate/extension.xml15
-rw-r--r--keystone/contrib/extensions/admin/osksvalidate/handler.py46
-rw-r--r--keystone/contrib/extensions/admin/raxgrp/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/raxgrp/extension.xml15
-rw-r--r--keystone/contrib/extensions/admin/raxkey/extension.json21
-rw-r--r--keystone/contrib/extensions/admin/raxkey/extension.xml15
-rw-r--r--keystone/contrib/extensions/admin/raxkey/frontend.py105
-rw-r--r--keystone/contrib/extensions/extensions.json5
-rw-r--r--keystone/contrib/extensions/extensions.xml5
-rw-r--r--keystone/contrib/extensions/service/__init__.py1
-rw-r--r--keystone/contrib/extensions/service/osec2/extension.json16
-rw-r--r--keystone/contrib/extensions/service/osec2/extension.xml16
-rw-r--r--keystone/contrib/extensions/service/osec2/frontend.py105
-rwxr-xr-xkeystone/contrib/extensions/service/raxgrp/api.py141
-rw-r--r--keystone/contrib/extensions/service/raxgrp/extension.json16
-rw-r--r--keystone/contrib/extensions/service/raxgrp/extension.xml13
-rw-r--r--keystone/contrib/extensions/service/raxkey/__init__.py0
-rw-r--r--keystone/contrib/extensions/service/raxkey/extension.json16
-rw-r--r--keystone/contrib/extensions/service/raxkey/extension.xml13
-rw-r--r--keystone/contrib/extensions/service/raxkey/frontend.py62
-rw-r--r--keystone/contrib/s3/__init__.py1
-rw-r--r--keystone/contrib/s3/core.py37
-rw-r--r--keystone/controllers/__init__.py0
-rw-r--r--keystone/controllers/base_controller.py44
-rw-r--r--keystone/controllers/credentials.py71
-rw-r--r--keystone/controllers/endpointtemplates.py99
-rw-r--r--keystone/controllers/extensions.py48
-rw-r--r--keystone/controllers/roles.py101
-rwxr-xr-xkeystone/controllers/services.py69
-rw-r--r--keystone/controllers/staticfiles.py89
-rw-r--r--keystone/controllers/tenant.py81
-rw-r--r--keystone/controllers/token.py141
-rw-r--r--keystone/controllers/user.py105
-rw-r--r--keystone/controllers/version.py116
-rw-r--r--keystone/exception.py58
-rw-r--r--keystone/frontends/__init__.py0
-rw-r--r--keystone/frontends/d5_compat.py455
-rw-r--r--keystone/frontends/legacy_token_auth.py126
-rw-r--r--keystone/frontends/normalizer.py212
-rw-r--r--keystone/identity/__init__.py1
-rw-r--r--keystone/identity/backends/__init__.py (renamed from keystone/contrib/extensions/admin/raxkey/__init__.py)0
-rw-r--r--keystone/identity/backends/kvs.py222
-rw-r--r--keystone/identity/backends/pam.py29
-rw-r--r--keystone/identity/backends/sql.py366
-rw-r--r--keystone/identity/core.py537
-rw-r--r--keystone/logic/__init__.py0
-rw-r--r--keystone/logic/extension_reader.py142
-rwxr-xr-xkeystone/logic/service.py1558
-rw-r--r--keystone/logic/signer.py166
-rw-r--r--keystone/logic/types/__init__.py0
-rw-r--r--keystone/logic/types/atom.py57
-rwxr-xr-xkeystone/logic/types/auth.py673
-rw-r--r--keystone/logic/types/credential.py125
-rw-r--r--keystone/logic/types/endpoint.py363
-rw-r--r--keystone/logic/types/extension.py12
-rwxr-xr-xkeystone/logic/types/fault.py165
-rw-r--r--keystone/logic/types/tenant.py150
-rwxr-xr-xkeystone/logic/types/user.py280
-rw-r--r--keystone/manage/__init__.py507
-rw-r--r--keystone/manage/api.py210
-rw-r--r--keystone/manage2/__init__.py107
-rw-r--r--keystone/manage2/base.py111
-rw-r--r--keystone/manage2/commands/__init__.py0
-rw-r--r--keystone/manage2/commands/create_credential.py43
-rw-r--r--keystone/manage2/commands/create_endpoint_template.py62
-rw-r--r--keystone/manage2/commands/create_role.py36
-rw-r--r--keystone/manage2/commands/create_service.py42
-rw-r--r--keystone/manage2/commands/create_tenant.py38
-rw-r--r--keystone/manage2/commands/create_token.py59
-rw-r--r--keystone/manage2/commands/create_user.py55
-rw-r--r--keystone/manage2/commands/delete_credential.py18
-rw-r--r--keystone/manage2/commands/delete_endpoint_template.py18
-rw-r--r--keystone/manage2/commands/delete_role.py18
-rw-r--r--keystone/manage2/commands/delete_service.py18
-rw-r--r--keystone/manage2/commands/delete_tenant.py21
-rw-r--r--keystone/manage2/commands/delete_token.py18
-rw-r--r--keystone/manage2/commands/delete_user.py21
-rw-r--r--keystone/manage2/commands/downgrade_database.py19
-rw-r--r--keystone/manage2/commands/goto_database.py26
-rw-r--r--keystone/manage2/commands/grant_role.py45
-rw-r--r--keystone/manage2/commands/list_credentials.py23
-rw-r--r--keystone/manage2/commands/list_endpoint_templates.py23
-rw-r--r--keystone/manage2/commands/list_endpoints.py20
-rw-r--r--keystone/manage2/commands/list_role_grants.py50
-rw-r--r--keystone/manage2/commands/list_roles.py20
-rw-r--r--keystone/manage2/commands/list_services.py21
-rw-r--r--keystone/manage2/commands/list_tenants.py22
-rw-r--r--keystone/manage2/commands/list_tokens.py23
-rw-r--r--keystone/manage2/commands/list_users.py23
-rw-r--r--keystone/manage2/commands/map_endpoint.py37
-rw-r--r--keystone/manage2/commands/revoke_role.py40
-rw-r--r--keystone/manage2/commands/sync_database.py19
-rw-r--r--keystone/manage2/commands/unmap_endpoint.py28
-rw-r--r--keystone/manage2/commands/update_credential.py55
-rw-r--r--keystone/manage2/commands/update_endpoint_template.py88
-rw-r--r--keystone/manage2/commands/update_role.py40
-rw-r--r--keystone/manage2/commands/update_service.py47
-rw-r--r--keystone/manage2/commands/update_tenant.py40
-rw-r--r--keystone/manage2/commands/update_token.py42
-rw-r--r--keystone/manage2/commands/update_user.py62
-rw-r--r--keystone/manage2/commands/upgrade_database.py19
-rw-r--r--keystone/manage2/commands/version.py53
-rw-r--r--keystone/manage2/commands/version_control_database.py15
-rw-r--r--keystone/manage2/common.py64
-rw-r--r--keystone/manage2/mixins.py42
-rw-r--r--keystone/managers/__init__.py0
-rw-r--r--keystone/managers/credential.py46
-rw-r--r--keystone/managers/endpoint.py65
-rw-r--r--keystone/managers/endpoint_template.py69
-rw-r--r--keystone/managers/grant.py59
-rw-r--r--keystone/managers/role.py74
-rw-r--r--keystone/managers/service.py65
-rw-r--r--keystone/managers/tenant.py75
-rw-r--r--keystone/managers/token.py61
-rw-r--r--keystone/managers/user.py84
-rw-r--r--keystone/middleware/__init__.py1
-rw-r--r--keystone/middleware/auth_basic.py190
-rw-r--r--keystone/middleware/auth_openid.py125
-rwxr-xr-x[-rw-r--r--]keystone/middleware/auth_token.py670
-rw-r--r--keystone/middleware/core.py112
-rw-r--r--keystone/middleware/crypt.py74
-rw-r--r--keystone/middleware/ec2_token.py92
-rw-r--r--keystone/middleware/glance_auth_token.py10
-rw-r--r--keystone/middleware/nova_auth_token.py104
-rw-r--r--keystone/middleware/nova_keystone_context.py69
-rwxr-xr-xkeystone/middleware/quantum_auth_token.py461
-rw-r--r--keystone/middleware/remoteauth.py128
-rw-r--r--keystone/middleware/s3_token.py151
-rw-r--r--keystone/middleware/swift_auth.py145
-rw-r--r--keystone/middleware/url.py41
-rw-r--r--keystone/models.py813
-rw-r--r--keystone/policy/__init__.py1
-rw-r--r--keystone/policy/backends/__init__.py (renamed from keystone/contrib/extensions/service/osec2/__init__.py)0
-rw-r--r--keystone/policy/backends/simple.py23
-rw-r--r--keystone/policy/core.py21
-rw-r--r--keystone/routers/__init__.py0
-rwxr-xr-xkeystone/routers/admin.py145
-rw-r--r--keystone/routers/service.py117
-rwxr-xr-xkeystone/server.py186
-rw-r--r--keystone/service.py448
-rw-r--r--keystone/test.py248
-rw-r--r--keystone/test/EchoSOAPUI.xml2
-rw-r--r--keystone/test/IdentitySOAPUI.xml1355
-rw-r--r--keystone/test/__init__.py723
-rw-r--r--keystone/test/client/__init__.py39
-rw-r--r--keystone/test/client/test_client.py101
-rw-r--r--keystone/test/client/test_d5_compat_calls.py169
-rw-r--r--keystone/test/client/test_extensions.py68
-rw-r--r--keystone/test/client/test_frontends.py38
-rw-r--r--keystone/test/client/test_keystone_manage.py54
-rw-r--r--keystone/test/client/test_middleware.py124
-rw-r--r--keystone/test/client/test_request_specs.py124
-rw-r--r--keystone/test/client/test_static_files.py94
-rw-r--r--keystone/test/etc/ldap.conf.template60
-rw-r--r--keystone/test/etc/memcache.conf.template58
-rw-r--r--keystone/test/etc/sql.conf.template54
-rw-r--r--keystone/test/etc/sql_no_hpidm.conf.template54
-rw-r--r--keystone/test/etc/ssl.conf.template58
-rw-r--r--keystone/test/functional/__init__.py25
-rw-r--r--keystone/test/functional/common.py1738
-rw-r--r--keystone/test/functional/test_auth.py494
-rw-r--r--keystone/test/functional/test_authentication.py352
-rw-r--r--keystone/test/functional/test_credentials.py231
-rw-r--r--keystone/test/functional/test_endpoints.py740
-rw-r--r--keystone/test/functional/test_extensions.py258
-rw-r--r--keystone/test/functional/test_issue_85.py43
-rw-r--r--keystone/test/functional/test_roles.py559
-rw-r--r--keystone/test/functional/test_services.py294
-rw-r--r--keystone/test/functional/test_static_files.py90
-rw-r--r--keystone/test/functional/test_tenants.py598
-rw-r--r--keystone/test/functional/test_token.py207
-rw-r--r--keystone/test/functional/test_users.py406
-rw-r--r--keystone/test/sampledata.py137
-rw-r--r--keystone/test/unit/__init__.py0
-rw-r--r--keystone/test/unit/base.py385
-rw-r--r--keystone/test/unit/decorators.py49
-rw-r--r--keystone/test/unit/test_auth.py187
-rw-r--r--keystone/test/unit/test_authn_ec2.py303
-rw-r--r--keystone/test/unit/test_authn_password.py65
-rw-r--r--keystone/test/unit/test_authn_s3.py245
-rw-r--r--keystone/test/unit/test_backends.py199
-rw-r--r--keystone/test/unit/test_buffout.py91
-rw-r--r--keystone/test/unit/test_cfg.py826
-rw-r--r--keystone/test/unit/test_commands.py1241
-rw-r--r--keystone/test/unit/test_commands_v1.py77
-rw-r--r--keystone/test/unit/test_config.py70
-rw-r--r--keystone/test/unit/test_controller_version.py139
-rw-r--r--keystone/test/unit/test_d5_compat.py174
-rw-r--r--keystone/test/unit/test_extensions.py81
-rw-r--r--keystone/test/unit/test_logic_auth.py132
-rw-r--r--keystone/test/unit/test_migrations.py136
-rw-r--r--keystone/test/unit/test_models.py131
-rw-r--r--keystone/test/unit/test_models_endpoint.py78
-rw-r--r--keystone/test/unit/test_models_endpoint_template.py79
-rw-r--r--keystone/test/unit/test_models_role.py115
-rw-r--r--keystone/test/unit/test_models_service.py90
-rw-r--r--keystone/test/unit/test_models_services.py47
-rw-r--r--keystone/test/unit/test_models_tenant.py167
-rw-r--r--keystone/test/unit/test_models_token.py70
-rw-r--r--keystone/test/unit/test_models_user.py69
-rw-r--r--keystone/test/unit/test_normalizingfilter.py94
-rw-r--r--keystone/test/unit/test_server.py88
-rw-r--r--keystone/test/unit/test_service_logic.py65
-rw-r--r--keystone/test/unit/test_utils.py89
-rw-r--r--keystone/test/unit/test_wsgi.py71
-rw-r--r--keystone/test/utils.py61
-rw-r--r--keystone/token/__init__.py1
-rw-r--r--keystone/token/backends/__init__.py (renamed from keystone/contrib/extensions/service/raxgrp/__init__.py)0
-rw-r--r--keystone/token/backends/kvs.py32
-rw-r--r--keystone/token/backends/memcache.py58
-rw-r--r--keystone/token/backends/sql.py69
-rw-r--r--keystone/token/core.py82
-rw-r--r--keystone/tools/__init__.py19
-rw-r--r--keystone/tools/buffout.py89
-rw-r--r--keystone/tools/tracer.py159
-rwxr-xr-xkeystone/utils.py312
-rw-r--r--keystone/version.py31
490 files changed, 4964 insertions, 48276 deletions
diff --git a/keystone/__init__.py b/keystone/__init__.py
index e3771d3e..e69de29b 100644
--- a/keystone/__init__.py
+++ b/keystone/__init__.py
@@ -1,19 +0,0 @@
-# Copyright (C) 2011 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 gettext
-
-# This installs the _(...) function as a built-in so all other modules
-# don't need to.
-gettext.install('keystone')
diff --git a/keystone/backends/__init__.py b/keystone/backends/__init__.py
deleted file mode 100755
index 84d73d04..00000000
--- a/keystone/backends/__init__.py
+++ /dev/null
@@ -1,56 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 logging
-
-from keystone.cfg import NoSuchOptError
-from keystone import config
-from keystone import utils
-
-LOG = logging.getLogger(__name__)
-
-CONF = config.CONF
-DEFAULT_BACKENDS = "keystone.backends.sqlalchemy"
-
-#Configs applicable to all backends.
-SHOULD_HASH_PASSWORD = True
-
-
-class GroupConf(CONF.__class__):
- """ Allows direct access to the values in the backend groups."""
- def __init__(self, group, *args, **kwargs):
- self.group = group
- super(GroupConf, self).__init__(*args, **kwargs)
-
- def __getattr__(self, att):
- try:
- # pylint: disable=W0212
- return CONF._get(att, self.group)
- except NoSuchOptError:
- return None
-
-
-def configure_backends():
- """Load backends given in the 'backends' option."""
- global SHOULD_HASH_PASSWORD # pylint: disable=W0603
- SHOULD_HASH_PASSWORD = CONF.hash_password
-
- backend_names = CONF.backends or DEFAULT_BACKENDS
- for module_name in backend_names.split(","):
- backend_module = utils.import_module(module_name)
- backend_conf = GroupConf(module_name)
- backend_module.configure_backend(backend_conf)
diff --git a/keystone/backends/api.py b/keystone/backends/api.py
deleted file mode 100755
index c44805b3..00000000
--- a/keystone/backends/api.py
+++ /dev/null
@@ -1,439 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-# pylint: disable=W0603, R0921
-
-
-#Base APIs
-class BaseUserAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- def get_all(self):
- """ Get all users """
- raise NotImplementedError
-
- def create(self, values):
- """ Create a user
-
- The backend will assign an ID if is not passed in
-
- :param values: dict of user attributes (models.User works)
- :returns: models.User - the created user object
-
- """
- raise NotImplementedError
-
- def get(self, id):
- """ Get a user
-
- :param id: string - the user ID to get
- :returns: models.User - the user object
-
- """
- raise NotImplementedError
-
- def get_by_name(self, name):
- """ Get a user by username
-
- :param name: string - the user name
- :returns: models.User
-
- """
- raise NotImplementedError
-
- def get_by_email(self, email):
- """ Get a user by email
-
- :param name: string - the user email
- :returns: models.User
-
- """
- raise NotImplementedError
-
- def get_page(self, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def user_roles_by_tenant(self, user_id, tenant_id):
- raise NotImplementedError
-
- def update(self, id, values):
- """ Update a user
-
- :param values: dict of user attributes (models.User works)
- :returns: models.User - the updated user object
-
- """
- raise NotImplementedError
-
- def delete(self, id):
- """ Delete a user
-
- :param id: string - the user id
-
- """
- raise NotImplementedError
-
- def get_by_tenant(self, user_id, tenant_id):
- """ Gets a user for a tenant
-
- Same as get user, but also validates the user is related to that tenant
- either through the default tenant (user.tenant_id) or by role
-
- :param user_id: string - id of user
- :param tenant_id: string - id of tenant
- :returns: models.User - the user object valid on the tenant, othwerwise
- None
-
- """
- raise NotImplementedError
-
- def get_by_access(self, access):
- raise NotImplementedError
-
- def users_get_by_tenant(self, user_id, tenant_id):
- raise NotImplementedError
-
- def user_role_add(self, values):
- """ Adds a user to a role (optionally for a tenant) - 'grant'
-
- This creates a new UserRoleAssociation based on the passed in values
-
- :param values: dict of values containing user_id, role_id, and
- optionally a tenant_id
-
- """
- raise NotImplementedError
-
- def users_get_page(self, marker, limit):
- raise NotImplementedError
-
- def users_get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def users_get_by_tenant_get_page(self, tenant_id, role_id, marker, limit):
- raise NotImplementedError
-
- def users_get_by_tenant_get_page_markers(self, tenant_id,
- role_id, marker, limit):
- raise NotImplementedError
-
- def check_password(self, user_id, password):
- """ Check a user password
-
- The backend should handle any encryption/decryption
-
- :param user_id: string - user id
- :param password: string - the password to check
- :returns: True/False
-
- """
- raise NotImplementedError
-
-
-class BaseTokenAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- def create(self, values):
- raise NotImplementedError
-
- def get(self, id):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
- def get_for_user(self, user_id):
- raise NotImplementedError
-
- def get_for_user_by_tenant(self, user_id, tenant_id):
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
-
-class BaseTenantAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- def create(self, values):
- raise NotImplementedError
-
- def get(self, id):
- raise NotImplementedError
-
- def get_by_name(self, name):
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
- def list_for_user_get_page(self, user, marker, limit):
- raise NotImplementedError
-
- def list_for_user_get_page_markers(self, user, marker, limit):
- raise NotImplementedError
-
- def get_page(self, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def update(self, id, values):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
- def get_all_endpoints(self, tenant_id):
- raise NotImplementedError
-
- def get_role_assignments(self, tenant_id):
- raise NotImplementedError
-
-
-class BaseRoleAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- #
- # Role Methods
- #
- def create(self, values):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
- def get(self, id):
- raise NotImplementedError
-
- def get_by_name(self, name):
- raise NotImplementedError
-
- def get_by_service(self, service_id):
- raise NotImplementedError
-
- def get_by_service_get_page(self, service_id, marker, limit):
- """ Get one page of roles by service"""
- raise NotImplementedError
-
- def get_by_service_get_page_markers(self, service_id, marker, limit):
- """ Calculate pagination markers for roles by service """
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
- def get_page(self, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- #
- # Role-Grant Methods
- #
- def rolegrant_get(self, id):
- """ Get a UserRoleAssociation (role grant) by id """
- raise NotImplementedError
-
- def rolegrant_delete(self, id):
- """ Delete a UserRoleAssociation (role grant) by id """
- raise NotImplementedError
-
- def rolegrant_list_by_role(self, id):
- """ Get a list of all (global and tenant) grants for this role """
- raise NotImplementedError
-
- def rolegrant_get_by_ids(self, user_id, role_id, tenant_id):
- raise NotImplementedError
-
- def list_global_roles_for_user(self, user_id):
- """ Get a list of all global roles granted to this user.
-
- :param user_id: string - id of user
-
- """
- raise NotImplementedError
-
- def list_tenant_roles_for_user(self, user_id, tenant_id):
- """ Get a list of all tenant roles granted to this user.
-
- :param user_id: string - id of user
- :param tenant_id: string - id of tenant
-
- """
- raise NotImplementedError
-
- def rolegrant_get_page(self, marker, limit, user_id, tenant_id):
- raise NotImplementedError
-
- def rolegrant_get_page_markers(self, user_id, tenant_id, marker, limit):
- raise NotImplementedError
-
-
-class BaseEndpointTemplateAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- def create(self, values):
- raise NotImplementedError
-
- def update(self, id, values):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
- def get(self, id):
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
- def get_by_service(self, service_id):
- raise NotImplementedError
-
- def get_page(self, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def get_by_service_get_page(self, service_id, marker, limit):
- raise NotImplementedError
-
- def get_by_service_get_page_markers(self, service_id, marker, limit):
- raise NotImplementedError
-
- def endpoint_get_by_tenant_get_page(self, tenant_id, marker, limit):
- raise NotImplementedError
-
- def endpoint_get_by_tenant_get_page_markers(self, tenant_id, marker,
- limit):
- raise NotImplementedError
-
- def endpoint_get_by_endpoint_template(self, endpoint_template_id):
- raise NotImplementedError
-
- def endpoint_add(self, values):
- raise NotImplementedError
-
- def endpoint_get(self, id):
- raise NotImplementedError
-
- def endpoint_get_by_tenant(self, tenant_id):
- raise NotImplementedError
-
- def endpoint_delete(self, id):
- raise NotImplementedError
-
-
-class BaseServiceAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- def create(self, values):
- raise NotImplementedError
-
- def get(self, id):
- raise NotImplementedError
-
- def get_by_name(self, name):
- raise NotImplementedError
-
- def get_by_name_and_type(self, name, type):
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
- def get_page(self, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
-
-class BaseCredentialsAPI(object):
- def __init__(self, *args, **kw):
- pass
-
- def create(self, values):
- raise NotImplementedError
-
- def update(self, id, credential):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
- def get(self, id):
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
- def get_by_access(self, access):
- raise NotImplementedError
-
-
-#API
-#TODO(Yogi) Refactor all API to separate classes specific to models.
-ENDPOINT_TEMPLATE = BaseEndpointTemplateAPI()
-ROLE = BaseRoleAPI()
-TENANT = BaseTenantAPI()
-TOKEN = BaseTokenAPI()
-USER = BaseUserAPI()
-SERVICE = BaseServiceAPI()
-CREDENTIALS = BaseCredentialsAPI()
-
-
-# Function to dynamically set module references.
-def set_value(variable_name, value):
- if variable_name == 'endpoint_template':
- global ENDPOINT_TEMPLATE
- ENDPOINT_TEMPLATE = value
- elif variable_name == 'role':
- global ROLE
- ROLE = value
- elif variable_name == 'tenant':
- global TENANT
- TENANT = value
- elif variable_name == 'token':
- global TOKEN
- TOKEN = value
- elif variable_name == 'user':
- global USER
- USER = value
- elif variable_name == 'service':
- global SERVICE
- SERVICE = value
- elif variable_name == 'credentials':
- global CREDENTIALS
- CREDENTIALS = value
diff --git a/keystone/backends/backendutils.py b/keystone/backends/backendutils.py
deleted file mode 100644
index 3e16f214..00000000
--- a/keystone/backends/backendutils.py
+++ /dev/null
@@ -1,60 +0,0 @@
-import logging
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-from keystone.backends import models
-import keystone.backends as backends
-# pylint: disable=E0611
-try:
- from passlib.hash import sha512_crypt as sc
-except ImportError as exc:
- logger.exception(exc)
- raise exc
-
-
-def __get_hashed_password(password):
- if password:
- return __make_password(password)
- else:
- return None
-
-
-def set_hashed_password(values):
- """
- Sets hashed password for password.
- """
- if backends.SHOULD_HASH_PASSWORD:
- if isinstance(values, dict) and 'password' in values.keys():
- values['password'] = __get_hashed_password(values['password'])
- elif isinstance(values, models.User):
- values.password = __get_hashed_password(values.password)
- else:
- logger.warn("Could not hash password on unsupported type: %s" %
- type(values))
-
-
-def check_password(raw_password, enc_password):
- """
- Compares raw password and encoded password.
- """
- if not raw_password:
- return False
- if backends.SHOULD_HASH_PASSWORD:
- return sc.verify(raw_password, enc_password)
- else:
- return enc_password == raw_password
-
-
-def __make_password(raw_password):
- """
- Produce a new encoded password.
- """
- if raw_password is None:
- return None
- hsh = __get_hexdigest(raw_password)
- return '%s' % (hsh)
-
-
-#Refer http://packages.python.org/passlib/lib/passlib.hash.sha512_crypt.html
-#Using the default properties as of now.Salt gets generated automatically.
-def __get_hexdigest(raw_password):
- return sc.encrypt(raw_password)
diff --git a/keystone/backends/ldap/__init__.py b/keystone/backends/ldap/__init__.py
deleted file mode 100644
index b3e0b31b..00000000
--- a/keystone/backends/ldap/__init__.py
+++ /dev/null
@@ -1,33 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 ldap
-
-import keystone.backends.api as top_api
-import keystone.backends.models as top_models
-from keystone import utils
-
-from . import api
-from . import models
-
-
-def configure_backend(conf):
- api_obj = api.API(conf)
- for name in api_obj.apis:
- top_api.set_value(name, getattr(api_obj, name))
- for model_name in models.__all__:
- top_models.set_value(model_name, getattr(models, model_name))
diff --git a/keystone/backends/ldap/api/__init__.py b/keystone/backends/ldap/api/__init__.py
deleted file mode 100644
index c739b4da..00000000
--- a/keystone/backends/ldap/api/__init__.py
+++ /dev/null
@@ -1,111 +0,0 @@
-import ldap
-import logging
-
-from .. import fakeldap
-from .tenant import TenantAPI
-from .user import UserAPI
-from .role import RoleAPI
-
-LOG = logging.getLogger('keystone.backends.ldap.api')
-
-
-def py2ldap(val):
- if isinstance(val, str):
- return val
- elif isinstance(val, bool):
- return 'TRUE' if val else 'FALSE'
- else:
- return str(val)
-
-LDAP_VALUES = {
- 'TRUE': True,
- 'FALSE': False,
-}
-
-
-def ldap2py(val):
- try:
- return LDAP_VALUES[val]
- except KeyError:
- pass
- try:
- return int(val)
- except ValueError:
- pass
- return val
-
-
-def safe_iter(attrs):
- if attrs is None:
- return
- elif isinstance(attrs, list):
- for e in attrs:
- yield e
- else:
- yield attrs
-
-
-class LDAPWrapper(object):
- def __init__(self, url):
- LOG.debug("LDAP init: url=%s", url)
- self.conn = ldap.initialize(url)
-
- def simple_bind_s(self, user, password):
- LOG.debug("LDAP bind: dn=%s", user)
- return self.conn.simple_bind_s(user, password)
-
- def add_s(self, dn, attrs):
- ldap_attrs = [(typ, map(py2ldap, safe_iter(values)))
- for typ, values in attrs]
- if LOG.isEnabledFor(logging.DEBUG):
- sane_attrs = [(typ, values if typ != 'userPassword' else ['****'])
- for typ, values in ldap_attrs]
- LOG.debug("LDAP add: dn=%s, attrs=%s", dn, sane_attrs)
- return self.conn.add_s(dn, ldap_attrs)
-
- def search_s(self, dn, scope, query):
- if LOG.isEnabledFor(logging.DEBUG):
- LOG.debug("LDAP search: dn=%s, scope=%s, query=%s", dn,
- fakeldap.scope_names[scope], query)
- res = self.conn.search_s(dn, scope, query)
- return [(dn, dict([(typ, map(ldap2py, values))
- for typ, values in attrs.iteritems()]))
- for dn, attrs in res]
-
- def modify_s(self, dn, modlist):
- ldap_modlist = [(op, typ, None if values is None else
- map(py2ldap, safe_iter(values)))
- for op, typ, values in modlist]
- if LOG.isEnabledFor(logging.DEBUG):
- sane_modlist = [(op, typ, values if typ != 'userPassword'
- else ['****']) for op, typ, values in ldap_modlist]
- LOG.debug("LDAP modify: dn=%s, modlist=%s", dn, sane_modlist)
- return self.conn.modify_s(dn, ldap_modlist)
-
- def delete_s(self, dn):
- LOG.debug("LDAP delete: dn=%s", dn)
- return self.conn.delete_s(dn)
-
-
-class API(object):
- apis = ['tenant', 'user', 'role']
-
- def __init__(self, conf):
- self.LDAP_URL = conf.ldap_url
- self.LDAP_USER = conf.ldap_user
- self.LDAP_PASSWORD = conf.ldap_password
- self.tenant = TenantAPI(self, conf)
- self.user = UserAPI(self, conf)
- self.role = RoleAPI(self, conf)
-
- def get_connection(self, user=None, password=None):
- if self.LDAP_URL.startswith('fake://'):
- conn = fakeldap.initialize(self.LDAP_URL)
- else:
- conn = LDAPWrapper(self.LDAP_URL)
- if user is None:
- user = self.LDAP_USER
- if password is None:
- password = self.LDAP_PASSWORD
- conn.simple_bind_s(user, password)
- return conn
diff --git a/keystone/backends/ldap/api/base.py b/keystone/backends/ldap/api/base.py
deleted file mode 100644
index 1275c08d..00000000
--- a/keystone/backends/ldap/api/base.py
+++ /dev/null
@@ -1,183 +0,0 @@
-import ast
-import ldap
-from itertools import izip, count
-
-
-def _get_redirect(cls, method):
- # pylint: disable=W0613
- def inner(self, *args):
- return getattr(cls(), method)(*args)
- return inner
-
-
-def add_redirects(loc, cls, methods):
- for method in methods:
- loc[method] = _get_redirect(cls, method)
-
-
-class BaseLdapAPI(object):
- DEFAULT_TREE_DN = None
- DEFAULT_STRUCTURAL_CLASSES = None
- DEFAULT_ID_ATTR = 'cn'
- DUMB_MEMBER_DN = 'cn=dumb,dc=nonexistent'
- options_name = None
- object_class = 'top'
- model = None
- attribute_mapping = {}
- attribute_ignore = []
-
- def __init__(self, api, conf):
- self.api = api
- if self.options_name is not None:
- dn = '%s_tree_dn' % self.options_name
- self.tree_dn = conf[dn] or self.DEFAULT_TREE_DN
- structs = '%s_structural_classes' % self.options_name
- lst = conf[structs] or self.DEFAULT_STRUCTURAL_CLASSES
- self.structural_classes = ast.literal_eval(str(lst))
- idatt = '%s_id_attr' % self.options_name
- self.id_attr = conf[idatt] or self.DEFAULT_ID_ATTR
- self.use_dumb_member = conf.use_dumb_member or True
-
- def _id_to_dn(self, id):
- return '%s=%s,%s' % (self.id_attr, ldap.dn.escape_dn_chars(str(id)),
- self.tree_dn)
-
- @staticmethod
- def _dn_to_id(dn):
- return ldap.dn.str2dn(dn)[0][0][1]
-
- # pylint: disable=E1102
- def _ldap_res_to_model(self, res):
- obj = self.model(id=self._dn_to_id(res[0]))
- obj['name'] = obj['id']
- for k in obj:
- if k in self.attribute_ignore:
- continue
- try:
- v = res[1][self.attribute_mapping.get(k, k)]
- except KeyError:
- pass
- else:
- try:
- obj[k] = v[0]
- except IndexError:
- obj[k] = None
- return obj
-
- # pylint: disable=E1102
- def create(self, values):
- conn = self.api.get_connection()
- object_classes = self.structural_classes + [self.object_class]
- attrs = [('objectClass', object_classes)]
- for k, v in values.iteritems():
- if k == 'id' or k in self.attribute_ignore:
- continue
- if v is not None:
- attr_type = self.attribute_mapping.get(k, k)
- attrs.append((attr_type, [v]))
- if 'groupOfNames' in object_classes and self.use_dumb_member:
- attrs.append(('member', [self.DUMB_MEMBER_DN]))
- conn.add_s(self._id_to_dn(values['id']), attrs)
- return self.model(**values)
-
- def _ldap_get(self, id, filter=None):
- conn = self.api.get_connection()
- query = '(objectClass=%s)' % (self.object_class,)
- if filter is not None:
- query = '(&%s%s)' % (filter, query)
- try:
- res = conn.search_s(self._id_to_dn(id), ldap.SCOPE_BASE, query)
- except ldap.NO_SUCH_OBJECT:
- return None
- try:
- return res[0]
- except IndexError:
- return None
-
- def _ldap_get_all(self, filter=None):
- conn = self.api.get_connection()
- query = '(objectClass=%s)' % (self.object_class,)
- if filter is not None:
- query = '(&%s%s)' % (filter, query)
- try:
- return conn.search_s(self.tree_dn, ldap.SCOPE_ONELEVEL, query)
- except ldap.NO_SUCH_OBJECT:
- return []
-
- def get(self, id, filter=None):
- res = self._ldap_get(id, filter)
- if res is None:
- return None
- else:
- return self._ldap_res_to_model(res)
-
- # pylint: disable=W0141
- def get_all(self, filter=None):
- return map(self._ldap_res_to_model, self._ldap_get_all(filter))
-
- def get_page(self, marker, limit):
- return self._get_page(marker, limit, self.get_all())
-
- def get_page_markers(self, marker, limit):
- return self._get_page_markers(marker, limit, self.get_all())
-
- # pylint: disable=W0141
- @staticmethod
- def _get_page(marker, limit, lst, key=lambda e: e.id):
- lst.sort(key=key)
- if not marker:
- return lst[:limit]
- else:
- return filter(lambda e: key(e) > marker, lst)[:limit]
-
- @staticmethod
- def _get_page_markers(marker, limit, lst, key=lambda e: e.id):
- if len(lst) < limit:
- return (None, None)
- lst.sort(key=key)
- if marker is None:
- if len(lst) <= limit + 1:
- nxt = None
- else:
- nxt = key(lst[limit])
- return (None, nxt)
-
- for i, item in izip(count(), lst):
- k = key(item)
- if k >= marker:
- break
- # pylint: disable=W0631
- if i <= limit:
- prv = None
- else:
- prv = key(lst[i - limit])
- if i + limit >= len(lst) - 1:
- nxt = None
- else:
- nxt = key(lst[i + limit])
- return (prv, nxt)
-
- def update(self, id, values, old_obj=None):
- if old_obj is None:
- old_obj = self.get(id)
- modlist = []
- for k, v in values.iteritems():
- if k == 'id' or k in self.attribute_ignore:
- continue
- if v is None:
- if old_obj[k] is not None:
- modlist.append((ldap.MOD_DELETE,
- self.attribute_mapping.get(k, k), None))
- else:
- if old_obj[k] != v:
- if old_obj[k] is None:
- op = ldap.MOD_ADD
- else:
- op = ldap.MOD_REPLACE
- modlist.append((op, self.attribute_mapping.get(k, k), [v]))
- conn = self.api.get_connection()
- conn.modify_s(self._id_to_dn(id), modlist)
-
- def delete(self, id):
- conn = self.api.get_connection()
- conn.delete_s(self._id_to_dn(id))
diff --git a/keystone/backends/ldap/api/role.py b/keystone/backends/ldap/api/role.py
deleted file mode 100644
index 5ec81949..00000000
--- a/keystone/backends/ldap/api/role.py
+++ /dev/null
@@ -1,288 +0,0 @@
-import ldap
-
-from keystone.backends.api import BaseTenantAPI
-from keystone.common import exception
-
-from keystone import models
-from .base import BaseLdapAPI
-
-
-# pylint: disable=W0212, W0223
-class RoleAPI(BaseLdapAPI, BaseTenantAPI):
- DEFAULT_TREE_DN = 'ou=Groups,dc=example,dc=com'
- DEFAULT_STRUCTURAL_CLASSES = ['groupOfNames']
- options_name = 'role'
- object_class = 'keystoneRole'
- model = models.Role
- attribute_mapping = {'description': 'desc', 'serviceId': 'service_id'}
-
- @staticmethod
- def _create_ref(role_id, tenant_id, user_id):
- role_id = '' if role_id is None else str(role_id)
- tenant_id = '' if tenant_id is None else str(tenant_id)
- user_id = '' if user_id is None else str(user_id)
- return '%d-%d-%s%s%s' % (len(role_id), len(tenant_id),
- role_id, tenant_id, user_id)
-
- @staticmethod
- def _explode_ref(rolegrant):
- a = rolegrant.split('-', 2)
- len_role = int(a[0])
- len_tenant = int(a[1])
- role_id = a[2][:len_role]
- role_id = None if len(role_id) == 0 else str(role_id)
- tenant_id = a[2][len_role:len_tenant + len_role]
- tenant_id = None if len(tenant_id) == 0 else str(tenant_id)
- user_id = a[2][len_tenant + len_role:]
- user_id = None if len(user_id) == 0 else str(user_id)
- return role_id, tenant_id, user_id
-
- def _subrole_id_to_dn(self, role_id, tenant_id):
- if tenant_id is None:
- return self._id_to_dn(role_id)
- else:
- return "cn=%s,%s" % (ldap.dn.escape_dn_chars(role_id),
- self.api.tenant._id_to_dn(tenant_id))
-
- def get(self, id, filter=None):
- model = super(RoleAPI, self).get(id, filter)
- if model:
- model['name'] = model['id']
- return model
-
- def create(self, values):
- values['id'] = values['name']
- delattr(values, 'name')
-
- return super(RoleAPI, self).create(values)
-
- # pylint: disable=W0221
- def get_by_name(self, name, filter=None):
- return self.get(name, filter)
-
- def add_user(self, role_id, user_id, tenant_id=None):
- user = self.api.user.get(user_id)
- if user is None:
- raise exception.NotFound("User %s not found" % (user_id,))
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- conn = self.api.get_connection()
- user_dn = self.api.user._id_to_dn(user_id)
- try:
- conn.modify_s(role_dn, [(ldap.MOD_ADD, 'member', user_dn)])
- except ldap.TYPE_OR_VALUE_EXISTS:
- raise exception.Duplicate(
- "User %s already has role %s in tenant %s" % (user_id,
- role_id, tenant_id))
- except ldap.NO_SUCH_OBJECT:
- if tenant_id is None or self.get(role_id) is None:
- raise exception.NotFound("Role %s not found" % (role_id,))
- attrs = [
- ('objectClass', ['keystoneTenantRole', 'groupOfNames']),
- ('member', [user_dn]),
- ('keystoneRole', self._id_to_dn(role_id)),
- ]
- if self.use_dumb_member:
- attrs[1][1].append(self.DUMB_MEMBER_DN)
- conn.add_s(role_dn, attrs)
- return models.UserRoleAssociation(
- id=self._create_ref(role_id, tenant_id, user_id),
- role_id=role_id, user_id=user_id, tenant_id=tenant_id)
-
- def get_by_service(self, service_id):
- roles = self.get_all('(service_id=%s)' % \
- (ldap.filter.escape_filter_chars(service_id),))
- try:
- res = []
- for role in roles:
- res.append(role)
- return res
- except IndexError:
- return None
-
- def get_role_assignments(self, tenant_id):
- conn = self.api.get_connection()
- query = '(objectClass=keystoneTenantRole)'
- tenant_dn = self.api.tenant._id_to_dn(tenant_id)
- try:
- roles = conn.search_s(tenant_dn, ldap.SCOPE_ONELEVEL, query)
- except ldap.NO_SUCH_OBJECT:
- return []
- res = []
- for role_dn, attrs in roles:
- try:
- user_dns = attrs['member']
- except KeyError:
- continue
- for user_dn in user_dns:
- if self.use_dumb_member and user_dn == self.DUMB_MEMBER_DN:
- continue
- user_id = self.api.user._dn_to_id(user_dn)
- role_id = self._dn_to_id(role_dn)
- res.append(models.UserRoleAssociation(
- id=self._create_ref(role_id, tenant_id, user_id),
- user_id=user_id,
- role_id=role_id,
- tenant_id=tenant_id))
- return res
-
- def list_global_roles_for_user(self, user_id):
- user_dn = self.api.user._id_to_dn(user_id)
- roles = self.get_all('(member=%s)' % (user_dn,))
- return [models.UserRoleAssociation(
- id=self._create_ref(role.id, None, user_id),
- role_id=role.id,
- user_id=user_id) for role in roles]
-
- def list_tenant_roles_for_user(self, user_id, tenant_id=None):
- conn = self.api.get_connection()
- user_dn = self.api.user._id_to_dn(user_id)
- query = '(&(objectClass=keystoneTenantRole)(member=%s))' % (user_dn,)
- if tenant_id is not None:
- tenant_dn = self.api.tenant._id_to_dn(tenant_id)
- try:
- roles = conn.search_s(tenant_dn, ldap.SCOPE_ONELEVEL, query)
- except ldap.NO_SUCH_OBJECT:
- return []
- res = []
- for role_dn, _ in roles:
- role_id = self._dn_to_id(role_dn)
- res.append(models.UserRoleAssociation(
- id=self._create_ref(role_id, tenant_id, user_id),
- user_id=user_id,
- role_id=role_id,
- tenant_id=tenant_id))
- return res
- else:
- try:
- roles = conn.search_s(self.api.tenant.tree_dn,
- ldap.SCOPE_SUBTREE, query)
- except ldap.NO_SUCH_OBJECT:
- return []
- res = []
- for role_dn, _ in roles:
- role_id = self._dn_to_id(role_dn)
- tenant_id = ldap.dn.str2dn(role_dn)[1][0][1]
- res.append(models.UserRoleAssociation(
- id=self._create_ref(role_id, tenant_id, user_id),
- user_id=user_id,
- role_id=role_id,
- tenant_id=tenant_id))
- return res
-
- def rolegrant_get(self, id):
- role_id, tenant_id, user_id = self._explode_ref(id)
- user_dn = self.api.user._id_to_dn(user_id)
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- query = '(&(objectClass=keystoneTenantRole)(member=%s))' % (user_dn,)
- conn = self.api.get_connection()
- try:
- res = conn.search_s(role_dn, ldap.SCOPE_BASE, query)
- except ldap.NO_SUCH_OBJECT:
- return None
- if len(res) == 0:
- return None
- return models.UserRoleAssociation(id=id, role_id=role_id,
- tenant_id=tenant_id, user_id=user_id)
-
- def rolegrant_delete(self, id):
- role_id, tenant_id, user_id = self._explode_ref(id)
- user_dn = self.api.user._id_to_dn(user_id)
- role_dn = self._subrole_id_to_dn(role_id, tenant_id)
- conn = self.api.get_connection()
- try:
- conn.modify_s(role_dn, [(ldap.MOD_DELETE, 'member', [user_dn])])
- except ldap.NO_SUCH_ATTRIBUTE:
- raise exception.NotFound("No such user in role")
-
- def rolegrant_get_page(self, marker, limit, user_id, tenant_id):
- all_roles = []
- if tenant_id is None:
- all_roles += self.list_global_roles_for_user(user_id)
- else:
- for tenant in self.api.tenant.get_all():
- all_roles += self.list_tenant_roles_for_user(user_id,
- tenant.id)
- return self._get_page(marker, limit, all_roles)
-
- def rolegrant_get_page_markers(self, user_id, tenant_id, marker, limit):
- all_roles = []
- if tenant_id is None:
- all_roles = self.list_global_roles_for_user(user_id)
- else:
- for tenant in self.api.tenant.get_all():
- all_roles += self.list_tenant_roles_for_user(user_id,
- tenant.id)
- return self._get_page_markers(marker, limit, all_roles)
-
- def get_by_service_get_page(self, service_id, marker, limit):
- all_roles = self.get_by_service(service_id)
- return self._get_page(marker, limit, all_roles)
-
- def get_by_service_get_page_markers(self, service_id, marker, limit):
- all_roles = self.get_by_service(service_id)
- return self._get_page_markers(marker, limit, all_roles)
-
- def rolegrant_list_by_role(self, id):
- role_dn = self._id_to_dn(id)
- try:
- roles = self.get_all('(keystoneRole=%s)' % (role_dn,))
- except ldap.NO_SUCH_OBJECT:
- return []
- res = []
- for role_dn, attrs in roles:
- try:
- user_dns = attrs['member']
- tenant_dns = attrs['tenant']
- except KeyError:
- continue
- for user_dn in user_dns:
- if self.use_dumb_member and user_dn == self.DUMB_MEMBER_DN:
- continue
- user_id = self.api.user._dn_to_id(user_dn)
- tenant_id = None
- if tenant_dns is not None:
- for tenant_dn in tenant_dns:
- tenant_id = self.api.tenant._dn_to_id(tenant_dn)
- role_id = self._dn_to_id(role_dn)
- res.append(models.UserRoleAssociation(
- id=self._create_ref(role_id, tenant_id, user_id),
- user_id=user_id,
- role_id=role_id,
- tenant_id=tenant_id))
- return res
-
- def rolegrant_get_by_ids(self, user_id, role_id, tenant_id):
- conn = self.api.get_connection()
- user_dn = self.api.user._id_to_dn(user_id)
- query = '(&(objectClass=keystoneTenantRole)(member=%s))' % (user_dn,)
- if tenant_id is not None:
- tenant_dn = self.api.tenant._id_to_dn(tenant_id)
- try:
- roles = conn.search_s(tenant_dn, ldap.SCOPE_ONELEVEL, query)
- except ldap.NO_SUCH_OBJECT:
- return None
- if len(roles) == 0:
- return None
- for role_dn, _ in roles:
- ldap_role_id = self._dn_to_id(role_dn)
- if role_id == ldap_role_id:
- res = models.UserRoleAssociation(
- id=self._create_ref(role_id, tenant_id, user_id),
- user_id=user_id,
- role_id=role_id,
- tenant_id=tenant_id)
- return res
- else:
- try:
- roles = self.get_all('(member=%s)' % (user_dn,))
- except ldap.NO_SUCH_OBJECT:
- return None
- if len(roles) == 0:
- return None
- for role in roles:
- if role.id == role_id:
- return models.UserRoleAssociation(
- id=self._create_ref(role.id, None, user_id),
- role_id=role.id,
- user_id=user_id)
- return None
diff --git a/keystone/backends/ldap/api/tenant.py b/keystone/backends/ldap/api/tenant.py
deleted file mode 100644
index fbc795ec..00000000
--- a/keystone/backends/ldap/api/tenant.py
+++ /dev/null
@@ -1,109 +0,0 @@
-import ldap
-import uuid
-
-from keystone.backends.api import BaseTenantAPI
-from keystone.backends.sqlalchemy.api.tenant import TenantAPI as SQLTenantAPI
-
-from keystone import models
-from .base import BaseLdapAPI, add_redirects
-
-
-class TenantAPI(BaseLdapAPI, BaseTenantAPI): # pylint: disable=W0223
- DEFAULT_TREE_DN = 'ou=Groups,dc=example,dc=com'
- DEFAULT_STRUCTURAL_CLASSES = ['groupOfNames']
- options_name = 'tenant'
- object_class = 'keystoneTenant'
- model = models.Tenant
- attribute_mapping = {'description': 'desc', 'enabled': 'keystoneEnabled',
- 'name': 'keystoneName'}
-
- def get_by_name(self, name, filter=None): # pylint: disable=W0221,W0613
- tenants = self.get_all('(keystoneName=%s)' % \
- (ldap.filter.escape_filter_chars(name),))
- try:
- return tenants[0]
- except IndexError:
- return None
-
- def create(self, values):
- data = values.copy()
- if 'id' not in data or data['id'] is None:
- data['id'] = str(uuid.uuid4())
- return super(TenantAPI, self).create(data)
-
- def get_user_tenants(self, user_id, include_roles=True):
- """Returns list of tenants a user has access to
-
- Always includes default tenants.
- Adds role assignments if 'include_roles' is True.
- """
- user_dn = self.api.user._id_to_dn(user_id) # pylint: disable=W0212
- query = '(member=%s)' % (user_dn,)
- memberships = self.get_all(query)
- if include_roles:
- roles = self.api.role.list_tenant_roles_for_user(user_id)
- for role in roles:
- exists = False
- for tenant in memberships:
- if tenant['id'] == role.tenant_id:
- exists = True
- break
- if not exists:
- memberships.append(self.get(role.tenant_id))
- return memberships
-
- def list_for_user_get_page(self, user, marker, limit):
- return self._get_page(marker, limit, self.get_user_tenants(user.id))
-
- def list_for_user_get_page_markers(self, user, marker, limit):
- return self._get_page_markers(marker, limit,
- self.get_user_tenants(user.id))
-
- def is_empty(self, id):
- tenant = self._ldap_get(id)
- members = tenant[1].get('member', [])
- if self.use_dumb_member:
- empty = members == [self.DUMB_MEMBER_DN]
- else:
- empty = len(members) == 0
- return empty and len(self.api.role.get_role_assignments(id)) == 0
-
- def get_role_assignments(self, tenant_id):
- return self.api.role.get_role_assignments(tenant_id)
-
- def add_user(self, tenant_id, user_id):
- conn = self.api.get_connection()
- conn.modify_s(self._id_to_dn(tenant_id),
- [(ldap.MOD_ADD, 'member',
- self.api.user._id_to_dn(user_id))]) # pylint: disable=W0212
-
- def remove_user(self, tenant_id, user_id):
- conn = self.api.get_connection()
- conn.modify_s(self._id_to_dn(tenant_id),
- [(ldap.MOD_DELETE, 'member',
- self.api.user._id_to_dn(user_id))]) # pylint: disable=W0212
-
- def get_users(self, tenant_id, role_id=None):
- tenant = self._ldap_get(tenant_id)
- res = []
- if not role_id:
- # Get users who have default tenant mapping
- for user_dn in tenant[1].get('member', []):
- if self.use_dumb_member and user_dn == self.DUMB_MEMBER_DN:
- continue
- #pylint: disable=W0212
- res.append(self.api.user.get(self.api.user._dn_to_id(user_dn)))
- rolegrants = self.api.role.get_role_assignments(tenant_id)
- # Get users who are explicitly mapped via a tenant
- for rolegrant in rolegrants:
- if role_id is None or rolegrant.role_id == role_id:
- res.append(self.api.user.get(rolegrant.user_id))
- return res
-
- add_redirects(locals(), SQLTenantAPI, ['get_all_endpoints'])
-
- def delete(self, id):
- if not self.is_empty(id):
- raise fault.ForbiddenFault("You may not delete a tenant that "
- "contains users")
- super(TenantAPI, self).delete(id)
diff --git a/keystone/backends/ldap/api/user.py b/keystone/backends/ldap/api/user.py
deleted file mode 100644
index 77bb6e22..00000000
--- a/keystone/backends/ldap/api/user.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import ldap
-import ldap.filter
-import uuid
-
-import keystone.backends.backendutils as utils
-from keystone.backends.api import BaseUserAPI
-from keystone.backends.sqlalchemy.api.user import UserAPI as SQLUserAPI
-
-from keystone import models
-from .base import BaseLdapAPI, add_redirects
-
-
-class UserAPI(BaseLdapAPI, BaseUserAPI):
- DEFAULT_TREE_DN = 'ou=Users,dc=example,dc=com'
- DEFAULT_STRUCTURAL_CLASSES = ['keystoneUidObject']
- DEFAULT_ID_ATTR = 'uid'
- options_name = 'user'
- object_class = 'keystoneUser'
- model = models.User
- attribute_mapping = {
- 'password': 'userPassword',
- 'email': 'mail',
- 'enabled': 'keystoneEnabled',
- 'name': 'keystoneName',
- }
- attribute_ignore = ['tenant_id']
-
- def _ldap_res_to_model(self, res):
- obj = super(UserAPI, self)._ldap_res_to_model(res)
- tenants = self.api.tenant.get_user_tenants(obj.id, False)
- if len(tenants) > 0:
- obj.tenant_id = tenants[0].id
- return obj
-
- def get_by_name(self, name, filter=None):
- users = self.get_all('(keystoneName=%s)' % \
- (ldap.filter.escape_filter_chars(name),))
- try:
- return users[0]
- except IndexError:
- return None
-
- def create(self, values):
- values['id'] = str(uuid.uuid4())
- utils.set_hashed_password(values)
- values = super(UserAPI, self).create(values)
- if values['tenant_id'] is not None:
- self.api.tenant.add_user(values['tenant_id'], values['id'])
- return values
-
- def update(self, id, values):
- old_obj = self.get(id)
- try:
- new_tenant = values['tenant_id']
- except KeyError:
- pass
- else:
- if old_obj.tenant_id != new_tenant:
- if old_obj.tenant_id:
- self.api.tenant.remove_user(old_obj.tenant_id, id)
- if new_tenant:
- self.api.tenant.add_user(new_tenant, id)
- utils.set_hashed_password(values)
- super(UserAPI, self).update(id, values, old_obj)
-
- def delete(self, id):
- user = self.get(id)
- if user.tenant_id:
- self.api.tenant.remove_user(user.tenant_id, id)
- super(UserAPI, self).delete(id)
- for ref in self.api.role.list_global_roles_for_user(id):
- self.api.role.rolegrant_delete(ref.id)
- for ref in self.api.role.list_tenant_roles_for_user(id):
- self.api.role.rolegrant_delete(ref.id)
-
- def get_by_email(self, email):
- users = self.get_all('(mail=%s)' % \
- (ldap.filter.escape_filter_chars(email),))
- try:
- return users[0]
- except IndexError:
- return None
-
- def user_roles_by_tenant(self, user_id, tenant_id):
- return self.api.role.list_tenant_roles_for_user(user_id, tenant_id)
-
- def get_by_tenant(self, user_id, tenant_id):
- user_dn = self._id_to_dn(user_id)
- user = self.get(user_id)
- tenant = self.api.tenant._ldap_get(tenant_id,
- '(member=%s)' % (user_dn,))
- if tenant is not None:
- return user
- else:
- if self.api.role.list_tenant_roles_for_user(user_id, tenant_id):
- return user
- return None
-
- def user_role_add(self, values):
- return self.api.role.add_user(values.role_id, values.user_id,
- values.tenant_id)
-
- def users_get_page(self, marker, limit):
- return self.get_page(marker, limit)
-
- def users_get_page_markers(self, marker, limit):
- return self.get_page_markers(marker, limit)
-
- def users_get_by_tenant_get_page(self, tenant_id, role_id, marker, limit):
- return self._get_page(marker, limit,
- self.api.tenant.get_users(tenant_id, role_id))
-
- def users_get_by_tenant_get_page_markers(self, tenant_id,
- role_id, marker, limit):
- return self._get_page_markers(marker, limit,
- self.api.tenant.get_users(tenant_id, role_id))
-
- def check_password(self, user_id, password):
- user = self.get(user_id)
- return utils.check_password(password, user.password)
-
- add_redirects(locals(), SQLUserAPI, ['get_by_group', 'tenant_group',
- 'tenant_group_delete', 'user_groups_get_all',
- 'users_tenant_group_get_page', 'users_tenant_group_get_page_markers'])
diff --git a/keystone/backends/ldap/fakeldap.py b/keystone/backends/ldap/fakeldap.py
deleted file mode 100644
index ee80d15a..00000000
--- a/keystone/backends/ldap/fakeldap.py
+++ /dev/null
@@ -1,315 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-"""Fake LDAP server for test harness.
-
-This class does very little error checking, and knows nothing about ldap
-class definitions. It implements the minimum emulation of the python ldap
-library to work with nova.
-
-"""
-
-import logging
-import re
-import shelve
-
-import ldap
-
-
-scope_names = {
- ldap.SCOPE_BASE: 'SCOPE_BASE',
- ldap.SCOPE_ONELEVEL: 'SCOPE_ONELEVEL',
- ldap.SCOPE_SUBTREE: 'SCOPE_SUBTREE',
-}
-
-
-LOG = logging.getLogger('keystone.backends.ldap.fakeldap')
-
-
-def initialize(uri):
- """Opens a fake connection with an LDAP server."""
- return FakeLDAP(uri)
-
-
-def _match_query(query, attrs):
- """Match an ldap query to an attribute dictionary.
-
- The characters &, |, and ! are supported in the query. No syntax checking
- is performed, so malformed querys will not work correctly.
- """
- # cut off the parentheses
- inner = query[1:-1]
- if inner.startswith('&'):
- # cut off the &
- l, r = _paren_groups(inner[1:])
- return _match_query(l, attrs) and _match_query(r, attrs)
- if inner.startswith('|'):
- # cut off the |
- l, r = _paren_groups(inner[1:])
- return _match_query(l, attrs) or _match_query(r, attrs)
- if inner.startswith('!'):
- # cut off the ! and the nested parentheses
- return not _match_query(query[2:-1], attrs)
-
- (k, _sep, v) = inner.partition('=')
- return _match(k, v, attrs)
-
-
-def _paren_groups(source):
- """Split a string into parenthesized groups."""
- count = 0
- start = 0
- result = []
- for pos in xrange(len(source)):
- if source[pos] == '(':
- if count == 0:
- start = pos
- count += 1
- if source[pos] == ')':
- count -= 1
- if count == 0:
- result.append(source[start:pos + 1])
- return result
-
-
-def _match(key, value, attrs):
- """Match a given key and value against an attribute list."""
- if key not in attrs:
- return False
- # This is a wild card search. Implemented as all or nothing for now.
- if value == "*":
- return True
- if key == 'serviceId':
- # for serviceId, the backend is returning a list of numbers
- # make sure we convert them to strings first before comparing
- # them
- str_sids = map(lambda x: str(x), attrs[key])
- return str(value) in str_sids
- if key != "objectclass":
- return value in attrs[key]
- # it is an objectclass check, so check subclasses
- values = _subs(value)
- for v in values:
- if v in attrs[key]:
- return True
- return False
-
-
-def _subs(value):
- """Returns a list of subclass strings.
-
- The strings represent the ldap objectclass plus any subclasses that
- inherit from it. Fakeldap doesn't know about the ldap object structure,
- so subclasses need to be defined manually in the dictionary below.
-
- """
- subs = {'groupOfNames': [
- 'keystoneTenant',
- 'keystoneRole',
- 'keystoneTenantRole']}
- if value in subs:
- return [value] + subs[value]
- return [value]
-
-
-server_fail = False
-
-
-class FakeShelve(dict):
- @classmethod
- def get_instance(cls):
- try:
- return cls.__instance
- except AttributeError:
- cls.__instance = cls()
- return cls.__instance
-
- def sync(self):
- pass
-
-
-class FakeLDAP(object):
- """Fake LDAP connection."""
-
- def __init__(self, url):
- LOG.debug("FakeLDAP initialize url=%s" % (url,))
- if url == 'fake://memory':
- self.db = FakeShelve.get_instance()
- else:
- self.db = shelve.open(url[7:])
-
- def simple_bind_s(self, dn, password):
- """This method is ignored, but provided for compatibility."""
- if server_fail:
- raise ldap.SERVER_DOWN
- LOG.debug("FakeLDAP bind dn=%s" % (dn,))
- if dn == 'cn=Admin' and password == 'password':
- return
- try:
- attrs = self.db["%s%s" % (self.__prefix, dn)]
- except KeyError:
- LOG.error("FakeLDAP bind fail: dn=%s not found" % (dn,))
- raise ldap.NO_SUCH_OBJECT
- db_passwd = None
- try:
- db_passwd = attrs['userPassword'][0]
- except (KeyError, IndexError):
- LOG.error("FakeLDAP bind fail: password for dn=%s not found" % dn)
- raise ldap.INAPPROPRIATE_AUTH
- if db_passwd != password:
- LOG.error("FakeLDAP bind fail: password for dn=%s does not match" %
- dn)
- raise ldap.INVALID_CREDENTIALS
-
- def unbind_s(self):
- """This method is ignored, but provided for compatibility."""
- if server_fail:
- raise ldap.SERVER_DOWN
-
- def add_s(self, dn, attrs):
- """Add an object with the specified attributes at dn."""
- if server_fail:
- raise ldap.SERVER_DOWN
-
- key = "%s%s" % (self.__prefix, dn)
- LOG.debug("FakeLDAP add item: dn=%s, attrs=%s" % (dn, attrs))
- if key in self.db:
- LOG.error(
- "FakeLDAP add item failed: dn '%s' is already in store." % dn)
- raise ldap.ALREADY_EXISTS(dn)
- self.db[key] = dict([(k, v if isinstance(v, list) else [v])
- for k, v in attrs])
- self.db.sync()
-
- def delete_s(self, dn):
- """Remove the ldap object at specified dn."""
- if server_fail:
- raise ldap.SERVER_DOWN
-
- key = "%s%s" % (self.__prefix, dn)
- LOG.debug("FakeLDAP delete item: dn=%s" % (dn,))
- try:
- del self.db[key]
- except KeyError:
- LOG.error("FakeLDAP delete item failed: dn '%s' not found." % dn)
- raise ldap.NO_SUCH_OBJECT
- self.db.sync()
-
- def modify_s(self, dn, attrs):
- """Modify the object at dn using the attribute list.
-
- :param dn: an LDAP DN
- :param attrs: a list of tuples in the following form:
- ([MOD_ADD | MOD_DELETE | MOD_REPACE], attribute, value)
- """
- if server_fail:
- raise ldap.SERVER_DOWN
-
- key = "%s%s" % (self.__prefix, dn)
- LOG.debug("FakeLDAP modify item: dn=%s attrs=%s" % (dn, attrs))
- try:
- entry = self.db[key]
- except KeyError:
- LOG.error("FakeLDAP modify item failed: dn '%s' not found." % dn)
- raise ldap.NO_SUCH_OBJECT
-
- for cmd, k, v in attrs:
- values = entry.setdefault(k, [])
- if cmd == ldap.MOD_ADD:
- if isinstance(v, list):
- values += v
- else:
- values.append(v)
- elif cmd == ldap.MOD_REPLACE:
- values[:] = v if isinstance(v, list) else [v]
- elif cmd == ldap.MOD_DELETE:
- if v is None:
- if len(values) == 0:
- LOG.error("FakeLDAP modify item failed: "
- "item has no attribute '%s' to delete" % k)
- raise ldap.NO_SUCH_ATTRIBUTE
- values[:] = []
- else:
- if not isinstance(v, list):
- v = [v]
- for val in v:
- try:
- values.remove(val)
- except ValueError:
- LOG.error("FakeLDAP modify item failed: "
- "item has no attribute '%s' with value '%s'"
- " to delete" % (k, val))
- raise ldap.NO_SUCH_ATTRIBUTE
- else:
- LOG.error("FakeLDAP modify item failed: unknown command %s"
- % (cmd,))
- raise NotImplementedError(\
- "modify_s action %s not implemented" % (cmd,))
- self.db[key] = entry
- self.db.sync()
-
- def search_s(self, dn, scope, query=None, fields=None):
- """Search for all matching objects under dn using the query.
-
- Args:
- dn -- dn to search under
- scope -- only SCOPE_BASE and SCOPE_SUBTREE are supported
- query -- query to filter objects by
- fields -- fields to return. Returns all fields if not specified
-
- """
- if server_fail:
- raise ldap.SERVER_DOWN
-
- LOG.debug("FakeLDAP search at dn=%s scope=%s query='%s'" %
- (dn, scope_names.get(scope, scope), query))
- if scope == ldap.SCOPE_BASE:
- try:
- item_dict = self.db["%s%s" % (self.__prefix, dn)]
- except KeyError:
- LOG.debug("FakeLDAP search fail: dn not found for SCOPE_BASE")
- raise ldap.NO_SUCH_OBJECT
- results = [(dn, item_dict)]
- elif scope == ldap.SCOPE_SUBTREE:
- results = [(k[len(self.__prefix):], v)
- for k, v in self.db.iteritems()
- if re.match("%s.*,%s" % (self.__prefix, dn), k)]
- elif scope == ldap.SCOPE_ONELEVEL:
- results = [(k[len(self.__prefix):], v)
- for k, v in self.db.iteritems()
- if re.match("%s\w+=[^,]+,%s" % (self.__prefix, dn), k)]
- else:
- LOG.error("FakeLDAP search fail: unknown scope %s" % (scope,))
- raise NotImplementedError("Search scope %s not implemented." %
- (scope,))
-
- objects = []
- for dn, attrs in results:
- # filter the objects by query
- if not query or _match_query(query, attrs):
- # filter the attributes by fields
- attrs = dict([(k, v) for k, v in attrs.iteritems()
- if not fields or k in fields])
- objects.append((dn, attrs))
- # pylint: enable=E1103
- LOG.debug("FakeLDAP search result: %s" % (objects,))
- return objects
-
- @property
- def __prefix(self): # pylint: disable=R0201
- """Get the prefix to use for all keys."""
- return 'ldap:'
diff --git a/keystone/backends/ldap/keystone.ldif b/keystone/backends/ldap/keystone.ldif
deleted file mode 100644
index 831b161c..00000000
--- a/keystone/backends/ldap/keystone.ldif
+++ /dev/null
@@ -1,74 +0,0 @@
-dn: cn=keystone,cn=schema,cn=config
-objectClass: olcSchemaConfig
-cn: keystone
-olcAttributeTypes: (
- 1.3.6.1.3.1.666.667.3.1
- NAME 'keystoneEnabled'
- EQUALITY booleanMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
- SINGLE-VALUE
- )
-olcAttributeTypes: (
- 1.3.6.1.3.1.666.667.3.2
- NAME 'keystoneTenant'
- SUP distinguishedName
- SINGLE-VALUE
- )
-olcAttributeTypes: (
- 1.3.6.1.3.1.666.667.3.3
- NAME 'keystoneRole'
- SUP distinguishedName
- SINGLE-VALUE
- )
-olcAttributeTypes: (
- 1.3.6.1.3.1.666.667.3.4
- NAME 'serviceId'
- EQUALITY caseExactIA5Match
- SUBSTR caseExactIA5SubstringsMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
- SINGLE-VALUE
- )
-olcAttributeTypes: (
- 1.3.6.1.3.1.666.667.3.5
- NAME 'keystoneName'
- SUP name
- SINGLE-VALUE
- )
-olcObjectClasses: (
- 1.3.6.1.3.1.666.667.4.1
- NAME 'keystoneUidObject'
- SUP top
- STRUCTURAL
- MUST ( uid )
- )
-olcObjectClasses: (
- 1.3.6.1.3.1.666.667.4.2
- NAME 'keystoneUser'
- SUP top
- AUXILIARY
- MUST ( keystoneName $ keystoneEnabled )
- MAY ( mail $ userPassword )
- )
-olcObjectClasses: (
- 1.3.6.1.3.1.666.667.4.3
- NAME 'keystoneRole'
- SUP top
- AUXILIARY
- MAY ( member $ description $ serviceId )
- )
-olcObjectClasses: (
- 1.3.6.1.3.1.666.667.4.4
- NAME 'keystoneTenant'
- SUP top
- AUXILIARY
- MUST ( keystoneName $ keystoneEnabled )
- MAY ( member $ description )
- )
-olcObjectClasses: (
- 1.3.6.1.3.1.666.667.4.5
- NAME 'keystoneTenantRole'
- SUP top
- AUXILIARY
- MUST ( keystoneRole )
- MAY ( member )
- )
diff --git a/keystone/backends/ldap/keystone.schema b/keystone/backends/ldap/keystone.schema
deleted file mode 100644
index 68f0d562..00000000
--- a/keystone/backends/ldap/keystone.schema
+++ /dev/null
@@ -1,83 +0,0 @@
-objectidentifier keystoneSchema 1.3.6.1.3.1.666.667
-objectidentifier keystoneAttrs keystoneSchema:3
-objectidentifier keystoneOCs keystoneSchema:4
-
-attributetype (
- keystoneAttrs:1
- NAME 'keystoneEnabled'
- EQUALITY booleanMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.7
- SINGLE-VALUE
- )
-
-attributetype (
- keystoneAttrs:2
- NAME 'keystoneTenant'
- SUP distinguishedName
- SINGLE-VALUE
- )
-
-attributetype (
- keystoneAttrs:3
- NAME 'keystoneRole'
- SUP distinguishedName
- SINGLE-VALUE
- )
-
-attributetype (
- keystoneAttrs:4
- NAME 'serviceId'
- EQUALITY caseExactIA5Match
- SUBSTR caseExactIA5SubstringsMatch
- SYNTAX 1.3.6.1.4.1.1466.115.121.1.26
- SINGLE-VALUE
- )
-attributetype: (
- keystoneAttrs:5
- NAME 'keystoneName'
- SUP name
- SINGLE-VALUE
- )
-objectClass (
- keystoneOCs:1
- NAME 'keystoneUidObject'
- SUP top
- STRUCTURAL
- MUST ( uid )
- )
-
-objectClass (
- keystoneOCs:2
- NAME 'keystoneUser'
- SUP top
- AUXILIARY
- MUST ( keystoneName $ keystoneEnabled )
- MAY ( mail $ userPassword )
- )
-
-objectClass (
- keystoneOCs:3
- NAME 'keystoneRole'
- SUP top
- AUXILIARY
- MUST ( cn )
- MAY ( member $ description $ serviceId )
- )
-
-objectClass (
- keystoneOCs:4
- NAME 'keystoneTenant'
- SUP top
- AUXILIARY
- MUST ( keystoneName $ keystoneEnabled )
- MAY ( member $ description )
- )
-
-objectClass (
- keystoneOCs:5
- NAME 'keystoneTenantRole'
- SUP top
- AUXILIARY
- MUST ( keystoneRole )
- MAY ( member )
- )
diff --git a/keystone/backends/ldap/models.py b/keystone/backends/ldap/models.py
deleted file mode 100644
index d0c9ffca..00000000
--- a/keystone/backends/ldap/models.py
+++ /dev/null
@@ -1,52 +0,0 @@
-from collections import Mapping
-
-__all__ = ['UserRoleAssociation', 'Role', 'Tenant', 'User']
-
-
-def create_model(name, attrs):
- class Cmapper(Mapping):
- __slots__ = attrs
-
- def __init__(self, arg=None, **kwargs):
- if arg is None:
- arg = kwargs
- if isinstance(arg, dict):
- missed_attrs = set(attrs)
- for k, v in kwargs.iteritems():
- setattr(self, k, v)
- missed_attrs.remove(k)
- for name in missed_attrs:
- setattr(self, name, None)
- elif isinstance(arg, C):
- for name in attrs:
- setattr(self, name, getattr(arg, name))
- else:
- raise ValueError
-
- def __getitem__(self, name):
- return getattr(self, name)
-
- def __setitem__(self, name, value):
- return setattr(self, name, value)
-
- def __iter__(self):
- return iter(attrs)
-
- def __len__(self):
- return len(attrs)
- Cmapper.__name__ = name
- return Cmapper
-
-
-UserRoleAssociation = create_model(
- 'UserRoleAssociation', ['id', 'user_id', 'role_id', 'tenant_id'])
-Role = create_model(
- 'Role', ['id', 'desc', 'service_id'])
-Tenant = create_model(
- 'Tenant', ['id', 'name', 'desc', 'enabled'])
-User = create_model(
- 'User', ['id', 'name', 'password', 'email', 'enabled', 'tenant_id'])
-#Endpoints = create_model(
-# 'Endpoints', ['id', 'tenant_id', 'endpoint_template_id'])
-#Credentials = create_model(
-# 'Credentials', ['id', 'user_id', 'type', 'key', 'secret'])
diff --git a/keystone/backends/memcache/__init__.py b/keystone/backends/memcache/__init__.py
deleted file mode 100755
index 084c36d6..00000000
--- a/keystone/backends/memcache/__init__.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 ast
-import logging
-
-from keystone.common import config
-from keystone.backends.memcache import models
-import keystone.utils as utils
-import keystone.backends.api as top_api
-import keystone.backends.models as top_models
-import memcache
-
-MODEL_PREFIX = 'keystone.backends.memcache.models.'
-API_PREFIX = 'keystone.backends.memcache.api.'
-MEMCACHE_SERVER = None
-CACHE_TIME = 86400
-
-
-def configure_backend(options):
- hosts = options['memcache_hosts']
- global MEMCACHE_SERVER
- if not MEMCACHE_SERVER:
- MEMCACHE_SERVER = Memcache_Server(hosts)
- register_models(options)
- global CACHE_TIME
- CACHE_TIME = config.get_option(
- options, 'cache_time', type='int', default=86400)
-
-
-class Memcache_Server():
- def __init__(self, hosts):
- self.hosts = hosts
- self.server = memcache.Client([self.hosts])
-
- def set(self, key, value, expiry=CACHE_TIME):
- """
- This method is used to set a new value
- in the memcache server.
- """
- self.server.set(key.encode('utf-8'), value, expiry)
-
- def get(self, key):
- """
- This method is used to retrieve a value
- from the memcache server
- """
- return self.server.get(key.encode('utf-8'))
-
- def delete(self, key):
- """
- This method is used to delete a value from the
- memcached server. Lazy delete
- """
- self.server.delete(key.encode('utf-8'))
-
-
-def register_models(options):
- """Register Models and create properties"""
- supported_memcache_models = ast.literal_eval(
- options["backend_entities"])
- for supported_memcache_model in supported_memcache_models:
- model = utils.import_module(MODEL_PREFIX + supported_memcache_model)
- top_models.set_value(supported_memcache_model, model)
- if model.__api__ is not None:
- model_api = utils.import_module(API_PREFIX + model.__api__)
- top_api.set_value(model.__api__, model_api.get())
diff --git a/keystone/backends/memcache/api/__init__.py b/keystone/backends/memcache/api/__init__.py
deleted file mode 100644
index 86d2910e..00000000
--- a/keystone/backends/memcache/api/__init__.py
+++ /dev/null
@@ -1,18 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from . import token
diff --git a/keystone/backends/memcache/api/token.py b/keystone/backends/memcache/api/token.py
deleted file mode 100755
index 4bbb5fa3..00000000
--- a/keystone/backends/memcache/api/token.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-from keystone.backends.memcache import MEMCACHE_SERVER
-from keystone.backends.api import BaseTokenAPI
-
-
-# pylint: disable=W0223
-class TokenAPI(BaseTokenAPI):
- def __init__(self, *args, **kw):
- super(TokenAPI, self).__init__(*args, **kw)
-
- def create(self, token):
- if not hasattr(token, 'tenant_id'):
- token.tenant_id = None
- if token.tenant_id is not None:
- tenant_user_key = "%s::%s" % (token.tenant_id, token.user_id)
- else:
- tenant_user_key = "U%s" % token.user_id
-
- MEMCACHE_SERVER.set(token.id, token)
- MEMCACHE_SERVER.set(tenant_user_key, token)
-
- def get(self, id):
- token = MEMCACHE_SERVER.get(id)
- if token is not None and not hasattr(token, 'tenant_id'):
- token.tenant_id = None
- return token
-
- # pylint: disable=E1103
- def delete(self, id):
- token = self.get(id)
- if token is not None:
- MEMCACHE_SERVER.delete(id)
- if token is not None and not hasattr(token, 'tenant_id'):
- token.tenant_id = None
- if token.tenant_id is not None:
- MEMCACHE_SERVER.delete("%s::%s" % (token.tenant_id,
- token.user_id))
- else:
- MEMCACHE_SERVER.delete(token.id)
- MEMCACHE_SERVER.delete("U%s" % token.user_id)
-
- def get_for_user(self, user_id):
- token = MEMCACHE_SERVER.get("U%s" % user_id)
- if token is not None and not hasattr(token, 'tenant_id'):
- token.tenant_id = None
- return token
-
- def get_for_user_by_tenant(self, user_id, tenant_id):
- if tenant_id is not None:
- token = MEMCACHE_SERVER.get("%s::%s" % (tenant_id, user_id))
- else:
- token = MEMCACHE_SERVER.get("U%s" % user_id)
- if token is not None and not hasattr(token, 'tenant_id'):
- token.tenant_id = None
- return token
-
-
-def get():
- return TokenAPI()
diff --git a/keystone/backends/memcache/models.py b/keystone/backends/memcache/models.py
deleted file mode 100755
index 58dc3f03..00000000
--- a/keystone/backends/memcache/models.py
+++ /dev/null
@@ -1,19 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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.
-
-
-class Token():
- __api__ = 'token'
diff --git a/keystone/backends/models.py b/keystone/backends/models.py
deleted file mode 100755
index 10ac6267..00000000
--- a/keystone/backends/models.py
+++ /dev/null
@@ -1,60 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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.
-
-# pylint: disable=C0103,W0603
-#Current Models
-UserRoleAssociation = None
-Endpoints = None
-Role = None
-Tenant = None
-User = None
-Credentials = None
-Token = None
-EndpointTemplates = None
-Service = None
-
-
-# Function to dynamically set model references.
-def set_value(variable_name, value):
- if variable_name == 'UserRoleAssociation':
- global UserRoleAssociation
- UserRoleAssociation = value
- elif variable_name == 'Endpoints':
- global Endpoints
- Endpoints = value
- elif variable_name == 'Role':
- global Role
- Role = value
- elif variable_name == 'Tenant':
- global Tenant
- Tenant = value
- elif variable_name == 'User':
- global User
- User = value
- elif variable_name == 'Credentials':
- global Credentials
- Credentials = value
- elif variable_name == 'Token':
- global Token
- Token = value
- elif variable_name == 'EndpointTemplates':
- global EndpointTemplates
- EndpointTemplates = value
- elif variable_name == 'Service':
- global Service
- Service = value
- else:
- raise IndexError("Unrecognized model type: %s" % variable_name)
diff --git a/keystone/backends/sqlalchemy/__init__.py b/keystone/backends/sqlalchemy/__init__.py
deleted file mode 100755
index cea111c1..00000000
--- a/keystone/backends/sqlalchemy/__init__.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-# pylint: disable=W0602,W0603
-
-from sqlalchemy.orm import joinedload, aliased, sessionmaker
-
-import ast
-import logging
-import os
-import sys
-
-from sqlalchemy import create_engine
-from sqlalchemy.pool import StaticPool
-
-try:
- # pylint: disable=E0611
- from migrate.versioning import exceptions as versioning_exceptions
-except ImportError:
- from migrate import exceptions as versioning_exceptions
-
-from keystone import utils
-from keystone.backends.sqlalchemy import models
-from keystone.backends.sqlalchemy import migration
-import keystone.backends.api as top_api
-import keystone.backends.models as top_models
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-_DRIVER = None
-
-
-class Driver():
- def __init__(self, conf):
- self.session = None
- self._engine = None
- self.connection_str = conf.sql_connection
- model_list = ast.literal_eval(conf.backend_entities)
- self._init_engine(model_list)
- self._init_models(model_list)
- self._init_session_maker()
-
- def _init_engine(self, model_list):
- logger.info("Initializing sqlalchemy backend: %s" % \
- self.connection_str)
- if self.connection_str == "sqlite://":
- # initialize in-memory sqlite (i.e. for testing)
- self._engine = create_engine(
- self.connection_str,
- connect_args={'check_same_thread': False},
- poolclass=StaticPool)
-
- # TODO(dolph): we should be using version control, but
- # we don't have a way to pass our in-memory instance to
- # the versioning api
- self._init_tables(model_list)
- else:
- # initialize a "real" database
- self._engine = create_engine(
- self.connection_str,
- pool_recycle=3600)
- self._init_version_control()
- self._init_tables(model_list)
-
- def _init_version_control(self):
- """Verify the state of the database"""
- repo_path = migration.get_migrate_repo_path()
-
- try:
- repo_version = migration.get_repo_version(repo_path)
- db_version = migration.get_db_version(self._engine, repo_path)
-
- if repo_version != db_version:
- msg = ('Database (%s) is not up to date (current=%s, '
- 'latest=%s); run `keystone-manage sync_database` or '
- 'override your migrate version manually (see docs)' %
- (self.connection_str, db_version, repo_version))
- logging.warning(msg)
- raise Exception(msg)
- except versioning_exceptions.DatabaseNotControlledError:
- msg = ('Database (%s) is not version controlled; '
- 'run `keystone-manage sync_database` or '
- 'override your migrate version manually (see docs)' %
- (self.connection_str))
- logging.warning(msg)
-
- @staticmethod
- def _init_models(model_list):
- for model in model_list:
- model_class = getattr(models, model)
- top_models.set_value(model, model_class)
-
- if model_class.__api__ is not None:
- api_path = '.'.join([__package__, 'api', model_class.__api__])
- api_module = sys.modules.get(api_path)
- if api_module is None:
- api_module = utils.import_module(api_path)
- top_api.set_value(model_class.__api__, api_module.get())
-
- def _init_tables(self, model_list):
- tables = []
-
- for model in model_list:
- model_class = getattr(models, model)
- tables.append(model_class.__table__)
-
- tables_to_create = []
- for table in reversed(models.Base.metadata.sorted_tables):
- if table in tables:
- tables_to_create.append(table)
-
- logger.debug('Creating tables: %s' % \
- ','.join([table.name for table in tables_to_create]))
- models.Base.metadata.create_all(self._engine, tables=tables_to_create,
- checkfirst=True)
-
- def _init_session_maker(self):
- self.session = sessionmaker(
- bind=self._engine,
- autocommit=True,
- expire_on_commit=False)
-
- def get_session(self):
- """Creates a pre-configured database session"""
- return self.session()
-
- def reset(self):
- """Unregister models and reset DB engine.
-
- Useful clearing out data before testing
-
- TODO(dolph)::
-
- ... but what does this *do*? Issue DROP TABLE statements?
- TRUNCATE TABLE? Or is the scope of impact limited to python?
- """
- if self._engine is not None:
- models.Base.metadata.drop_all(self._engine)
- self._engine = None
-
-
-def configure_backend(conf):
- global _DRIVER
- _DRIVER = Driver(conf)
-
-
-def get_session():
- global _DRIVER
- return _DRIVER.get_session()
-
-
-def unregister_models():
- global _DRIVER
- if _DRIVER:
- return _DRIVER.reset()
diff --git a/keystone/backends/sqlalchemy/api/credentials.py b/keystone/backends/sqlalchemy/api/credentials.py
deleted file mode 100755
index 22105694..00000000
--- a/keystone/backends/sqlalchemy/api/credentials.py
+++ /dev/null
@@ -1,137 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.backends.sqlalchemy import get_session, models
-from keystone.backends import api
-from keystone.models import Credentials
-from keystone.logic.types import fault
-
-
-# pylint: disable=E1103,W0221
-class CredentialsAPI(api.BaseCredentialsAPI):
- def __init__(self, *args, **kw):
- super(CredentialsAPI, self).__init__(*args, **kw)
-
- @staticmethod
- def transpose(ref):
- """ Transposes field names from domain to sql model"""
- if hasattr(api.TENANT, 'uid_to_id'):
- if 'tenant_id' in ref:
- ref['tenant_id'] = api.TENANT.uid_to_id(ref['tenant_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.tenant_id = api.TENANT.uid_to_id(ref.tenant_id)
-
- if hasattr(api.USER, 'uid_to_id'):
- if 'user_id' in ref:
- ref['user_id'] = api.USER.uid_to_id(ref['user_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.user_id = api.USER.uid_to_id(ref.user_id)
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- if hasattr(api.TENANT, 'uid_to_id'):
- if 'tenant_id' in ref:
- ref['tenant_id'] = api.TENANT.id_to_uid(ref['tenant_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.tenant_id = api.TENANT.id_to_uid(ref.tenant_id)
-
- if hasattr(api.USER, 'uid_to_id'):
- if 'user_id' in ref:
- ref['user_id'] = api.USER.id_to_uid(ref['user_id'])
- elif hasattr(ref, 'user_id'):
- ref.user_id = api.USER.id_to_uid(ref.user_id)
-
- return Credentials(id=ref.id, user_id=ref.user_id,
- tenant_id=ref.tenant_id, type=ref.type, key=ref.key,
- secret=ref.secret)
-
- @staticmethod
- def to_model_list(refs):
- return [CredentialsAPI.to_model(ref) for ref in refs]
-
- def create(self, values):
- data = values.copy()
- CredentialsAPI.transpose(data)
-
- if 'tenant_id' in values:
- if data['tenant_id'] is None and values['tenant_id'] is not None:
- raise fault.ItemNotFoundFault('Invalid tenant id: %s' % \
- values['tenant_id'])
-
- credentials_ref = models.Credentials()
- credentials_ref.update(data)
- credentials_ref.save()
-
- return CredentialsAPI.to_model(credentials_ref)
-
- @staticmethod
- def update(id, values, session=None):
- if not session:
- session = get_session()
-
- CredentialsAPI.transpose(values)
-
- with session.begin():
- ref = session.query(models.Credentials).filter_by(id=id).first()
- ref.update(values)
- ref.save(session=session)
-
- def get(self, id, session=None):
- result = self._get(id, session)
-
- return CredentialsAPI.to_model(result)
-
- @staticmethod
- def _get(id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
-
- return session.query(models.Credentials).filter_by(id=id).first()
-
- @staticmethod
- def get_all(session=None):
- if not session:
- session = get_session()
-
- results = session.query(models.Credentials).all()
-
- return CredentialsAPI.to_model_list(results)
-
- def get_by_access(self, access, session=None):
- if not session:
- session = get_session()
-
- result = session.query(models.Credentials).\
- filter_by(type="EC2", key=access).first()
-
- return CredentialsAPI.to_model(result)
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
-
- with session.begin():
- group_ref = self._get(id, session)
- session.delete(group_ref)
-
-
-def get():
- return CredentialsAPI()
diff --git a/keystone/backends/sqlalchemy/api/endpoint_template.py b/keystone/backends/sqlalchemy/api/endpoint_template.py
deleted file mode 100755
index 84fce454..00000000
--- a/keystone/backends/sqlalchemy/api/endpoint_template.py
+++ /dev/null
@@ -1,381 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.backends.sqlalchemy import get_session, models, aliased
-from keystone.backends import api
-
-
-# pylint: disable=E1103,W0221
-class EndpointTemplateAPI(api.BaseEndpointTemplateAPI):
- def __init__(self, *args, **kw):
- super(EndpointTemplateAPI, self).__init__(*args, **kw)
-
- @staticmethod
- def transpose(values):
- """ Transposes field names from domain to sql model"""
- pass
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- pass
-
- @staticmethod
- def to_model_list(refs):
- return [EndpointTemplateAPI.to_model(ref) for ref in refs]
-
- def create(self, values):
- endpoint_template = models.EndpointTemplates()
- endpoint_template.update(values)
- endpoint_template.save()
- return endpoint_template
-
- def update(self, id, values, session=None):
- if not session:
- session = get_session()
- with session.begin():
- ref = self.get(id, session)
- ref.update(values)
- ref.save(session=session)
- return ref
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
- with session.begin():
- endpoint_template = self.get(id, session)
- session.delete(endpoint_template)
-
- def get(self, id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
-
- return session.query(models.EndpointTemplates).\
- filter_by(id=id).first()
-
- def get_all(self, session=None):
- if not session:
- session = get_session()
-
- return session.query(models.EndpointTemplates).all()
-
- def get_by_service(self, service_id, session=None):
- if not session:
- session = get_session()
- return session.query(models.EndpointTemplates).\
- filter_by(service_id=service_id).all()
-
- def get_by_service_get_page(self, service_id, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if marker:
- return session.query(models.EndpointTemplates).\
- filter("id>:marker").params(\
- marker='%s' % marker).filter_by(\
- service_id=service_id).order_by(\
- models.EndpointTemplates.id.desc()).limit(int(limit)).all()
- else:
- return session.query(models.EndpointTemplates).filter_by(\
- service_id=service_id).order_by(\
- models.EndpointTemplates.id.desc()).\
- limit(int(limit)).all()
-
- # pylint: disable=R0912
- def get_by_service_get_page_markers(self, service_id, marker, \
- limit, session=None):
- if not session:
- session = get_session()
- first = session.query(models.EndpointTemplates).filter_by(\
- service_id=service_id).order_by(\
- models.EndpointTemplates.id).first()
- last = session.query(models.EndpointTemplates).filter_by(\
- service_id=service_id).order_by(\
- models.EndpointTemplates.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.EndpointTemplates).\
- filter("id > :marker").\
- filter_by(service_id=service_id).\
- params(marker='%s' % marker).\
- order_by(models.EndpointTemplates.id).\
- limit(int(limit)).\
- all()
- prev_page = session.query(models.EndpointTemplates).\
- filter("id < :marker").\
- filter_by(service_id=service_id).\
- params(marker='%s' % marker).\
- order_by(models.EndpointTemplates.id.desc()).\
- limit(int(limit)).\
- all()
- if len(next_page) == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if len(prev_page) == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def get_page(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if marker:
- return session.query(models.EndpointTemplates).\
- filter("id>:marker").params(\
- marker='%s' % marker).order_by(\
- models.EndpointTemplates.id.desc()).limit(int(limit)).all()
- else:
- return session.query(models.EndpointTemplates).order_by(\
- models.EndpointTemplates.id.desc()).\
- limit(int(limit)).all()
-
- # pylint: disable=R0912
- def get_page_markers(self, marker, limit, session=None):
- if not session:
- session = get_session()
- first = session.query(models.EndpointTemplates).order_by(\
- models.EndpointTemplates.id).first()
- last = session.query(models.EndpointTemplates).order_by(\
- models.EndpointTemplates.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.EndpointTemplates).\
- filter("id > :marker").\
- params(marker='%s' % marker).\
- order_by(models.EndpointTemplates.id).\
- limit(int(limit)).\
- all()
- prev_page = session.query(models.EndpointTemplates).\
- filter("id < :marker").\
- params(marker='%s' % marker).\
- order_by(models.EndpointTemplates.id.desc()).\
- limit(int(limit)).\
- all()
- if len(next_page) == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if len(prev_page) == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def endpoint_get_by_tenant_get_page(self, tenant_id, marker, limit,
- session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- if marker:
- results = session.query(models.Endpoints).\
- filter(models.Endpoints.tenant_id == tenant_id).\
- filter("id >= :marker").params(
- marker='%s' % marker).order_by(
- models.Endpoints.id).limit(int(limit)).all()
- else:
- results = session.query(models.Endpoints).\
- filter(models.Endpoints.tenant_id == tenant_id).\
- order_by(models.Endpoints.id).limit(int(limit)).all()
-
- if hasattr(api.TENANT, 'id_to_uid'):
- for result in results:
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return results
-
- # pylint: disable=R0912
- def endpoint_get_by_tenant_get_page_markers(self, tenant_id, marker, limit,
- session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- tba = aliased(models.Endpoints)
- first = session.query(tba).\
- filter(tba.tenant_id == tenant_id).\
- order_by(tba.id).first()
- last = session.query(tba).\
- filter(tba.tenant_id == tenant_id).\
- order_by(tba.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(tba).\
- filter(tba.tenant_id == tenant_id).\
- filter("id>=:marker").params(
- marker='%s' % marker).order_by(
- tba.id).limit(int(limit)).all()
-
- prev_page = session.query(tba).\
- filter(tba.tenant_id == tenant_id).\
- filter("id < :marker").params(
- marker='%s' % marker).order_by(
- tba.id).limit(int(limit) + 1).all()
- next_len = len(next_page)
- prev_len = len(prev_page)
-
- if next_len == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if prev_len == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if first.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if marker == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def endpoint_add(self, values):
- if hasattr(api.TENANT, 'uid_to_id'):
- values.tenant_id = api.TENANT.uid_to_id(values.tenant_id)
-
- endpoints = models.Endpoints()
- endpoints.update(values)
- endpoints.save()
-
- if hasattr(api.TENANT, 'id_to_uid'):
- endpoints.tenant_id = api.TENANT.id_to_uid(endpoints.tenant_id)
-
- return endpoints
-
- def endpoint_get(self, id, session=None):
- if not session:
- session = get_session()
-
- result = session.query(models.Endpoints).\
- filter_by(id=id).first()
-
- if hasattr(api.TENANT, 'id_to_uid'):
- if result:
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return result
-
- @staticmethod
- def endpoint_get_by_ids(endpoint_template_id, tenant_id,
- session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- result = session.query(models.Endpoints).\
- filter_by(endpoint_template_id=endpoint_template_id).\
- filter_by(tenant_id=tenant_id).first()
-
- if hasattr(api.TENANT, 'id_to_uid'):
- if result:
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return result
-
- @staticmethod
- def endpoint_get_all(session=None):
- if not session:
- session = get_session()
-
- results = session.query(models.Endpoints).all()
-
- for result in results:
- if hasattr(api.TENANT, 'id_to_uid'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return results
-
- def endpoint_get_by_tenant(self, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- result = session.query(models.Endpoints).\
- filter_by(tenant_id=tenant_id).first()
-
- if hasattr(api.TENANT, 'id_to_uid'):
- if result:
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return result
-
- def endpoint_get_by_endpoint_template(
- self, endpoint_template_id, session=None):
- if not session:
- session = get_session()
-
- result = session.query(models.Endpoints).\
- filter_by(endpoint_template_id=endpoint_template_id).all()
-
- return result
-
- def endpoint_delete(self, id, session=None):
- if not session:
- session = get_session()
-
- with session.begin():
- endpoints = self.endpoint_get(id, session)
- if endpoints:
- session.delete(endpoints)
-
-
-def get():
- return EndpointTemplateAPI()
diff --git a/keystone/backends/sqlalchemy/api/role.py b/keystone/backends/sqlalchemy/api/role.py
deleted file mode 100755
index 5419924f..00000000
--- a/keystone/backends/sqlalchemy/api/role.py
+++ /dev/null
@@ -1,463 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.backends.sqlalchemy import get_session, models
-from keystone.backends import api
-from keystone.models import Role, UserRoleAssociation
-
-
-# pylint: disable=E1103,W0221
-class RoleAPI(api.BaseRoleAPI):
- def __init__(self, *args, **kw):
- super(RoleAPI, self).__init__(*args, **kw)
-
- @staticmethod
- def transpose(values):
- """ Handles transposing field names from Keystone model to
- sqlalchemy mode
-
- Differences:
- desc <-> description
- """
- if 'description' in values:
- values['desc'] = values.pop('description')
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- return Role(id=str(ref.id), name=ref.name, description=ref.desc,
- service_id=ref.service_id)
-
- @staticmethod
- def to_model_list(refs):
- return [RoleAPI.to_model(ref) for ref in refs]
-
- @staticmethod
- def to_ura_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- return UserRoleAssociation(id=ref.id,
- role_id=ref.role_id,
- user_id=ref.user_id,
- tenant_id=ref.tenant_id)
-
- @staticmethod
- def to_ura_model_list(refs):
- return [RoleAPI.to_ura_model(ref) for ref in refs]
-
- # pylint: disable=W0221
- def create(self, values):
- data = values.copy()
- RoleAPI.transpose(data)
- role = models.Role()
- role.update(data)
- role.save()
- return RoleAPI.to_model(role)
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
- with session.begin():
- role = session.query(models.Role).filter_by(id=id).first()
- session.delete(role)
-
- @staticmethod
- def update(id, values, session=None):
- if not session:
- session = get_session()
-
- RoleAPI.transpose(values)
-
- with session.begin():
- ref = session.query(models.Role).filter_by(id=id).first()
- ref.update(values)
- ref.save(session=session)
-
- def get(self, id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
- return RoleAPI.to_model(
- session.query(models.Role).filter_by(id=id).first())
-
- def get_by_name(self, name, session=None):
- if not session:
- session = get_session()
- return RoleAPI.to_model(
- session.query(models.Role).filter_by(name=name).first())
-
- def get_by_service(self, service_id, session=None):
- if not session:
- session = get_session()
- results = session.query(models.Role).\
- filter_by(service_id=service_id).all()
- return RoleAPI.to_model_list(results)
-
- def get_all(self, session=None):
- if not session:
- session = get_session()
- return RoleAPI.to_model_list(session.query(models.Role).all())
-
- def get_page(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if marker:
- results = session.query(models.Role).filter("id>:marker").params(
- marker='%s' % marker).order_by(
- models.Role.id.desc()).limit(int(limit)).all()
- else:
- results = session.query(models.Role).order_by(
- models.Role.id.desc()).limit(int(limit)).all()
- return RoleAPI.to_model_list(results)
-
- # pylint: disable=R0912
- def get_page_markers(self, marker, limit, session=None):
- if not session:
- session = get_session()
- first = session.query(models.Role).order_by(
- models.Role.id).first()
- last = session.query(models.Role).order_by(
- models.Role.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.Role).filter("id > :marker").params(
- marker='%s' % marker).order_by(
- models.Role.id).limit(int(limit)).all()
- prev_page = session.query(models.Role).filter("id < :marker").params(
- marker='%s' % marker).order_by(
- models.Role.id.desc()).limit(int(limit)).all()
- if not next_page:
- next_page = last
- else:
- next_page = next_page[-1]
- if not prev_page:
- prev_page = first
- else:
- prev_page = prev_page[-1]
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def get_by_service_get_page(self, service_id, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if marker:
- results = session.query(models.Role).filter("id>:marker").params(
- marker='%s' % marker).filter_by(
- service_id=service_id).order_by(
- models.Role.id.desc()).limit(int(limit)).all()
- else:
- results = session.query(models.Role).filter_by(
- service_id=service_id).order_by(
- models.Role.id.desc()).limit(int(limit)).all()
- return RoleAPI.to_model_list(results)
-
- # pylint: disable=R0912
- def get_by_service_get_page_markers(self,
- service_id, marker, limit, session=None):
- if not session:
- session = get_session()
- first = session.query(models.Role).filter_by(
- service_id=service_id).order_by(
- models.Role.id).first()
- last = session.query(models.Role).filter_by(
- service_id=service_id).order_by(
- models.Role.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.Role).filter("id > :marker").params(
- marker='%s' % marker).filter_by(
- service_id=service_id).order_by(
- models.Role.id).limit(int(limit)).all()
- prev_page = session.query(models.Role).filter("id < :marker").params(
- marker='%s' % marker).filter_by(
- service_id=service_id).order_by(
- models.Role.id.desc()).limit(int(limit)).all()
- if not next_page:
- next_page = last
- else:
- next_page = next_page[-1]
- if not prev_page:
- prev_page = first
- else:
- prev_page = prev_page[-1]
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- #
- # Role Grants start here
- #
- def rolegrant_get(self, id, session=None):
- if not session:
- session = get_session()
-
- result = session.query(models.UserRoleAssociation).filter_by(id=id).\
- first()
-
- if result:
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model(result)
-
- def list_role_grants(self, role_id=None, user_id=None, tenant_id=None,
- session=None):
- """Lists all role grants; optionally specify a role ID, user ID, or
- tenant ID.
-
- If tenant ID is provided as False (tenant_id=False), global grants will
- be returned."""
-
- session = session or get_session()
-
- is_global = tenant_id == False
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- query = session.query(models.UserRoleAssociation)
-
- if role_id is not None:
- query = query.filter_by(role_id=role_id)
-
- if user_id is not None:
- query = query.filter_by(user_id=user_id)
-
- if is_global:
- query = query.filter(models.UserRoleAssociation.tenant_id == None)
- elif tenant_id is not None:
- query = query.filter_by(tenant_id=tenant_id)
-
- results = query.all()
-
- for result in results:
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model_list(results)
-
- def rolegrant_delete(self, id, session=None):
- if not session:
- session = get_session()
-
- with session.begin():
- rolegrant = session.query(models.UserRoleAssociation).\
- filter_by(id=id).first()
- session.delete(rolegrant)
-
- # pylint: disable=R0912
- def rolegrant_get_page_markers(self, user_id, tenant_id, marker,
- limit, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- query = session.query(models.UserRoleAssociation).filter_by(
- user_id=user_id)
- if tenant_id:
- query = query.filter_by(tenant_id=tenant_id)
- else:
- query = query.filter("tenant_id is null")
- first = query.order_by(models.UserRoleAssociation.id).first()
- last = query.order_by(models.UserRoleAssociation.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = query.\
- filter("id > :marker").\
- params(marker='%s' % marker).\
- order_by(models.UserRoleAssociation.id).\
- limit(int(limit)).\
- all()
- prev_page = query.\
- filter("id < :marker").\
- params(marker='%s' % marker).\
- order_by(models.UserRoleAssociation.id.desc()).\
- limit(int(limit)).\
- all()
-
- if not next_page:
- next_page = last
- else:
- next_page = next_page[-1]
- if not prev_page:
- prev_page = first
- else:
- prev_page = prev_page[-1]
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def rolegrant_get_page(self, marker, limit, user_id, tenant_id,
- session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- query = session.query(models.UserRoleAssociation).\
- filter_by(user_id=user_id)
- if tenant_id:
- query = query.filter_by(tenant_id=tenant_id)
- else:
- query = query.filter("tenant_id is null")
- if marker:
- results = query.filter("id>:marker").params(
- marker='%s' % marker).order_by(
- models.UserRoleAssociation.id.desc()).limit(
- int(limit)).all()
- else:
- results = query.order_by(
- models.UserRoleAssociation.id.desc()).limit(
- int(limit)).all()
-
- for result in results:
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model_list(results)
-
- def list_global_roles_for_user(self, user_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
-
- results = session.query(models.UserRoleAssociation).\
- filter_by(user_id=user_id).filter("tenant_id is null").all()
-
- for result in results:
- result['role_id'] = str(result['role_id'])
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model_list(results)
-
- def list_tenant_roles_for_user(self, user_id, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- results = session.query(models.UserRoleAssociation).\
- filter_by(user_id=user_id).filter_by(tenant_id=tenant_id).all()
-
- for result in results:
- result['role_id'] = str(result['role_id'])
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model_list(results)
-
- def rolegrant_list_by_role(self, role_id, session=None):
- """ Get a list of all (global and tenant) grants for this role """
- if not session:
- session = get_session()
-
- results = session.query(models.UserRoleAssociation).\
- filter_by(role_id=role_id).all()
-
- for result in results:
- result['role_id'] = str(result['role_id'])
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model_list(results)
-
- def rolegrant_get_by_ids(self, user_id, role_id, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- if tenant_id is None:
- result = session.query(models.UserRoleAssociation).\
- filter_by(user_id=user_id).filter("tenant_id is null").\
- filter_by(role_id=role_id).first()
- else:
- result = session.query(models.UserRoleAssociation).\
- filter_by(user_id=user_id).filter_by(tenant_id=tenant_id).\
- filter_by(role_id=role_id).first()
-
- if result:
- result['role_id'] = str(result['role_id'])
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return RoleAPI.to_ura_model(result)
-
-
-def get():
- return RoleAPI()
diff --git a/keystone/backends/sqlalchemy/api/service.py b/keystone/backends/sqlalchemy/api/service.py
deleted file mode 100644
index 3e546106..00000000
--- a/keystone/backends/sqlalchemy/api/service.py
+++ /dev/null
@@ -1,194 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.backends.sqlalchemy import get_session, models
-from keystone.backends import api
-from keystone.models import Service
-
-
-# pylint: disable=E1103,W0221
-class ServiceAPI(api.BaseServiceAPI):
- def __init__(self, *args, **kw):
- super(ServiceAPI, self).__init__(*args, **kw)
-
- # pylint: disable=W0221
- @staticmethod
- def transpose(values):
- """ Handles transposing field names from Keystone model to
- sqlalchemy model
-
- Differences:
- desc <-> description
- id <-> uid (coming soon)
- """
- if 'description' in values:
- values['desc'] = values.pop('description')
-
- if hasattr(api.USER, 'uid_to_id'):
- if 'owner_id' in values:
- values['owner_id'] = api.USER.uid_to_id(values['owner_id'])
- elif hasattr(values, 'owner_id'):
- values.owner_id = api.USER.uid_to_id(values.owner_id)
-
- @staticmethod
- def from_model(ref):
- """ Returns SQLAlchemy model object based on Keystone model"""
- if ref:
- if hasattr(api.USER, 'uid_to_id'):
- if 'owner_id' in ref:
- ref['owner_id'] = api.USER.uid_to_id(ref['owner_id'])
- elif hasattr(ref, 'owner_id'):
- ref.owner_id = api.USER.uid_to_id(ref.owner_id)
-
- result = models.Service()
- try:
- result.id = int(ref.id)
- except (AttributeError, TypeError):
- # Unspecified or invalid ID -- ignore it.
- pass
- result.update(ref)
- if hasattr(ref, 'description'):
- result.desc = ref.description
- return result
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- if hasattr(api.USER, 'id_to_uid'):
- if 'owner_id' in ref:
- ref['owner_id'] = api.USER.id_to_uid(ref['owner_id'])
- elif hasattr(ref, 'owner_id'):
- ref.owner_id = api.USER.id_to_uid(ref.owner_id)
-
- return Service(id=str(ref.id), name=ref.name, description=ref.desc,
- type=ref.type, owner_id=ref.owner_id)
-
- @staticmethod
- def to_model_list(refs):
- return [ServiceAPI.to_model(ref) for ref in refs]
-
- # pylint: disable=W0221
- def create(self, values):
- service_ref = ServiceAPI.from_model(values)
- service_ref.save()
- return ServiceAPI.to_model(service_ref)
-
- @staticmethod
- def update(id, values, session=None):
- if not session:
- session = get_session()
-
- ServiceAPI.transpose(values)
-
- with session.begin():
- service_ref = session.query(models.Service).filter_by(id=id).\
- first()
- service_ref.update(values)
- service_ref.save(session=session)
-
- def get(self, id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
- return ServiceAPI.to_model(session.query(models.Service).
- filter_by(id=id).first())
-
- def get_by_name(self, name, session=None):
- if not session:
- session = get_session()
- return ServiceAPI.to_model(session.query(models.Service).
- filter_by(name=name).first())
-
- def get_by_name_and_type(self, name, type, session=None):
- if not session:
- session = get_session()
- result = session.query(models.Service).\
- filter_by(name=name).\
- filter_by(type=type).\
- first()
- return ServiceAPI.to_model(result)
-
- def get_all(self, session=None):
- if not session:
- session = get_session()
- return ServiceAPI.to_model_list(session.query(models.Service).all())
-
- def get_page(self, marker, limit, session=None):
- if not session:
- session = get_session()
- if marker:
- return session.query(models.Service).filter("id>:marker").params(
- marker='%s' % marker).order_by(
- models.Service.id.desc()).limit(int(limit)).all()
- else:
- return session.query(models.Service).order_by(
- models.Service.id.desc()).limit(
- int(limit)).all()
-
- @staticmethod
- def get_page_markers(marker, limit, session=None):
- if not session:
- session = get_session()
- first = session.query(models.Service).order_by(
- models.Service.id).first()
- last = session.query(models.Service).order_by(
- models.Service.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.Service).\
- filter("id > :marker").params(
- marker='%s' % marker).order_by(
- models.Service.id).limit(int(limit)).all()
- prev_page = session.query(models.Service).\
- filter("id < :marker").params(
- marker='%s' % marker).order_by(
- models.Service.id.desc()).limit(int(limit)).all()
- if len(next_page) == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if len(prev_page) == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
- with session.begin():
- service_ref = session.query(models.Service).\
- filter_by(id=id).first()
- session.delete(service_ref)
-
-
-def get():
- return ServiceAPI()
diff --git a/keystone/backends/sqlalchemy/api/tenant.py b/keystone/backends/sqlalchemy/api/tenant.py
deleted file mode 100755
index db516b15..00000000
--- a/keystone/backends/sqlalchemy/api/tenant.py
+++ /dev/null
@@ -1,377 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 uuid
-
-from keystone.backends.sqlalchemy import get_session, models, aliased
-from keystone.backends import api
-from keystone.models import Tenant
-
-
-# pylint: disable=E1103,W0221
-class TenantAPI(api.BaseTenantAPI):
- def __init__(self, *args, **kw):
- super(TenantAPI, self).__init__(*args, **kw)
-
- # pylint: disable=W0221
- @staticmethod
- def transpose(values):
- """ Handles transposing field names from Keystone model to
- sqlalchemy mode
-
- Differences:
- desc <-> description
- id <-> uid (coming soon)
- """
- if 'id' in values:
- values['uid'] = values['id']
- del values['id']
- if 'description' in values:
- values['desc'] = values['description']
- del values['description']
- if 'enabled' in values:
- if values['enabled'] in [1, 'true', 'True', True]:
- values['enabled'] = True
- else:
- values['enabled'] = False
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- return Tenant(id=ref.uid, name=ref.name, description=ref.desc,
- enabled=bool(ref.enabled))
-
- @staticmethod
- def to_model_list(refs):
- return [TenantAPI.to_model(ref) for ref in refs]
-
- def create(self, values):
- data = values.copy()
- TenantAPI.transpose(data)
- tenant_ref = models.Tenant()
- tenant_ref.update(data)
- if tenant_ref.uid is None:
- tenant_ref.uid = uuid.uuid4().hex
- tenant_ref.save()
- return TenantAPI.to_model(tenant_ref)
-
- def get(self, id, session=None):
- """Returns a tenant by ID.
-
- .warning::
-
- Internally, the provided ID is matched against the ``tenants.UID``,
- not the PK (``tenants.id``) column.
-
- For PK lookups from within the sqlalchemy backend,
- use ``_get_by_id()`` instead.
- """
- if id is None:
- return None
-
- session = session or get_session()
-
- result = session.query(models.Tenant).filter_by(uid=id).first()
-
- return TenantAPI.to_model(result)
-
- @staticmethod
- def _get_by_id(id, session=None):
- """Returns a tenant by ID (PK).
-
- .warning::
-
- The provided ID is matched against the PK (``tenants.ID``).
-
- This is **only** for use within the sqlalchemy backend.
- """
- if id is None:
- return None
-
- session = session or get_session()
-
- return session.query(models.Tenant).filter_by(id=id).first()
-
- @staticmethod
- def id_to_uid(id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
- tenant = session.query(models.Tenant).filter_by(id=id).first()
- return tenant.uid if tenant else None
-
- @staticmethod
- def uid_to_id(uid, session=None):
- if uid is None:
- return None
-
- session = session or get_session()
- tenant = session.query(models.Tenant).filter_by(uid=uid).first()
- return tenant.id if tenant else None
-
- def get_by_name(self, name, session=None):
- session = session or get_session()
-
- result = session.query(models.Tenant).filter_by(name=name).first()
-
- return TenantAPI.to_model(result)
-
- def get_all(self, session=None):
- if not session:
- session = get_session()
-
- results = session.query(models.Tenant).all()
-
- return TenantAPI.to_model_list(results)
-
- def list_for_user_get_page(self, user_id, marker, limit, session=None):
- if not session:
- session = get_session()
-
- user = api.USER.get(user_id)
- if hasattr(api.USER, 'uid_to_id'):
- backend_user_id = api.USER.uid_to_id(user_id)
- else:
- backend_user_id = user_id
-
- ura = aliased(models.UserRoleAssociation)
- tenant = aliased(models.Tenant)
- q1 = session.query(tenant).join((ura, ura.tenant_id == tenant.id)).\
- filter(ura.user_id == backend_user_id)
- if 'tenant_id' in user:
- if hasattr(api.TENANT, 'uid_to_id'):
- backend_tenant_id = api.TENANT.uid_to_id(user.tenant_id)
- else:
- backend_tenant_id = user.tenant_id
- q2 = session.query(tenant).filter(tenant.id == backend_tenant_id)
- q3 = q1.union(q2)
- else:
- q3 = q1
- if marker:
- results = q3.filter("tenant.id>:marker").params(
- marker='%s' % marker).order_by(
- tenant.id.desc()).limit(int(limit)).all()
- else:
- results = q3.order_by(tenant.id.desc()).limit(int(limit)).all()
-
- return TenantAPI.to_model_list(results)
-
- # pylint: disable=R0912
- def list_for_user_get_page_markers(self, user_id, marker, limit,
- session=None):
- if not session:
- session = get_session()
-
- user = api.USER.get(user_id)
- if hasattr(api.USER, 'uid_to_id'):
- backend_user_id = api.USER.uid_to_id(user_id)
- else:
- backend_user_id = user_id
-
- ura = aliased(models.UserRoleAssociation)
- tenant = aliased(models.Tenant)
- q1 = session.query(tenant).join((ura, ura.tenant_id == tenant.id)).\
- filter(ura.user_id == backend_user_id)
- if 'tenant_id' in user:
- if hasattr(api.TENANT, 'uid_to_id'):
- backend_tenant_id = api.TENANT.uid_to_id(user.tenant_id)
- else:
- backend_tenant_id = user.tenant_id
- q2 = session.query(tenant).filter(tenant.id == backend_tenant_id)
- q3 = q1.union(q2)
- else:
- q3 = q1
-
- first = q3.order_by(tenant.id).first()
- last = q3.order_by(tenant.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = q3.filter(tenant.id > marker).order_by(
- tenant.id).limit(int(limit)).all()
- prev_page = q3.filter(tenant.id > marker).order_by(
- tenant.id.desc()).limit(int(limit)).all()
- if len(next_page) == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if len(prev_page) == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def get_page(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if marker:
- tenants = session.query(models.Tenant).\
- filter("id>:marker").params(
- marker='%s' % marker).order_by(
- models.Tenant.id.desc()).limit(int(limit)).all()
- else:
- tenants = session.query(models.Tenant).order_by(
- models.Tenant.id.desc()).limit(int(limit)).all()
-
- return self.to_model_list(tenants)
-
- # pylint: disable=R0912
- def get_page_markers(self, marker, limit, session=None):
- if not session:
- session = get_session()
- first = session.query(models.Tenant).order_by(
- models.Tenant.id).first()
- last = session.query(models.Tenant).order_by(
- models.Tenant.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.Tenant).\
- filter("id > :marker").\
- params(marker='%s' % marker).\
- order_by(models.Tenant.id).\
- limit(int(limit)).\
- all()
- prev_page = session.query(models.Tenant).\
- filter("id < :marker").\
- params(marker='%s' % marker).\
- order_by(models.Tenant.id.desc()).\
- limit(int(limit)).\
- all()
- if len(next_page) == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if len(prev_page) == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def is_empty(self, id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- id = self.uid_to_id(id)
-
- a_user = session.query(models.UserRoleAssociation).filter_by(
- tenant_id=id).first()
- if a_user is not None:
- return False
- a_user = session.query(models.User).filter_by(tenant_id=id).first()
- if a_user is not None:
- return False
- return True
-
- def update(self, id, values, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- pkid = self.uid_to_id(id)
- else:
- pkid = id
-
- data = values.copy()
- TenantAPI.transpose(data)
-
- with session.begin():
- tenant_ref = self._get_by_id(pkid, session)
- tenant_ref.update(data)
- tenant_ref.save(session=session)
- return self.get(id, session)
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
-
- if not self.is_empty(id):
- raise fault.ForbiddenFault("You may not delete a tenant that "
- "contains users")
-
- if hasattr(api.TENANT, 'uid_to_id'):
- id = self.uid_to_id(id)
-
- with session.begin():
- tenant_ref = self._get_by_id(id, session)
- session.delete(tenant_ref)
-
- def get_all_endpoints(self, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = self.uid_to_id(tenant_id)
-
- endpoint_templates = aliased(models.EndpointTemplates)
- q = session.query(endpoint_templates).\
- filter(endpoint_templates.is_global == True)
- if tenant_id:
- ep = aliased(models.Endpoints)
- q1 = session.query(endpoint_templates).join((ep,
- ep.endpoint_template_id == endpoint_templates.id)).\
- filter(ep.tenant_id == tenant_id)
- q = q.union(q1)
- return q.all()
-
- def get_role_assignments(self, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = TenantAPI.uid_to_id(tenant_id)
-
- results = session.query(models.UserRoleAssociation).\
- filter_by(tenant_id=tenant_id)
-
- for result in results:
- if hasattr(api.USER, 'uid_to_id'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return results
-
-
-def get():
- return TenantAPI()
diff --git a/keystone/backends/sqlalchemy/api/token.py b/keystone/backends/sqlalchemy/api/token.py
deleted file mode 100755
index 869822bb..00000000
--- a/keystone/backends/sqlalchemy/api/token.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.backends.sqlalchemy import get_session, models
-from keystone.backends import api
-from keystone.models import Token
-
-
-# pylint: disable=E1103,W0221
-class TokenAPI(api.BaseTokenAPI):
- def __init__(self, *args, **kw):
- super(TokenAPI, self).__init__(*args, **kw)
-
- @staticmethod
- def transpose(ref):
- """ Transposes field names from domain to sql model"""
- if hasattr(api.TENANT, 'uid_to_id'):
- if 'tenant_id' in ref:
- ref['tenant_id'] = api.TENANT.uid_to_id(ref['tenant_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.tenant_id = api.TENANT.uid_to_id(ref.tenant_id)
-
- if hasattr(api.USER, 'uid_to_id'):
- if 'user_id' in ref:
- ref['user_id'] = api.USER.uid_to_id(ref['user_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.user_id = api.USER.uid_to_id(ref.user_id)
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- if hasattr(api.TENANT, 'uid_to_id'):
- if 'tenant_id' in ref:
- ref['tenant_id'] = api.TENANT.id_to_uid(ref['tenant_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.tenant_id = api.TENANT.id_to_uid(ref.tenant_id)
-
- if hasattr(api.USER, 'uid_to_id'):
- if 'user_id' in ref:
- ref['user_id'] = api.USER.id_to_uid(ref['user_id'])
- elif hasattr(ref, 'user_id'):
- ref.user_id = api.USER.id_to_uid(ref.user_id)
-
- return Token(id=ref.id, user_id=ref.user_id, expires=ref.expires,
- tenant_id=ref.tenant_id)
-
- @staticmethod
- def to_model_list(refs):
- return [TokenAPI.to_model(ref) for ref in refs]
-
- def create(self, values):
- data = values.copy()
- TokenAPI.transpose(data)
- token_ref = models.Token()
- token_ref.update(data)
- token_ref.save()
- return TokenAPI.to_model(token_ref)
-
- def get(self, id, session=None):
- result = self._get(id, session)
-
- return TokenAPI.to_model(result)
-
- @staticmethod
- def _get(id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
-
- result = session.query(models.Token).filter_by(id=id).first()
-
- return result
-
- @staticmethod
- def update(id, values, session=None):
- if not session:
- session = get_session()
-
- TokenAPI.transpose(values)
-
- with session.begin():
- ref = session.query(models.Token).filter_by(id=id).first()
- ref.update(values)
- ref.save(session=session)
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
-
- with session.begin():
- token_ref = self._get(id, session)
- session.delete(token_ref)
-
- def get_for_user(self, user_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
-
- result = session.query(models.Token).filter_by(
- user_id=user_id, tenant_id=None).order_by("expires desc").first()
-
- return TokenAPI.to_model(result)
-
- def get_for_user_by_tenant(self, user_id, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- result = session.query(models.Token).\
- filter_by(user_id=user_id, tenant_id=tenant_id).\
- order_by("expires desc").\
- first()
-
- return TokenAPI.to_model(result)
-
- def get_all(self, session=None):
- if not session:
- session = get_session()
-
- results = session.query(models.Token).all()
-
- return TokenAPI.to_model_list(results)
-
-
-def get():
- return TokenAPI()
diff --git a/keystone/backends/sqlalchemy/api/user.py b/keystone/backends/sqlalchemy/api/user.py
deleted file mode 100755
index f5a64b18..00000000
--- a/keystone/backends/sqlalchemy/api/user.py
+++ /dev/null
@@ -1,458 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 uuid
-
-import keystone.backends.backendutils as utils
-from keystone.backends.sqlalchemy import get_session, models, aliased, \
- joinedload
-from keystone.backends import api
-from keystone.models import User
-
-
-# pylint: disable=E1103,W0221,W0223
-class UserAPI(api.BaseUserAPI):
- def __init__(self, *args, **kw):
- super(UserAPI, self).__init__(*args, **kw)
-
- @staticmethod
- def transpose(ref):
- """ Transposes field names from domain to sql model"""
- if 'id' in ref:
- ref['uid'] = ref.pop('id')
-
- if hasattr(api.TENANT, 'uid_to_id'):
- if 'tenant_id' in ref:
- ref['tenant_id'] = api.TENANT.uid_to_id(ref['tenant_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.tenant_id = api.TENANT.uid_to_id(ref.tenant_id)
-
- @staticmethod
- def to_model(ref):
- """ Returns Keystone model object based on SQLAlchemy model"""
- if ref:
- if hasattr(api.TENANT, 'uid_to_id'):
- if 'tenant_id' in ref:
- ref['tenant_id'] = api.TENANT.id_to_uid(ref['tenant_id'])
- elif hasattr(ref, 'tenant_id'):
- ref.tenant_id = api.TENANT.id_to_uid(ref.tenant_id)
-
- return User(id=ref.uid, password=ref.password, name=ref.name,
- tenant_id=ref.tenant_id, email=ref.email,
- enabled=bool(ref.enabled))
-
- @staticmethod
- def to_model_list(refs):
- return [UserAPI.to_model(ref) for ref in refs]
-
- # pylint: disable=W0221
- def get_all(self, session=None):
- if not session:
- session = get_session()
-
- results = session.query(models.User)
-
- return UserAPI.to_model_list(results)
-
- def create(self, values):
- data = values.copy()
- UserAPI.transpose(data)
- utils.set_hashed_password(data)
- if 'uid' not in data or data['uid'] is None:
- data['uid'] = uuid.uuid4().hex
- user_ref = models.User()
- user_ref.update(data)
- user_ref.save()
- return UserAPI.to_model(user_ref)
-
- def get(self, id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
-
- result = session.query(models.User).filter_by(uid=str(id)).first()
-
- return UserAPI.to_model(result)
-
- @staticmethod
- def _get_by_id(id, session=None):
- """Only for use by the sql backends
-
- - Queries by PK ID
- - Doesn't wrap result with domain layer models
- """
- if id is None:
- return None
-
- session = session or get_session()
-
- # TODO(dolph): user ID's are NOT strings... why is this is being cast?
- return session.query(models.User).filter_by(id=str(id)).first()
-
- @staticmethod
- def id_to_uid(id, session=None):
- if id is None:
- return None
-
- session = session or get_session()
- user = session.query(models.User).filter_by(id=str(id)).first()
- return user.uid if user else None
-
- @staticmethod
- def uid_to_id(uid, session=None):
- if uid is None:
- return None
-
- session = session or get_session()
- user = session.query(models.User).filter_by(uid=str(uid)).first()
- return user.id if user else None
-
- def get_by_name(self, name, session=None):
- if not session:
- session = get_session()
-
- result = session.query(models.User).filter_by(name=name).first()
-
- return UserAPI.to_model(result)
-
- def get_by_email(self, email, session=None):
- if not session:
- session = get_session()
-
- result = session.query(models.User).filter_by(email=email).first()
-
- return UserAPI.to_model(result)
-
- def get_page(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if marker:
- results = session.query(models.User).filter("id>:marker").params(
- marker='%s' % marker).order_by(
- models.User.id.desc()).limit(int(limit)).all()
- else:
- results = session.query(models.User).order_by(
- models.User.id.desc()).limit(int(limit)).all()
-
- return UserAPI.to_model_list(results)
-
- # pylint: disable=R0912
- def get_page_markers(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- first = session.query(models.User).order_by(
- models.User.id).first()
- last = session.query(models.User).order_by(
- models.User.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(models.User).filter("id > :marker").params(
- marker='%s' % marker).order_by(
- models.User.id).limit(int(limit)).all()
- prev_page = session.query(models.User).filter("id < :marker").params(
- marker='%s' % marker).order_by(
- models.User.id.desc()).limit(int(limit)).all()
- if len(next_page) == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if len(prev_page) == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if prev_page.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if next_page.id == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def user_roles_by_tenant(self, user_id, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- results = session.query(models.UserRoleAssociation).\
- filter_by(user_id=user_id, tenant_id=tenant_id).\
- options(joinedload('roles'))
-
- for result in results:
- if hasattr(api.USER, 'id_to_uid'):
- result.user_id = api.USER.id_to_uid(result.user_id)
- if hasattr(api.TENANT, 'id_to_uid'):
- result.tenant_id = api.TENANT.id_to_uid(result.tenant_id)
-
- return results
-
- def update(self, id, values, session=None):
- if not session:
- session = get_session()
-
- UserAPI.transpose(values)
-
- with session.begin():
- user_ref = session.query(models.User).filter_by(uid=id).first()
- utils.set_hashed_password(values)
- user_ref.update(values)
- user_ref.save(session=session)
-
- def delete(self, id, session=None):
- if not session:
- session = get_session()
-
- with session.begin():
- user_ref = session.query(models.User).filter_by(uid=id).first()
- session.delete(user_ref)
-
- def get_by_tenant(self, id, tenant_id, session=None):
- if not session:
- session = get_session()
-
- uid = id
-
- if hasattr(api.USER, 'uid_to_id'):
- id = api.USER.uid_to_id(uid)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- # Most common use case: user lives in tenant
- user = session.query(models.User).\
- filter_by(id=id, tenant_id=tenant_id).first()
- if user:
- return UserAPI.to_model(user)
-
- # Find user through grants to this tenant
- result = session.query(models.UserRoleAssociation).\
- filter_by(tenant_id=tenant_id, user_id=id).first()
- if result:
- return self.get(uid, session)
- else:
- return None
-
- def users_get_by_tenant(self, user_id, tenant_id, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.USER, 'uid_to_id'):
- user_id = api.USER.uid_to_id(user_id)
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- results = session.query(models.User).filter_by(id=user_id,
- tenant_id=tenant_id)
- return UserAPI.to_model_list(results)
-
- def user_role_add(self, values):
- if hasattr(api.USER, 'uid_to_id'):
- values['user_id'] = api.USER.uid_to_id(values['user_id'])
- if hasattr(api.TENANT, 'uid_to_id'):
- values['tenant_id'] = api.TENANT.uid_to_id(values['tenant_id'])
-
- user_rolegrant = models.UserRoleAssociation()
- user_rolegrant.update(values)
- user_rolegrant.save()
-
- if hasattr(api.USER, 'id_to_uid'):
- user_rolegrant.user_id = api.USER.id_to_uid(user_rolegrant.user_id)
- if hasattr(api.TENANT, 'id_to_uid'):
- user_rolegrant.tenant_id = api.TENANT.id_to_uid(
- user_rolegrant.tenant_id)
-
- return user_rolegrant
-
- def users_get_page(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- user = aliased(models.User)
- if marker:
- results = session.query(user).\
- filter("id>=:marker").params(
- marker='%s' % marker).order_by(
- "id").limit(int(limit)).all()
- else:
- results = session.query(user).\
- order_by("id").limit(int(limit)).all()
-
- return UserAPI.to_model_list(results)
-
- # pylint: disable=R0912
- def users_get_page_markers(self, marker, limit, session=None):
- if not session:
- session = get_session()
-
- user = aliased(models.User)
- first = session.query(user).\
- order_by(user.id).first()
- last = session.query(user).\
- order_by(user.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = session.query(user).\
- filter("id > :marker").params(
- marker='%s' % marker).order_by(user.id).\
- limit(int(limit)).all()
- prev_page = session.query(user).\
- filter("id < :marker").params(
- marker='%s' % marker).order_by(
- user.id.desc()).limit(int(limit)).all()
- next_len = len(next_page)
- prev_len = len(prev_page)
-
- if next_len == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if prev_len == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if first.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if marker == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def users_get_by_tenant_get_page(self, tenant_id, role_id, marker, limit,
- session=None):
- # This is broken. If a user has more than one role per project
- # shit hits the fan because we're limiting the wrong model.
- # Also the user lookup is nasty and potentially injectiable.
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- user = aliased(models.UserRoleAssociation)
- query = session.query(user).\
- filter("tenant_id = :tenant_id").\
- params(tenant_id='%s' % tenant_id)
-
- if role_id:
- query = query.filter(
- user.role_id == role_id)
-
- if marker:
- rv = query.filter("id>=:marker").\
- params(marker='%s' % marker).\
- order_by("id").\
- limit(int(limit)).\
- all()
- else:
- rv = query.\
- order_by("id").\
- limit(int(limit)).\
- all()
-
- user_ids = set([str(assoc.user_id) for assoc in rv])
- users = session.query(models.User).\
- filter("id in ('%s')" % "','".join(user_ids)).\
- all()
-
- for usr in users:
- usr.tenant_roles = set()
- for role in usr.roles:
- if role.tenant_id == tenant_id:
- usr.tenant_roles.add(role.role_id)
-
- return UserAPI.to_model_list(users)
-
- # pylint: disable=R0912
- def users_get_by_tenant_get_page_markers(self, tenant_id, \
- role_id, marker, limit, session=None):
- if not session:
- session = get_session()
-
- if hasattr(api.TENANT, 'uid_to_id'):
- tenant_id = api.TENANT.uid_to_id(tenant_id)
-
- user = aliased(models.UserRoleAssociation)
- query = session.query(user).\
- filter(user.tenant_id == tenant_id)
- if role_id:
- query = query.filter(
- user.role_id == role_id)
- first = query.\
- order_by(user.id).first()
- last = query.\
- order_by(user.id.desc()).first()
- if first is None:
- return (None, None)
- if marker is None:
- marker = first.id
- next_page = query.\
- filter("id > :marker").params(
- marker='%s' % marker).order_by(user.id).\
- limit(int(limit)).all()
- prev_page = query.\
- filter("id < :marker").params(
- marker='%s' % marker).order_by(
- user.id.desc()).limit(int(limit)).all()
- next_len = len(next_page)
- prev_len = len(prev_page)
-
- if next_len == 0:
- next_page = last
- else:
- for t in next_page:
- next_page = t
- if prev_len == 0:
- prev_page = first
- else:
- for t in prev_page:
- prev_page = t
- if first.id == marker:
- prev_page = None
- else:
- prev_page = prev_page.id
- if marker == last.id:
- next_page = None
- else:
- next_page = next_page.id
- return (prev_page, next_page)
-
- def check_password(self, user_id, password):
- user = self.get(user_id)
- return utils.check_password(password, user.password)
- # pylint: enable=W0221
-
-
-def get():
- return UserAPI()
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/001_initial_migration.py b/keystone/backends/sqlalchemy/migrate_repo/versions/001_initial_migration.py
deleted file mode 100644
index 45b69685..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/001_initial_migration.py
+++ /dev/null
@@ -1,196 +0,0 @@
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-
-
-meta = sqlalchemy.MetaData()
-
-
-# services
-
-service = {}
-service['id'] = sqlalchemy.Column('id', sqlalchemy.Integer,
- primary_key=True, autoincrement=True)
-service['name'] = sqlalchemy.Column('name', sqlalchemy.String(255),
- unique=True)
-service['type'] = sqlalchemy.Column('type', sqlalchemy.String(255))
-service['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-services = sqlalchemy.Table('services', meta, *service.values())
-
-sqlalchemy.UniqueConstraint(service['name'])
-
-
-# roles
-
-role = {}
-role['id'] = sqlalchemy.Column('id', sqlalchemy.Integer,
- primary_key=True, autoincrement=True)
-role['name'] = sqlalchemy.Column('name', sqlalchemy.String(255))
-role['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-role['service_id'] = sqlalchemy.Column('service_id', sqlalchemy.Integer)
-roles = sqlalchemy.Table('roles', meta, *role.values())
-
-sqlalchemy.UniqueConstraint(role['name'], role['service_id'])
-
-sqlalchemy.ForeignKeyConstraint(
- [role['service_id']],
- [service['id']])
-
-
-# tenants
-
-tenant = {}
-tenant['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-tenant['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-tenant['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-tenant['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-tenants = sqlalchemy.Table('tenants', meta, *tenant.values())
-
-sqlalchemy.UniqueConstraint(tenant['name'])
-
-
-# users
-
-user = {}
-user['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-user['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-user['password'] = sqlalchemy.Column('password', sqlalchemy.String(255))
-user['email'] = sqlalchemy.Column('email', sqlalchemy.String(255))
-user['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-user['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-users = sqlalchemy.Table('users', meta, *user.values())
-
-sqlalchemy.UniqueConstraint(user['name'])
-
-sqlalchemy.ForeignKeyConstraint(
- [user['tenant_id']],
- [tenant['id']])
-
-
-# credentials
-
-credential = {}
-credential['id'] = sqlalchemy.Column('id', sqlalchemy.Integer,
- primary_key=True, autoincrement=True)
-credential['user_id'] = sqlalchemy.Column('user_id', sqlalchemy.Integer)
-credential['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer,
- nullable=True)
-credential['type'] = sqlalchemy.Column('type', sqlalchemy.String(20))
-credential['key'] = sqlalchemy.Column('key', sqlalchemy.String(255))
-credential['secret'] = sqlalchemy.Column('secret', sqlalchemy.String(255))
-credentials = sqlalchemy.Table('credentials', meta, *credential.values())
-
-sqlalchemy.ForeignKeyConstraint(
- [credential['user_id']],
- [user['id']])
-sqlalchemy.ForeignKeyConstraint(
- [credential['tenant_id']],
- [tenant['id']])
-
-
-# tokens
-
-token = {}
-token['id'] = sqlalchemy.Column('id', sqlalchemy.String(255), primary_key=True,
- unique=True)
-token['user_id'] = sqlalchemy.Column('user_id', sqlalchemy.Integer)
-token['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-token['expires'] = sqlalchemy.Column('expires', sqlalchemy.DateTime)
-tokens = sqlalchemy.Table('token', meta, *token.values())
-
-
-# endpoint_templates
-
-endpoint_template = {}
-endpoint_template['id'] = sqlalchemy.Column('id', sqlalchemy.Integer,
- primary_key=True)
-endpoint_template['region'] = sqlalchemy.Column('region',
- sqlalchemy.String(255))
-endpoint_template['service_id'] = sqlalchemy.Column('service_id',
- sqlalchemy.Integer)
-endpoint_template['public_url'] = sqlalchemy.Column('public_url',
- sqlalchemy.String(2000))
-endpoint_template['admin_url'] = sqlalchemy.Column('admin_url',
- sqlalchemy.String(2000))
-endpoint_template['internal_url'] = sqlalchemy.Column('internal_url',
- sqlalchemy.String(2000))
-endpoint_template['enabled'] = sqlalchemy.Column('enabled',
- sqlalchemy.Boolean)
-endpoint_template['is_global'] = sqlalchemy.Column('is_global',
- sqlalchemy.Boolean)
-endpoint_templates = sqlalchemy.Table('endpoint_templates', meta,
- *endpoint_template.values())
-
-sqlalchemy.ForeignKeyConstraint(
- [endpoint_template['service_id']], [service['id']])
-
-
-# endpoints
-
-endpoint = {}
-endpoint['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True)
-endpoint['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-endpoint['endpoint_template_id'] = sqlalchemy.Column('endpoint_template_id',
- sqlalchemy.Integer)
-endpoints = sqlalchemy.Table('endpoints', meta, *endpoint.values())
-
-sqlalchemy.UniqueConstraint(
- endpoint['endpoint_template_id'], endpoint['tenant_id'])
-
-sqlalchemy.ForeignKeyConstraint(
- [endpoint['endpoint_template_id']],
- [endpoint_template['id']])
-
-
-# user_roles
-
-user_role = {}
-user_role['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True)
-user_role['user_id'] = sqlalchemy.Column('user_id', sqlalchemy.Integer)
-user_role['role_id'] = sqlalchemy.Column('role_id', sqlalchemy.Integer)
-user_role['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-user_roles = sqlalchemy.Table('user_roles', meta, *user_role.values())
-
-sqlalchemy.UniqueConstraint(
- user_role['user_id'], user_role['role_id'], user_role['tenant_id'])
-
-sqlalchemy.ForeignKeyConstraint(
- [user_role['user_id']],
- [user['id']])
-sqlalchemy.ForeignKeyConstraint(
- [user_role['role_id']],
- [role['id']])
-sqlalchemy.ForeignKeyConstraint(
- [user_role['tenant_id']],
- [tenant['id']])
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- user_roles.create()
- endpoints.create()
- roles.create()
- services.create()
- tenants.create()
- users.create()
- credentials.create()
- tokens.create()
- endpoint_templates.create()
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- user_roles.drop()
- endpoints.drop()
- roles.drop()
- services.drop()
- tenants.drop()
- users.drop()
- credentials.drop()
- tokens.drop()
- endpoint_templates.drop()
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/002_rename_token_table.py b/keystone/backends/sqlalchemy/migrate_repo/versions/002_rename_token_table.py
deleted file mode 100644
index e350b2a4..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/002_rename_token_table.py
+++ /dev/null
@@ -1,26 +0,0 @@
-"""
-Addresses bug 854425
-
-Renames the 'token' table to 'tokens',
-in order to appear more consistent with
-other table names.
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-
-
-meta = sqlalchemy.MetaData()
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
- # pylint: disable=E1101
- sqlalchemy.Table('token', meta).rename('tokens')
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
- # pylint: disable=E1101
- sqlalchemy.Table('tokens', meta).rename('token')
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/003_add_endpoint_template_versions.py b/keystone/backends/sqlalchemy/migrate_repo/versions/003_add_endpoint_template_versions.py
deleted file mode 100644
index be5bde24..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/003_add_endpoint_template_versions.py
+++ /dev/null
@@ -1,64 +0,0 @@
-"""
-Adds support for versioning endpoint templates
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-import migrate
-
-
-meta = sqlalchemy.MetaData()
-
-endpoint_template = {}
-endpoint_template['id'] = sqlalchemy.Column('id', sqlalchemy.Integer,
- primary_key=True)
-endpoint_template['region'] = sqlalchemy.Column('region',
- sqlalchemy.String(255))
-endpoint_template['service_id'] = sqlalchemy.Column('service_id',
- sqlalchemy.Integer)
-endpoint_template['public_url'] = sqlalchemy.Column('public_url',
- sqlalchemy.String(2000))
-endpoint_template['admin_url'] = sqlalchemy.Column('admin_url',
- sqlalchemy.String(2000))
-endpoint_template['internal_url'] = sqlalchemy.Column('internal_url',
- sqlalchemy.String(2000))
-endpoint_template['enabled'] = sqlalchemy.Column('enabled',
- sqlalchemy.Boolean)
-endpoint_template['is_global'] = sqlalchemy.Column('is_global',
- sqlalchemy.Boolean)
-endpoint_templates = sqlalchemy.Table('endpoint_templates', meta,
- *endpoint_template.values())
-
-version_id = sqlalchemy.Column('version_id', sqlalchemy.String(20),
- nullable=True)
-version_list = sqlalchemy.Column('version_list', sqlalchemy.String(2000),
- nullable=True)
-version_info = sqlalchemy.Column('version_info', sqlalchemy.String(500),
- nullable=True)
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.create_column(version_id, endpoint_templates)
- assert endpoint_templates.c.version_id is version_id
-
- migrate.create_column(version_list, endpoint_templates)
- assert endpoint_templates.c.version_list is version_list
-
- migrate.create_column(version_info, endpoint_templates)
- assert endpoint_templates.c.version_info is version_info
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.drop_column(version_id, endpoint_templates)
- assert not hasattr(endpoint_templates.c, 'version_id')
-
- migrate.drop_column(version_list, endpoint_templates)
- assert not hasattr(endpoint_templates.c, 'version_list')
-
- migrate.drop_column(version_info, endpoint_templates)
- assert not hasattr(endpoint_templates.c, 'version_info')
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/004_add_service_owner.py b/keystone/backends/sqlalchemy/migrate_repo/versions/004_add_service_owner.py
deleted file mode 100644
index 4bf02c8e..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/004_add_service_owner.py
+++ /dev/null
@@ -1,39 +0,0 @@
-"""
-Adds support for owner id in services
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-import migrate
-
-
-meta = sqlalchemy.MetaData()
-
-service = {}
-service['id'] = sqlalchemy.Column('id', sqlalchemy.Integer,
- primary_key=True, autoincrement=True)
-service['name'] = sqlalchemy.Column('name', sqlalchemy.String(255),
- unique=True)
-service['type'] = sqlalchemy.Column('type', sqlalchemy.String(255))
-service['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-services = sqlalchemy.Table('services', meta, *service.values())
-
-owner_id = sqlalchemy.Column('owner_id', sqlalchemy.Integer,
- nullable=True)
-
-sqlalchemy.UniqueConstraint(service['name'])
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.create_column(owner_id, services)
- assert services.c.owner_id is owner_id
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.drop_column(owner_id, services)
- assert not hasattr(services.c, 'owner_id')
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/005_add_tenants_uid.py b/keystone/backends/sqlalchemy/migrate_repo/versions/005_add_tenants_uid.py
deleted file mode 100644
index ab8e7305..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/005_add_tenants_uid.py
+++ /dev/null
@@ -1,38 +0,0 @@
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-import migrate
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of tenants
-
-tenant = {}
-tenant['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-tenant['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-tenant['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-tenant['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-tenants = sqlalchemy.Table('tenants', meta, *tenant.values())
-
-
-# this column will become unique/non-nullable after populating it
-tenant_uid = sqlalchemy.Column('uid', sqlalchemy.String(255),
- unique=False, nullable=True)
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.create_column(tenant_uid, tenants)
- assert tenants.c.uid is tenant_uid
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.drop_column(tenant_uid, tenants)
- assert not hasattr(tenants.c, 'uid')
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/006_populate_tenants_uid.py b/keystone/backends/sqlalchemy/migrate_repo/versions/006_populate_tenants_uid.py
deleted file mode 100644
index 8e5ea2d4..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/006_populate_tenants_uid.py
+++ /dev/null
@@ -1,40 +0,0 @@
-"""
-Data migration to populate tenants.uid with existing tenants.id values.
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of tenants
-
-tenant = {}
-tenant['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-tenant['uid'] = sqlalchemy.Column('uid', sqlalchemy.String(255), unique=False,
- nullable=True)
-tenant['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-tenant['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-tenant['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-tenants = sqlalchemy.Table('tenants', meta, *tenant.values())
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- dtenants = tenants.select().execute()
- for dtenant in dtenants:
- whereclause = "`id`='%s'" % (dtenant.id)
- values = {'uid': str(dtenant.id)}
-
- tenants.update(whereclause=whereclause, values=values).execute()
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- tenants.update(values={'uid': None}).execute()
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/007_make_tenants_uid_unique.py b/keystone/backends/sqlalchemy/migrate_repo/versions/007_make_tenants_uid_unique.py
deleted file mode 100644
index 555d3c7f..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/007_make_tenants_uid_unique.py
+++ /dev/null
@@ -1,59 +0,0 @@
-"""
-Schema migration to enforce uniqueness on tenants.uid
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-import migrate
-from migrate.changeset import constraint
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of tenants
-
-tenant = {}
-tenant['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-tenant['uid'] = sqlalchemy.Column('uid', sqlalchemy.String(255), unique=False,
- nullable=True)
-tenant['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-tenant['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-tenant['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-tenants = sqlalchemy.Table('tenants', meta, *tenant.values())
-
-
-unique_constraint = constraint.UniqueConstraint(tenant['uid'])
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- tenant['uid'].alter(nullable=False)
- assert not tenants.c.uid.nullable
-
- unique_constraint.create()
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- try:
- # this is NOT supported in sqlite!
- # but let's try anyway, in case it is
- unique_constraint.drop()
- except migrate.exceptions.NotSupportedError, e:
- if migrate_engine.name == 'sqlite':
- # skipping the constraint drop doesn't seem to cause any issues
- # *in sqlite*
- # as constraints are only checked on row insert/update,
- # and don't apply to nulls.
- print 'WARNING: Skipping dropping unique constraint ' \
- 'from `tenants`, UNIQUE (uid)'
- else:
- raise e
-
- tenant['uid'].alter(nullable=True)
- assert tenants.c.uid.nullable
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/008_add_users_uid.py b/keystone/backends/sqlalchemy/migrate_repo/versions/008_add_users_uid.py
deleted file mode 100644
index c634cae9..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/008_add_users_uid.py
+++ /dev/null
@@ -1,40 +0,0 @@
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-import migrate
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of users
-
-user = {}
-user['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-user['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-user['password'] = sqlalchemy.Column('password', sqlalchemy.String(255))
-user['email'] = sqlalchemy.Column('email', sqlalchemy.String(255))
-user['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-user['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-users = sqlalchemy.Table('users', meta, *user.values())
-
-
-# this column will become unique/non-nullable after populating it
-user_uid = sqlalchemy.Column('uid', sqlalchemy.String(255),
- unique=False, nullable=True)
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.create_column(user_uid, users)
- assert users.c.uid is user_uid
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- migrate.drop_column(user_uid, users)
- assert not hasattr(users.c, 'uid')
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/009_populate_users_uid.py b/keystone/backends/sqlalchemy/migrate_repo/versions/009_populate_users_uid.py
deleted file mode 100644
index c769eaa5..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/009_populate_users_uid.py
+++ /dev/null
@@ -1,42 +0,0 @@
-"""
-Data migration to populate users.uid with existing users.id values.
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of users
-
-user = {}
-user['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-user['uid'] = sqlalchemy.Column('uid', sqlalchemy.String(255), unique=False,
- nullable=True)
-user['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-user['password'] = sqlalchemy.Column('password', sqlalchemy.String(255))
-user['email'] = sqlalchemy.Column('email', sqlalchemy.String(255))
-user['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-user['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-users = sqlalchemy.Table('users', meta, *user.values())
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- dusers = users.select().execute()
- for duser in dusers:
- whereclause = "`id`='%s'" % (duser.id)
- values = {'uid': str(duser.id)}
-
- users.update(whereclause=whereclause, values=values).execute()
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- users.update(values={'uid': None}).execute()
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/010_make_users_uid_unique.py b/keystone/backends/sqlalchemy/migrate_repo/versions/010_make_users_uid_unique.py
deleted file mode 100644
index 164be7d4..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/010_make_users_uid_unique.py
+++ /dev/null
@@ -1,60 +0,0 @@
-"""
-Schema migration to enforce uniqueness on users.uid
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-import migrate
-from migrate.changeset import constraint
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of users
-
-user = {}
-user['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-user['uid'] = sqlalchemy.Column('uid', sqlalchemy.String(255), unique=False,
- nullable=True)
-user['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-user['password'] = sqlalchemy.Column('password', sqlalchemy.String(255))
-user['email'] = sqlalchemy.Column('email', sqlalchemy.String(255))
-user['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-user['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-users = sqlalchemy.Table('users', meta, *user.values())
-
-unique_constraint = constraint.UniqueConstraint(user['uid'])
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- user['uid'].alter(nullable=False)
- assert not users.c.uid.nullable
-
- unique_constraint.create()
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- try:
- # this is NOT supported in sqlite!
- # but let's try anyway, in case it is
- unique_constraint.drop()
- except migrate.exceptions.NotSupportedError, e:
- if migrate_engine.name == 'sqlite':
- # skipping the constraint drop doesn't seem to cause any issues
- # *in sqlite*
- # as constraints are only checked on row insert/update,
- # and don't apply to nulls.
- print 'WARNING: Skipping dropping unique constraint ' \
- 'from `users`, UNIQUE (uid)'
- else:
- raise e
-
- user['uid'].alter(nullable=True)
- assert users.c.uid.nullable
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/011_is_enabled_boolean.py b/keystone/backends/sqlalchemy/migrate_repo/versions/011_is_enabled_boolean.py
deleted file mode 100644
index 47b4a0bf..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/011_is_enabled_boolean.py
+++ /dev/null
@@ -1,58 +0,0 @@
-"""
-Change 'enabled' columns to boolean types
-"""
-# pylint: disable=C0103,R0801
-
-
-import sqlalchemy
-from migrate.changeset import constraint
-
-
-meta = sqlalchemy.MetaData()
-
-
-# define the previous state of users
-
-user = {}
-user['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-user['uid'] = sqlalchemy.Column('uid', sqlalchemy.String(255), unique=False,
- nullable=False)
-user['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-user['password'] = sqlalchemy.Column('password', sqlalchemy.String(255))
-user['email'] = sqlalchemy.Column('email', sqlalchemy.String(255))
-user['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-user['tenant_id'] = sqlalchemy.Column('tenant_id', sqlalchemy.Integer)
-users = sqlalchemy.Table('users', meta, *user.values())
-constraint.UniqueConstraint(user['uid'])
-
-tenant = {}
-tenant['id'] = sqlalchemy.Column('id', sqlalchemy.Integer, primary_key=True,
- autoincrement=True)
-tenant['uid'] = sqlalchemy.Column('uid', sqlalchemy.String(255), unique=False,
- nullable=False)
-tenant['name'] = sqlalchemy.Column('name', sqlalchemy.String(255), unique=True)
-tenant['desc'] = sqlalchemy.Column('desc', sqlalchemy.String(255))
-tenant['enabled'] = sqlalchemy.Column('enabled', sqlalchemy.Integer)
-tenants = sqlalchemy.Table('tenants', meta, *tenant.values())
-constraint.UniqueConstraint(tenant['uid'])
-
-
-def upgrade(migrate_engine):
- meta.bind = migrate_engine
-
- user['enabled'].alter(type=sqlalchemy.Boolean)
- assert users.c.enabled is user['enabled']
-
- tenant['enabled'].alter(type=sqlalchemy.Boolean)
- assert tenants.c.enabled is tenant['enabled']
-
-
-def downgrade(migrate_engine):
- meta.bind = migrate_engine
-
- user['enabled'].alter(type=sqlalchemy.Integer)
- assert users.c.enabled is user['enabled']
-
- tenant['enabled'].alter(type=sqlalchemy.Integer)
- assert tenants.c.enabled is tenant['enabled']
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_downgrade.sql b/keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_downgrade.sql
deleted file mode 100644
index 0d0bf99a..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_downgrade.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-ALTER TABLE users ALTER COLUMN enabled DROP DEFAULT;
-ALTER TABLE users ALTER COLUMN enabled TYPE integer USING CASE enabled WHEN true THEN 1 ELSE 0 END;
-
-ALTER TABLE tenants ALTER COLUMN enabled DROP DEFAULT;
-ALTER TABLE tenants ALTER COLUMN enabled TYPE integer USING CASE enabled WHEN true THEN 1 ELSE 0 END;
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_upgrade.sql b/keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_upgrade.sql
deleted file mode 100644
index f0eafb7e..00000000
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/011_postgresql_upgrade.sql
+++ /dev/null
@@ -1,5 +0,0 @@
-ALTER TABLE users ALTER COLUMN enabled DROP DEFAULT;
-ALTER TABLE users ALTER COLUMN enabled TYPE boolean USING CASE enabled WHEN '1' THEN true ELSE '0' END;
-
-ALTER TABLE tenants ALTER COLUMN enabled DROP DEFAULT;
-ALTER TABLE tenants ALTER COLUMN enabled TYPE boolean USING CASE enabled WHEN '1' THEN true ELSE '0' END;
diff --git a/keystone/backends/sqlalchemy/migration.py b/keystone/backends/sqlalchemy/migration.py
deleted file mode 100644
index 62219272..00000000
--- a/keystone/backends/sqlalchemy/migration.py
+++ /dev/null
@@ -1,172 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 logging
-import os
-
-from migrate.versioning import api as versioning_api
-# See LP bug #719834. sqlalchemy-migrate changed location of
-# exceptions.py after 0.6.0.
-try:
- # pylint: disable=E0611
- from migrate.versioning import exceptions as versioning_exceptions
-except ImportError:
- from migrate import exceptions as versioning_exceptions
-
-from keystone.logic.types import fault
-
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-def get_migrate_repo_path():
- """Get the path for the migrate repository."""
- path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
- 'migrate_repo')
- assert os.path.exists(path)
- return path
-
-
-def get_migrate_repo(repo_path):
- return versioning_api.repository.Repository(repo_path)
-
-
-def get_schema(engine, repo_path):
- return versioning_api.schema.ControlledSchema(engine, repo_path)
-
-
-def get_repo_version(repo_path):
- return get_migrate_repo(repo_path).latest
-
-
-def get_db_version(engine, repo_path):
- return get_schema(engine, repo_path).version
-
-
-def db_goto_version(sql_connection, version):
- """
- Jump to a specific database version without performing migrations.
-
- :param sql_connection: sqlalchemy connection string
- :param version: version to jump to
- """
-
- # pylint: disable=W0613
- @versioning_api.with_engine
- def set_db_version(url, repository, old_v, new_v, **opts):
- engine = opts.pop('engine')
- schema = get_schema(engine, repo_path)
- schema.update_repository_table(old_v, new_v)
- return True
-
- repo_path = get_migrate_repo_path()
- new_version = int(version)
- try:
- old_version = versioning_api.db_version(sql_connection, repo_path)
- if new_version != old_version:
- return set_db_version(sql_connection, repo_path, old_version,
- new_version)
- except versioning_exceptions.DatabaseNotControlledError:
- msg = (_("database '%(sql_connection)s' is not under "
- "migration control") % locals())
- raise fault.DatabaseMigrationError(msg)
-
-
-def db_version(sql_connection):
- """
- Return the database's current migration number
-
- :param sql_connection: sqlalchemy connection string
- :retval version number
- """
- repo_path = get_migrate_repo_path()
- try:
- return versioning_api.db_version(sql_connection, repo_path)
- except versioning_exceptions.DatabaseNotControlledError:
- msg = (_("database '%(sql_connection)s' is not under "
- "migration control") % locals())
- raise fault.DatabaseMigrationError(msg)
-
-
-def upgrade(sql_connection, version=None):
- """
- Upgrade the database's current migration level
-
- :param sql_connection: sqlalchemy connection string
- :param version: version to upgrade (defaults to latest)
- :retval version number
- """
- db_version(sql_connection) # Ensure db is under migration control
- repo_path = get_migrate_repo_path()
- version_str = version or 'latest' # pylint: disable=W0612
- logger.info(_("Upgrading %(sql_connection)s to version %(version_str)s") %
- locals())
- return versioning_api.upgrade(sql_connection, repo_path, version)
-
-
-def downgrade(sql_connection, version):
- """
- Downgrade the database's current migration level
-
- :param sql_connection: sqlalchemy connection string
- :param version: version to downgrade to
- :retval version number
- """
- db_version(sql_connection) # Ensure db is under migration control
- repo_path = get_migrate_repo_path()
- logger.info(_("Downgrading %(sql_connection)s to version %(version)s") %
- locals())
- return versioning_api.downgrade(sql_connection, repo_path, version)
-
-
-def version_control(sql_connection):
- """
- Place a database under migration control
-
- :param sql_connection: sqlalchemy connection string
- """
- try:
- _version_control(sql_connection)
- except versioning_exceptions.DatabaseAlreadyControlledError:
- msg = (_("database '%(sql_connection)s' is already under migration "
- "control") % locals())
- raise fault.DatabaseMigrationError(msg)
-
-
-def _version_control(sql_connection):
- """
- Place a database under migration control
-
- :param sql_connection: sqlalchemy connection string
- """
- repo_path = get_migrate_repo_path()
- return versioning_api.version_control(sql_connection, repo_path)
-
-
-def db_sync(sql_connection, version=None):
- """
- Place a database under migration control and perform an upgrade
-
- :param sql_connection: sqlalchemy connection string
- :retval version number
- """
- try:
- _version_control(sql_connection)
- except versioning_exceptions.DatabaseAlreadyControlledError:
- pass
-
- upgrade(sql_connection, version=version)
diff --git a/keystone/backends/sqlalchemy/models.py b/keystone/backends/sqlalchemy/models.py
deleted file mode 100755
index 7efe059c..00000000
--- a/keystone/backends/sqlalchemy/models.py
+++ /dev/null
@@ -1,187 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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.
-
-from sqlalchemy import Column, String, Integer, ForeignKey, \
- UniqueConstraint, Boolean, DateTime
-from sqlalchemy.exc import IntegrityError
-from sqlalchemy.ext.declarative import declarative_base
-from sqlalchemy.orm import relationship, object_mapper
-
-# pylint: disable=C0103
-Base = declarative_base()
-
-
-class KeystoneBase(object):
- """Base class for Keystone Models."""
- __api__ = None
- # pylint: disable=C0103
- _i = None
-
- def save(self, session=None):
- """Save this object."""
-
- if not session:
- from keystone.backends.sqlalchemy import get_session
- session = get_session()
- session.add(self)
- try:
- session.flush()
- except IntegrityError:
- raise
-
- def delete(self, session=None):
- """Delete this object."""
- self.save(session=session)
-
- def __setitem__(self, key, value):
- setattr(self, key, value)
-
- def __getitem__(self, key):
- return getattr(self, key)
-
- def get(self, key, default=None):
- return getattr(self, key, default)
-
- def __iter__(self):
- self._i = iter(object_mapper(self).columns)
- return self
-
- def next(self):
- n = self._i.next().name
- return n, getattr(self, n)
-
- def update(self, values):
- """Make the model object behave like a dict"""
- for k, v in values.iteritems():
- setattr(self, k, v)
-
- def iteritems(self):
- """Make the model object behave like a dict.
-
- Includes attributes from joins."""
- local = dict(self)
- joined = dict([(k, v) for k, v in self.__dict__.iteritems()
- if not k[0] == '_'])
- local.update(joined)
- return local.iteritems()
-
- def copy(self):
- """Make the model object behave like a dict."""
- return dict(self).copy()
-
-
-# Define associations first
-class UserRoleAssociation(Base, KeystoneBase):
- __tablename__ = 'user_roles'
- id = Column(Integer, primary_key=True)
- user_id = Column(Integer, ForeignKey('users.id'))
- role_id = Column(Integer, ForeignKey('roles.id'))
- tenant_id = Column(Integer, ForeignKey('tenants.id'))
- __table_args__ = (UniqueConstraint("user_id", "role_id", "tenant_id"), {})
-
- user = relationship('User')
- role = relationship('Role')
-
-
-class Endpoints(Base, KeystoneBase):
- __tablename__ = 'endpoints'
- id = Column(Integer, primary_key=True)
- tenant_id = Column(Integer)
- endpoint_template_id = Column(Integer, ForeignKey('endpoint_templates.id'))
- __table_args__ = (
- UniqueConstraint("endpoint_template_id", "tenant_id"), {})
-
-
-# Define objects
-class Role(Base, KeystoneBase):
- __tablename__ = 'roles'
- __api__ = 'role'
- id = Column(Integer, primary_key=True, autoincrement=True)
- name = Column(String(255))
- desc = Column(String(255))
- service_id = Column(Integer, ForeignKey('services.id'))
- __table_args__ = (
- UniqueConstraint("name", "service_id"), {})
-
-
-class Service(Base, KeystoneBase):
- __tablename__ = 'services'
- __api__ = 'service'
- id = Column(Integer, primary_key=True, autoincrement=True)
- name = Column(String(255), unique=True)
- type = Column(String(255))
- desc = Column(String(255))
- owner_id = Column(Integer, ForeignKey('users.id'))
-
-
-class Tenant(Base, KeystoneBase):
- __tablename__ = 'tenants'
- __api__ = 'tenant'
- id = Column(Integer, primary_key=True, autoincrement=True)
- uid = Column(String(255), unique=True, nullable=False)
- name = Column(String(255), unique=True)
- desc = Column(String(255))
- enabled = Column(Boolean)
-
-
-class User(Base, KeystoneBase):
- __tablename__ = 'users'
- __api__ = 'user'
- id = Column(Integer, primary_key=True, autoincrement=True)
- uid = Column(String(255), unique=True, nullable=False)
- name = Column(String(255), unique=True)
- password = Column(String(255))
- email = Column(String(255))
- enabled = Column(Boolean)
- tenant_id = Column(Integer, ForeignKey('tenants.id'))
- roles = relationship(UserRoleAssociation, cascade="all")
- credentials = relationship('Credentials', backref='user', cascade="all")
-
-
-class Credentials(Base, KeystoneBase):
- __tablename__ = 'credentials'
- __api__ = 'credentials'
- id = Column(Integer, primary_key=True, autoincrement=True)
- user_id = Column(Integer, ForeignKey('users.id'))
- tenant_id = Column(Integer, ForeignKey('tenants.id'), nullable=True)
- type = Column(String(20)) # ('Password','APIKey','EC2')
- key = Column(String(255))
- secret = Column(String(255))
-
-
-class Token(Base, KeystoneBase):
- __tablename__ = 'tokens'
- __api__ = 'token'
- id = Column(String(255), primary_key=True, unique=True)
- user_id = Column(Integer)
- tenant_id = Column(Integer)
- expires = Column(DateTime)
-
-
-class EndpointTemplates(Base, KeystoneBase):
- __tablename__ = 'endpoint_templates'
- __api__ = 'endpoint_template'
- id = Column(Integer, primary_key=True)
- region = Column(String(255))
- service_id = Column(Integer, ForeignKey('services.id'))
- public_url = Column(String(2000))
- admin_url = Column(String(2000))
- internal_url = Column(String(2000))
- enabled = Column(Boolean)
- is_global = Column(Boolean)
- version_id = Column(String(20))
- version_list = Column(String(2000))
- version_info = Column(String(500))
diff --git a/keystone/catalog/__init__.py b/keystone/catalog/__init__.py
new file mode 100644
index 00000000..95af1256
--- /dev/null
+++ b/keystone/catalog/__init__.py
@@ -0,0 +1 @@
+from keystone.catalog.core import *
diff --git a/keystone/backends/sqlalchemy/api/__init__.py b/keystone/catalog/backends/__init__.py
index e69de29b..e69de29b 100755..100644
--- a/keystone/backends/sqlalchemy/api/__init__.py
+++ b/keystone/catalog/backends/__init__.py
diff --git a/keystone/catalog/backends/kvs.py b/keystone/catalog/backends/kvs.py
new file mode 100644
index 00000000..8ee781ba
--- /dev/null
+++ b/keystone/catalog/backends/kvs.py
@@ -0,0 +1,39 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+
+from keystone.common import kvs
+
+
+class Catalog(kvs.Base):
+ # Public interface
+ def get_catalog(self, user_id, tenant_id, metadata=None):
+ return self.db.get('catalog-%s-%s' % (tenant_id, user_id))
+
+ def get_service(self, service_id):
+ return self.db.get('service-%s' % service_id)
+
+ def list_services(self):
+ return self.db.get('service_list', [])
+
+ def create_service(self, service_id, service):
+ self.db.set('service-%s' % service_id, service)
+ service_list = set(self.db.get('service_list', []))
+ service_list.add(service_id)
+ self.db.set('service_list', list(service_list))
+ return service
+
+ def update_service(self, service_id, service):
+ self.db.set('service-%s' % service_id, service)
+ return service
+
+ def delete_service(self, service_id):
+ self.db.delete('service-%s' % service_id)
+ service_list = set(self.db.get('service_list', []))
+ service_list.remove(service_id)
+ self.db.set('service_list', list(service_list))
+ return None
+
+ # Private interface
+ def _create_catalog(self, user_id, tenant_id, data):
+ self.db.set('catalog-%s-%s' % (tenant_id, user_id), data)
+ return data
diff --git a/keystone/catalog/backends/templated.py b/keystone/catalog/backends/templated.py
new file mode 100644
index 00000000..b6e7036f
--- /dev/null
+++ b/keystone/catalog/backends/templated.py
@@ -0,0 +1,95 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from keystone import config
+from keystone.common import logging
+from keystone.catalog.backends import kvs
+
+
+CONF = config.CONF
+config.register_str('template_file', group='catalog')
+
+
+def parse_templates(template_lines):
+ o = {}
+ for line in template_lines:
+ if ' = ' not in line:
+ continue
+
+ k, v = line.strip().split(' = ')
+ if not k.startswith('catalog.'):
+ continue
+
+ parts = k.split('.')
+
+ region = parts[1]
+ # NOTE(termie): object-store insists on having a dash
+ service = parts[2].replace('_', '-')
+ key = parts[3]
+
+ region_ref = o.get(region, {})
+ service_ref = region_ref.get(service, {})
+ service_ref[key] = v
+
+ region_ref[service] = service_ref
+ o[region] = region_ref
+
+ return o
+
+
+class TemplatedCatalog(kvs.Catalog):
+ """A backend that generates endpoints for the Catalog based on templates.
+
+ It is usually configured via config entries that look like:
+
+ catalog.$REGION.$SERVICE.$key = $value
+
+ and is stored in a similar looking hierarchy. Where a value can contain
+ values to be interpolated by standard python string interpolation that look
+ like (the % is replaced by a $ due to paste attmepting to interpolate on
+ its own:
+
+ http://localhost:$(public_port)s/
+
+ When expanding the template it will pass in a dict made up of the conf
+ instance plus a few additional key-values, notably tenant_id and user_id.
+
+ It does not care what the keys and values are but it is worth noting that
+ keystone_compat will expect certain keys to be there so that it can munge
+ them into the output format keystone expects. These keys are:
+
+ name - the name of the service, most likely repeated for all services of
+ the same type, across regions.
+
+ adminURL - the url of the admin endpoint
+
+ publicURL - the url of the public endpoint
+
+ internalURL - the url of the internal endpoint
+
+ """
+
+ def __init__(self, templates=None):
+ if templates:
+ self.templates = templates
+ else:
+ self._load_templates(CONF.catalog.template_file)
+ super(TemplatedCatalog, self).__init__()
+
+ def _load_templates(self, template_file):
+ self.templates = parse_templates(open(template_file))
+
+ def get_catalog(self, user_id, tenant_id, metadata=None):
+ d = dict(CONF.iteritems())
+ d.update({'tenant_id': tenant_id,
+ 'user_id': user_id})
+
+ o = {}
+ for region, region_ref in self.templates.iteritems():
+ o[region] = {}
+ for service, service_ref in region_ref.iteritems():
+ o[region][service] = {}
+ for k, v in service_ref.iteritems():
+ v = v.replace('$(', '%(')
+ o[region][service][k] = v % d
+
+ return o
diff --git a/keystone/catalog/core.py b/keystone/catalog/core.py
new file mode 100644
index 00000000..93c0de20
--- /dev/null
+++ b/keystone/catalog/core.py
@@ -0,0 +1,57 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Main entry point into the Catalog service."""
+
+import uuid
+
+import webob.exc
+
+from keystone import config
+from keystone.common import manager
+from keystone.common import wsgi
+
+
+CONF = config.CONF
+
+
+class Manager(manager.Manager):
+ """Default pivot point for the Catalog backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.catalog.driver)
+
+
+class ServiceController(wsgi.Application):
+ def __init__(self):
+ self.catalog_api = Manager()
+ super(ServiceController, self).__init__()
+
+ # CRUD extensions
+ # NOTE(termie): this OS-KSADM stuff is not very consistent
+ def get_services(self, context):
+ service_list = self.catalog_api.list_services(context)
+ service_refs = [self.catalog_api.get_service(context, x)
+ for x in service_list]
+ return {'OS-KSADM:services': service_refs}
+
+ def get_service(self, context, service_id):
+ service_ref = self.catalog_api.get_service(context, service_id)
+ if not service_ref:
+ raise webob.exc.HTTPNotFound()
+ return {'OS-KSADM:service': service_ref}
+
+ def delete_service(self, context, service_id):
+ service_ref = self.catalog_api.delete_service(context, service_id)
+
+ def create_service(self, context, OS_KSADM_service):
+ service_id = uuid.uuid4().hex
+ service_ref = OS_KSADM_service.copy()
+ service_ref['id'] = service_id
+ new_service_ref = self.catalog_api.create_service(
+ context, service_id, service_ref)
+ return {'OS-KSADM:service': new_service_ref}
diff --git a/keystone/cli.py b/keystone/cli.py
new file mode 100644
index 00000000..b6b5abb8
--- /dev/null
+++ b/keystone/cli.py
@@ -0,0 +1,129 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from __future__ import absolute_import
+
+import json
+import logging
+import sys
+import StringIO
+import textwrap
+
+import cli.app
+import cli.log
+
+from keystone import config
+from keystone.common import utils
+
+
+CONF = config.CONF
+CONF.set_usage('%prog COMMAND [key1=value1 key2=value2 ...]')
+
+
+class BaseApp(cli.log.LoggingApp):
+ def __init__(self, *args, **kw):
+ kw.setdefault('name', self.__class__.__name__.lower())
+ super(BaseApp, self).__init__(*args, **kw)
+
+ def add_default_params(self):
+ for args, kw in DEFAULT_PARAMS:
+ self.add_param(*args, **kw)
+
+ def _parse_keyvalues(self, args):
+ kv = {}
+ for x in args:
+ key, value = x.split('=', 1)
+ # make lists if there are multiple values
+ if key.endswith('[]'):
+ key = key[:-2]
+ existing = kv.get(key, [])
+ existing.append(value)
+ kv[key] = existing
+ else:
+ kv[key] = value
+ return kv
+
+
+class DbSync(BaseApp):
+ """Sync the database."""
+
+ name = 'db_sync'
+
+ def __init__(self, *args, **kw):
+ super(DbSync, self).__init__(*args, **kw)
+
+ def main(self):
+ for k in ['identity', 'catalog', 'policy', 'token']:
+ driver = utils.import_object(getattr(CONF, k).driver)
+ if hasattr(driver, 'db_sync'):
+ driver.db_sync()
+
+
+class ImportLegacy(BaseApp):
+ """Import a legacy database."""
+
+ name = 'import_legacy'
+
+ def __init__(self, *args, **kw):
+ super(ImportLegacy, self).__init__(*args, **kw)
+ self.add_param('old_db', nargs=1)
+
+ def main(self):
+ from keystone.common.sql import legacy
+ old_db = self.params.old_db[0]
+ migration = legacy.LegacyMigration(old_db)
+ migration.migrate_all()
+
+
+class ExportLegacyCatalog(BaseApp):
+ """Export the service catalog from a legacy database."""
+
+ name = 'export_legacy_catalog'
+
+ def __init__(self, *args, **kw):
+ super(ExportLegacyCatalog, self).__init__(*args, **kw)
+ self.add_param('old_db', nargs=1)
+
+ def main(self):
+ from keystone.common.sql import legacy
+ old_db = self.params.old_db[0]
+ migration = legacy.LegacyMigration(old_db)
+ print '\n'.join(migration.dump_catalog())
+
+
+CMDS = {'db_sync': DbSync,
+ 'import_legacy': ImportLegacy,
+ 'export_legacy_catalog': ExportLegacyCatalog,
+ }
+
+
+def print_commands(cmds):
+ print
+ print 'Available commands:'
+ o = []
+ max_length = max([len(k) for k in cmds]) + 2
+ for k, cmd in sorted(cmds.iteritems()):
+ initial_indent = '%s%s: ' % (' ' * (max_length - len(k)), k)
+ tw = textwrap.TextWrapper(initial_indent=initial_indent,
+ subsequent_indent=' ' * (max_length + 2),
+ width=80)
+ o.extend(tw.wrap(
+ (cmd.__doc__ and cmd.__doc__ or 'no docs').strip().split('\n')[0]))
+ print '\n'.join(o)
+
+
+def run(cmd, args):
+ return CMDS[cmd](argv=args).run()
+
+
+def main(argv=None, config_files=None):
+ CONF.reset()
+ args = CONF(config_files=config_files, args=argv)
+
+ if len(args) < 2:
+ CONF.print_help()
+ print_commands(CMDS)
+ sys.exit(1)
+
+ cmd = args[1]
+ if cmd in CMDS:
+ return run(cmd, (args[:1] + args[2:]))
diff --git a/keystone/client.py b/keystone/client.py
deleted file mode 100644
index 2e4a075d..00000000
--- a/keystone/client.py
+++ /dev/null
@@ -1,193 +0,0 @@
-# Copyright (C) 2011 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.
-
-"""Python HTTP clients for accessing Keystone's Service and Admin APIs."""
-
-import httplib
-import json
-import logging
-
-import keystone.common.exception
-
-LOG = logging.getLogger(__name__)
-
-
-class ServiceClient(object):
- """Keystone v2.0 HTTP API client for normal service function.
-
- Provides functionality for retrieving new tokens and for retrieving
- a list of tenants which the supplied token has access to.
-
- """
-
- _default_port = 5000
-
- def __init__(self, host, port=None, is_ssl=False, cert_file=None):
- """Initialize client.
-
- :param host: The hostname or IP of the Keystone service to use
- :param port: The port of the Keystone service to use
-
- """
- self.host = host
- self.port = port or self._default_port
- self.is_ssl = is_ssl
- self.cert_file = cert_file
-
- def _http_request(self, verb, path, body=None, headers=None):
- """Perform an HTTP request and return the HTTP response.
-
- :param verb: HTTP verb (e.g. GET, POST, etc.)
- :param path: HTTP path (e.g. /v2.0/tokens)
- :param body: HTTP Body content
- :param headers: Dictionary of HTTP headers
- :returns: httplib.HTTPResponse object
-
- """
- LOG.debug("Connecting to %s" % self.auth_address)
- if (self.is_ssl):
- connection = httplib.HTTPSConnection(self.auth_address,
- cert_file=self.cert_file)
- else:
- connection = httplib.HTTPConnection(self.auth_address)
- connection.request(verb, path, body=body, headers=headers)
- response = connection.getresponse()
- response.body = response.read()
- status_int = int(response.status)
- connection.close()
-
- if status_int < 200 or status_int >= 300:
- msg = "Client received HTTP %d" % status_int
- raise keystone.common.exception.ClientError(msg)
-
- return response
-
- @property
- def auth_address(self):
- """Return a host:port combination string."""
- return "%s:%d" % (self.host, self.port)
-
- def get_token(self, username, password):
- """Retrieve a token from Keystone for a given user/password.
-
- :param username: The user name to authenticate with
- :param password: The password to authenticate with
- :returns: A string token
-
- """
- body = json.dumps({
- "auth": {
- "passwordCredentials": {
- "username": username,
- "password": password,
- },
- },
- })
-
- headers = {
- "Accept": "application/json",
- "Content-Type": "application/json",
- }
-
- response = self._http_request("POST", "/v2.0/tokens", body, headers)
- token_id = json.loads(response.body)["access"]["token"]["id"]
-
- return token_id
-
-
-class AdminClient(ServiceClient):
- """Keystone v2.0 HTTP API client for administrative functions.
-
- Provides functionality for retrieving new tokens, validating existing
- tokens, and retrieving user information from valid tokens.
-
- """
-
- _default_port = 35357
- _default_admin_name = "admin"
- _default_admin_pass = "password"
-
- # pylint: disable=R0913
- def __init__(self, host, port=None, is_ssl=False, cert_file=None,
- admin_name=None, admin_pass=None):
- """Initialize client.
-
- :param host: The hostname or IP of the Keystone service to use
- :param port: The port of the Keystone service to use
- :param admin_name: The username to use for admin purposes
- :param admin_pass: The password to use for the admin account
-
- """
- super(AdminClient, self).__init__(host, port=port, is_ssl=is_ssl,
- cert_file=cert_file)
- self.admin_name = admin_name or self._default_admin_name
- self.admin_pass = admin_pass or self._default_admin_pass
- self._admin_token = None
-
- @property
- def admin_token(self):
- """Retrieve a valid admin token.
-
- If a token has already been retrieved, ensure that it is still valid
- and then return it. If it has not already been retrieved or the token
- is found to be invalid, retrieve a new token and return it.
-
- """
- token = self._admin_token
-
- if token is None or not self.check_token(token, token):
- token = self.get_token(self.admin_name, self.admin_pass)
-
- self._admin_token = token
- return self._admin_token
-
- def validate_token(self, token):
- """Validate a token, returning details about the user.
-
- :param token: A token string
- :returns: Object representing the user the token belongs to, or None
- if the token is not valid.
-
- """
- url = "/v2.0/tokens/%s" % token
-
- headers = {
- "Accept": "application/json",
- "X-Auth-Token": self.admin_token,
- }
-
- try:
- response = self._http_request("GET", url, headers=headers)
- except keystone.common.exception.ClientError:
- return None
-
- return json.loads(response.body)
-
- def check_token(self, token, admin_token=None):
- """Check to see if given token is valid.
-
- :param token: A token string
- :param admin_token: The administrative token to use
- :returns: True if token is valid, otherwise False
-
- """
- url = "/v2.0/tokens/%s" % token
- headers = {"X-Auth-Token": admin_token or self.admin_token}
-
- try:
- self._http_request("HEAD", url, headers=headers)
- except keystone.common.exception.ClientError:
- return False
-
- return True
diff --git a/keystone/common/bufferedhttp.py b/keystone/common/bufferedhttp.py
index db64175d..95caa4f4 100644
--- a/keystone/common/bufferedhttp.py
+++ b/keystone/common/bufferedhttp.py
@@ -1,3 +1,5 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
# Copyright (c) 2010-2011 OpenStack, LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -30,20 +32,13 @@ from urllib import quote
import logging
import time
-# pylint: disable=E0611
from eventlet.green.httplib import CONTINUE, HTTPConnection, HTTPMessage, \
HTTPResponse, HTTPSConnection, _UNKNOWN
-DEFAULT_TIMEOUT = 30
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-# pylint: disable=R0902
class BufferedHTTPResponse(HTTPResponse):
"""HTTPResponse class that buffers reading of headers"""
- # pylint: disable=C0103
def __init__(self, sock, debuglevel=0, strict=0,
method=None): # pragma: no cover
self.sock = sock
@@ -64,7 +59,6 @@ class BufferedHTTPResponse(HTTPResponse):
self.length = _UNKNOWN # number of bytes left in response
self.will_close = _UNKNOWN # conn will close at end of response
- # pylint: disable=E1101,E0203,W0201
def expect_response(self):
self.fp = self.sock.makefile('rb', 0)
version, status, reason = self._read_status()
@@ -79,24 +73,20 @@ class BufferedHTTPResponse(HTTPResponse):
self.msg.fp = None
-# pylint: disable=W0232
class BufferedHTTPConnection(HTTPConnection):
"""HTTPConnection class that uses BufferedHTTPResponse"""
response_class = BufferedHTTPResponse
- # pylint: disable=W0201
def connect(self):
self._connected_time = time.time()
return HTTPConnection.connect(self)
- # pylint: disable=W0201
def putrequest(self, method, url, skip_host=0, skip_accept_encoding=0):
self._method = method
self._path = url
return HTTPConnection.putrequest(self, method, url, skip_host,
skip_accept_encoding)
- # pylint: disable=E1101
def getexpect(self):
response = BufferedHTTPResponse(self.sock, strict=self.strict,
method=self._method)
@@ -105,17 +95,15 @@ class BufferedHTTPConnection(HTTPConnection):
def getresponse(self):
response = HTTPConnection.getresponse(self)
- logger.debug(("HTTP PERF: %(time).5f seconds to %(method)s "
- "%(host)s:%(port)s %(path)s)"),
+ logging.debug(('HTTP PERF: %(time).5f seconds to %(method)s '
+ '%(host)s:%(port)s %(path)s)'),
{'time': time.time() - self._connected_time, 'method': self._method,
'host': self.host, 'port': self.port, 'path': self._path})
return response
-# pylint: disable=R0913
def http_connect(ipaddr, port, device, partition, method, path,
- headers=None, query_string=None, ssl=False, key_file=None,
- cert_file=None, timeout=None):
+ headers=None, query_string=None, ssl=False):
"""
Helper function to create an HTTPConnection object. If ssl is set True,
HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection
@@ -130,21 +118,26 @@ def http_connect(ipaddr, port, device, partition, method, path,
:param headers: dictionary of headers
:param query_string: request query string
:param ssl: set True if SSL should be used (default: False)
- :param key_file: Private key file (not needed if cert_file has private key)
- :param cert_file: Certificate file (Keystore)
:returns: HTTPConnection object
"""
+ if ssl:
+ conn = HTTPSConnection('%s:%s' % (ipaddr, port))
+ else:
+ conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port))
path = quote('/' + device + '/' + str(partition) + path)
- # pylint: disable=E1121, E1124
- return http_connect_raw(ipaddr, port, device, partition, method, path,
- headers, query_string, ssl, key_file, cert_file,
- timeout=timeout)
+ if query_string:
+ path += '?' + query_string
+ conn.path = path
+ conn.putrequest(method, path)
+ if headers:
+ for header, value in headers.iteritems():
+ conn.putheader(header, value)
+ conn.endheaders()
+ return conn
-# pylint: disable=W0201
def http_connect_raw(ipaddr, port, method, path, headers=None,
- query_string=None, ssl=False, key_file=None,
- cert_file=None, timeout=None):
+ query_string=None, ssl=False):
"""
Helper function to create an HTTPConnection object. If ssl is set True,
HTTPSConnection will be used. However, if ssl=False, BufferedHTTPConnection
@@ -157,26 +150,18 @@ def http_connect_raw(ipaddr, port, method, path, headers=None,
:param headers: dictionary of headers
:param query_string: request query string
:param ssl: set True if SSL should be used (default: False)
- :param key_file: Private key file (not needed if cert_file has private key)
- :param cert_file: Certificate file (Keystore)
:returns: HTTPConnection object
"""
- if timeout is None:
- timeout = DEFAULT_TIMEOUT
if ssl:
- conn = HTTPSConnection('%s:%s' % (ipaddr, port), key_file=key_file,
- cert_file=cert_file, timeout=timeout)
+ conn = HTTPSConnection('%s:%s' % (ipaddr, port))
else:
- conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port),
- timeout=timeout)
+ conn = BufferedHTTPConnection('%s:%s' % (ipaddr, port))
if query_string:
path += '?' + query_string
conn.path = path
conn.putrequest(method, path)
if headers:
- # pylint: disable=E1103
for header, value in headers.iteritems():
conn.putheader(header, value)
- # pylint: disable=E1103
conn.endheaders()
return conn
diff --git a/keystone/cfg.py b/keystone/common/cfg.py
index da91356f..91c9546c 100644
--- a/keystone/cfg.py
+++ b/keystone/common/cfg.py
@@ -17,7 +17,7 @@
r"""
Configuration options which may be set on the command line or in config files.
-The schema for each option is defined using the Opt sub-classes e.g.
+The schema for each option is defined using the Opt sub-classes e.g.::
common_opts = [
cfg.StrOpt('bind_host',
@@ -28,7 +28,7 @@ The schema for each option is defined using the Opt sub-classes e.g.
help='Port number to listen on')
]
-Options can be strings, integers, floats, booleans, lists or 'multi strings':
+Options can be strings, integers, floats, booleans, lists or 'multi strings'::
enabled_apis_opt = \
cfg.ListOpt('enabled_apis',
@@ -43,7 +43,7 @@ Options can be strings, integers, floats, booleans, lists or 'multi strings':
default=DEFAULT_EXTENSIONS)
Option schemas are registered with with the config manager at runtime, but
-before the option is referenced:
+before the option is referenced::
class ExtensionManager(object):
@@ -59,7 +59,7 @@ before the option is referenced:
....
A common usage pattern is for each option schema to be defined in the module or
-class which uses the option:
+class which uses the option::
opts = ...
@@ -74,7 +74,7 @@ class which uses the option:
An option may optionally be made available via the command line. Such options
must registered with the config manager before the command line is parsed (for
-the purposes of --help and CLI arg validation):
+the purposes of --help and CLI arg validation)::
cli_opts = [
cfg.BoolOpt('verbose',
@@ -90,7 +90,7 @@ the purposes of --help and CLI arg validation):
def add_common_opts(conf):
conf.register_cli_opts(cli_opts)
-The config manager has a single CLI option defined by default, --config-file:
+The config manager has a single CLI option defined by default, --config-file::
class ConfigOpts(object):
@@ -104,7 +104,7 @@ The config manager has a single CLI option defined by default, --config-file:
Option values are parsed from any supplied config files using SafeConfigParser.
If none are specified, a default set is used e.g. glance-api.conf and
-glance-common.conf:
+glance-common.conf::
glance-api.conf:
[DEFAULT]
@@ -119,7 +119,7 @@ are parsed in order, with values in later files overriding those in earlier
files.
The parsing of CLI args and config files is initiated by invoking the config
-manager e.g.
+manager e.g.::
conf = ConfigOpts()
conf.register_opt(BoolOpt('verbose', ...))
@@ -127,7 +127,7 @@ manager e.g.
if conf.verbose:
...
-Options can be registered as belonging to a group:
+Options can be registered as belonging to a group::
rabbit_group = cfg.OptionGroup(name='rabbit',
title='RabbitMQ options')
@@ -154,7 +154,7 @@ Options can be registered as belonging to a group:
conf.register_opt(rabbit_ssl_opt, group=rabbit_group)
If no group is specified, options belong to the 'DEFAULT' section of config
-files:
+files::
glance-api.conf:
[DEFAULT]
@@ -175,7 +175,7 @@ Command-line options in a group are automatically prefixed with the group name:
Option values in the default group are referenced as attributes/properties on
the config manager; groups are also attributes on the config manager, with
-attributes for each of the options associated with the group:
+attributes for each of the options associated with the group::
server.start(app, conf.bind_port, conf.bind_host, conf)
@@ -184,7 +184,7 @@ attributes for each of the options associated with the group:
port=conf.rabbit.port,
...)
-Option values may reference other values using PEP 292 string substitution:
+Option values may reference other values using PEP 292 string substitution::
opts = [
cfg.StrOpt('state_path',
@@ -200,17 +200,13 @@ Option values may reference other values using PEP 292 string substitution:
Note that interpolation can be avoided by using '$$'.
"""
-# pylint: disable=W0231,W0212,W0141,C0302,R0913,W0402
+
+import sys
import ConfigParser
import copy
-import logging
import optparse
import os
-import re
import string
-import sys
-
-LOG = logging.getLogger(__name__)
class Error(Exception):
@@ -227,9 +223,9 @@ class ArgsAlreadyParsedError(Error):
"""Raised if a CLI opt is registered after parsing."""
def __str__(self):
- ret = "arguments already parsed"
+ ret = 'arguments already parsed'
if self.msg:
- ret += ": " + self.msg
+ ret += ': ' + self.msg
return ret
@@ -242,9 +238,9 @@ class NoSuchOptError(Error):
def __str__(self):
if self.group is None:
- return "no such option: %s" % self.opt_name
+ return 'no such option: %s' % self.opt_name
else:
- return "no such option in group %s: %s" % (self.group.name,
+ return 'no such option in group %s: %s' % (self.group.name,
self.opt_name)
@@ -255,7 +251,7 @@ class NoSuchGroupError(Error):
self.group_name = group_name
def __str__(self):
- return "no such group: %s" % self.group_name
+ return 'no such group: %s' % self.group_name
class DuplicateOptError(Error):
@@ -265,14 +261,14 @@ class DuplicateOptError(Error):
self.opt_name = opt_name
def __str__(self):
- return "duplicate option: %s" % self.opt_name
+ return 'duplicate option: %s' % self.opt_name
class TemplateSubstitutionError(Error):
"""Raised if an error occurs substituting a variable in an opt value."""
def __str__(self):
- return "template substitution error: %s" % self.msg
+ return 'template substitution error: %s' % self.msg
class ConfigFilesNotFoundError(Error):
@@ -445,8 +441,7 @@ class Opt(object):
prefix = self._get_optparse_prefix('', group)
self._add_to_optparse(container, self.name, self.short, kwargs, prefix)
- @staticmethod
- def _add_to_optparse(container, name, short, kwargs, prefix=''):
+ def _add_to_optparse(self, container, name, short, kwargs, prefix=''):
"""Add an option to an optparse parser or group.
:param container: an optparse.OptionContainer object
@@ -464,8 +459,7 @@ class Opt(object):
raise DuplicateOptError(a)
container.add_option(*args, **kwargs)
- @staticmethod
- def _get_optparse_container(parser, group):
+ def _get_optparse_container(self, parser, group):
"""Returns an optparse.OptionContainer.
:param parser: an optparse.OptionParser
@@ -497,8 +491,7 @@ class Opt(object):
})
return kwargs
- @staticmethod
- def _get_optparse_prefix(prefix, group):
+ def _get_optparse_prefix(self, prefix, group):
"""Build a prefix for the CLI option name, if required.
CLI options in a group are prefixed with the group's name in order
@@ -603,7 +596,6 @@ class ListOpt(Opt):
callback=self._parse_list,
**kwargs)
- # pylint: disable=W0613
def _parse_list(self, option, opt, value, parser):
"""An optparse callback for parsing an option value into a list."""
setattr(parser.values, self.dest, value.split(','))
@@ -689,7 +681,6 @@ class OptGroup(object):
return self._optparse_group
-# pylint: disable=R0902
class ConfigOpts(object):
"""
@@ -764,11 +755,16 @@ class ConfigOpts(object):
:raises: SystemExit, ConfigFilesNotFoundError, ConfigFileParseError
"""
self.reset()
+
self._args = args
+
(values, args) = self._oparser.parse_args(self._args)
+
self._cli_values = vars(values)
+
if self.config_file:
- self._parse_config_files()
+ self._parse_config_files(self.config_file)
+
return args
def __getattr__(self, name):
@@ -934,16 +930,9 @@ class ConfigOpts(object):
info = self._get_opt_info(name, group)
default, opt, override = map(lambda k: info[k], sorted(info.keys()))
- # Explicit code overrides always trump others.
if override is not None:
return override
- # CLI values override configuration settings.
- name = name if group is None else "%s_%s" % (group.name, name)
- value = self._cli_values.get(name, None)
- if value is not None:
- return value
-
if self._cparser is not None:
section = group.name if group is not None else 'DEFAULT'
try:
@@ -954,6 +943,11 @@ class ConfigOpts(object):
except ValueError, ve:
raise ConfigFileValueError(str(ve))
+ name = name if group is None else group.name + '_' + name
+ value = self._cli_values.get(name, None)
+ if value is not None:
+ return value
+
if default is not None:
return default
@@ -1017,60 +1011,11 @@ class ConfigOpts(object):
return opts[opt_name]
- # pylint: disable=R0914,R0201
- def _update_config_format(self, config_files):
- """
- Update the config files in case they contain keys with dashes instead
- of underscores. If a file needs updating, write it to a temp files and
- replace the original name with the temp file.
- NOTE: warnings are issued if any old formats are found.
- """
- ret = config_files[:]
- bad_settings = []
- for pos, cf in enumerate(config_files):
- warn = False
- out = []
- with file(cf) as config:
- for ln in config:
- try:
- kk, vv = ln.split("=")
- except ValueError:
- out.append(ln)
- continue
- # Replace dashes with underscores
- newk = kk.replace("-", "_")
- # Replace periods with colons *only* if not part of a
- # numeric value.
- newk = re.sub(r"([^\d])\.([^\d])", r"\1:\2", newk)
- if newk != kk and not kk.startswith("paste."):
- warn = True
- bad_settings.append("%s -> %s" % (kk, newk))
- out.append("=".join((newk, vv)))
- out_text = "\n".join(out)
- if warn:
- # Need to write out a new tmp file and print a warning
- changes = "\n\t".join(bad_settings)
- msg = "\n\nWarning: your configuration may be using an old"\
- " format. Please update the following settings by"\
- " replacing hyphens with underscores, and periods"\
- " with colons:\n\t%s\n\n" % changes
- # TODO(ziad): verify if that is what other projects are moving
- # to? If so, make this a warning
- LOG.debug(msg)
- # Importing here to avoid circular imports.
- from keystone import utils
- new_name = utils.write_temp_file(out_text)
- ret[pos] = new_name
- return ret
-
- def _parse_config_files(self, config_files=None):
+ def _parse_config_files(self, config_files):
"""Parse the supplied configuration files.
:raises: ConfigFilesNotFoundError, ConfigFileParseError
"""
- if config_files is None:
- config_files = self.config_file
- config_files = self._update_config_format(config_files)
self._cparser = ConfigParser.SafeConfigParser()
try:
diff --git a/keystone/common/config.py b/keystone/common/config.py
deleted file mode 100755
index dbfad235..00000000
--- a/keystone/common/config.py
+++ /dev/null
@@ -1,386 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Routines for configuring OpenStack Service
-"""
-
-import logging.config
-from logging import FileHandler
-import optparse
-import os
-from paste import deploy
-import sys
-import ConfigParser
-from keystone.common.wsgi import add_console_handler
-
-DEFAULT_LOG_FORMAT = "%(asctime)s %(levelname)8s [%(name)s] %(message)s"
-DEFAULT_LOG_DATE_FORMAT = "%Y-%m-%d %H:%M:%S"
-DEFAULT_LOG_DIR = "/var/log/keystone"
-DEFAULT_LOG_FILE = "keystone.log"
-
-
-def parse_options(parser, cli_args=None):
- """
- Returns the parsed CLI options, command to run and its arguments, merged
- with any same-named options found in a configuration file.
-
- The function returns a tuple of (options, args), where options is a
- mapping of option key/str(value) pairs, and args is the set of arguments
- (not options) supplied on the command-line.
-
- The reason that the option values are returned as strings only is that
- ConfigParser and paste.deploy only accept string values...
-
- :param parser: The option parser
- :param cli_args: (Optional) Set of arguments to process. If not present,
- sys.argv[1:] is used.
- :returns: tuple of (options, args)
-
- """
-
- (options, args) = parser.parse_args(cli_args)
-
- return (vars(options), args)
-
-
-def add_common_options(parser):
- """
- Given a supplied optparse.OptionParser, adds an OptionGroup that
- represents all common configuration options.
-
- :param parser: optparse.OptionParser
- """
- help_text = "The following configuration options are common to "\
- "all keystone programs."
-
- group = optparse.OptionGroup(parser, "Common Options", help_text)
- group.add_option('-v', '--verbose', default=False, dest="verbose",
- action="store_true",
- help="Print more verbose output")
- group.add_option('-d', '--debug', default=False, dest="debug",
- action="store_true",
- help="Print debugging output to console")
- group.add_option('-c', '--config-file', default=None, metavar="PATH",
- help="""Path to the config file to use. When not \
-specified (the default), we generally look at the first argument specified to \
-be a config file, and if that is also missing, we search standard directories \
-for a config file.""")
- group.add_option('-p', '--port', '--bind-port',
- dest="bind_port",
- help="specifies port to listen on")
- group.add_option('--host', '--bind-host',
- default=None, dest="bind_host",
- help="specifies host address to listen on "\
- "(default is all or 0.0.0.0)")
- # This one is handled by keystone/tools/tracer.py (if loaded)
- group.add_option('-t', '--trace-calls', default=False,
- dest="trace_calls",
- action="store_true",
- help="Turns on call tracing for troubleshooting")
-
- parser.add_option_group(group)
- return group
-
-
-def add_log_options(parser):
- """
- Given a supplied optparse.OptionParser, adds an OptionGroup that
- represents all the configuration options around logging.
-
- :param parser: optparse.OptionParser
- """
- help_text = "The following configuration options are specific to logging "\
- "functionality for this program."
-
- group = optparse.OptionGroup(parser, "Logging Options", help_text)
- group.add_option('--log-config', default=None, metavar="PATH",
- help="""If this option is specified, the logging \
-configuration file specified is used and overrides any other logging options \
-specified. Please see the Python logging module documentation for details on \
-logging configuration files.""")
- group.add_option('--log-date-format', metavar="FORMAT",
- default=DEFAULT_LOG_DATE_FORMAT,
- help="Format string for %(asctime)s in log records. "\
- "Default: %default")
- group.add_option('--log-file', default=None, metavar="PATH",
- help="(Optional) Name of log file to output to. "\
- "If not set, logging will go to stdout.")
- group.add_option("--log-dir", default=None,
- help="(Optional) The directory to keep log files in "\
- "(will be prepended to --logfile)")
-
- parser.add_option_group(group)
- return group
-
-
-def setup_logging(options, conf):
- """
- Sets up the logging options for a log with supplied name
-
- :param options: Mapping of typed option key/values
- :param conf: Mapping of untyped key/values from config file
- """
- if options.get('log_config', None):
- # Use a logging configuration file for all settings...
- if os.path.exists(options['log_config']):
- logging.config.fileConfig(options['log_config'])
- return
- else:
- raise RuntimeError("Unable to locate specified logging "\
- "config file: %s" % options['log_config'])
-
- # If either the CLI option or the conf value
- # is True, we set to True
- debug = options.get('debug') or conf.get('debug', False)
- debug = debug in [True, "True", "1"]
- verbose = options.get('verbose') or conf.get('verbose', False)
- verbose = verbose in [True, "True", "1"]
- root_logger = logging.root
- root_logger.setLevel(
- logging.DEBUG if debug else
- logging.INFO if verbose else
- logging.WARNING)
-
- # Set log configuration from options...
- # Note that we use a hard-coded log format in the options
- # because of Paste.Deploy bug #379
- # http://trac.pythonpaste.org/pythonpaste/ticket/379
- log_format = options.get('log_format', DEFAULT_LOG_FORMAT)
- log_date_format = options.get('log_date_format', DEFAULT_LOG_DATE_FORMAT)
- formatter = logging.Formatter(log_format, log_date_format)
-
- # grab log_file and log_dir from config; set to defaults of not already
- # defined
- logfile = options.get('log_file') or conf.get('log_file', DEFAULT_LOG_FILE)
- logdir = options.get('log_dir') or conf.get('log_dir', DEFAULT_LOG_DIR)
-
- # Add FileHandler if it doesn't exist
- logfile = os.path.abspath(os.path.join(logdir, logfile))
- handlers = [handler for handler in root_logger.handlers
- if isinstance(handler, FileHandler)
- and handler.baseFilename == logfile]
-
- if not handlers:
- logfile = logging.FileHandler(logfile)
- logfile.setFormatter(formatter)
- root_logger.addHandler(logfile)
-
- # Mirror to console if verbose or debug
- if debug or verbose:
- add_console_handler(root_logger, logging.DEBUG)
- else:
- add_console_handler(root_logger, logging.INFO)
-
-
-def find_config_file(options, args):
- """
- Return the first config file found.
-
- We search for the paste config file in the following order:
- * If --config-file option is used, use that
- * If args[0] is a file, use that
- * Search for keystone.conf in standard directories:
-
- * .
- * ~.keystone/
- * ~
- * /etc/keystone
- * /etc
-
- If no config file is given get from possible_topdir/etc/keystone.conf
-
- :returns: Full path to config file, or None if no config file found
- """
- POSSIBLE_TOPDIR = os.path.normpath(os.path.join(\
- os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
- fix_path = lambda p: os.path.abspath(os.path.expanduser(p))
- cfg_file = options.get('config_file')
- if cfg_file:
- if isinstance(cfg_file, list):
- cfg_file = cfg_file[0]
- if os.path.exists(cfg_file):
- return fix_path(cfg_file)
- elif args:
- if os.path.exists(args[0]):
- return fix_path(args[0])
-
- # Handle standard directory search for keystone.conf
- config_file_dirs = [fix_path(os.getcwd()),
- fix_path(os.path.join('~', '.keystone')),
- fix_path('~'),
- '/etc/keystone/',
- '/etc']
-
- for cfg_dir in config_file_dirs:
- cfg_file = os.path.join(cfg_dir, 'keystone.conf')
- if os.path.exists(cfg_file):
- return cfg_file
- else:
- if os.path.exists(os.path.join(POSSIBLE_TOPDIR, 'etc', \
- 'keystone.conf')):
- # For debug only
- config_file = os.path.join(POSSIBLE_TOPDIR, 'etc', \
- 'keystone.conf')
- return config_file
-
-
-def load_paste_config(app_name, options, args):
- """
- Looks for a config file to use for an app and returns the
- config file path and a configuration mapping from a paste config file.
-
- We search for the paste config file in the following order:
-
- * If --config-file option is used, use that
- * If args[0] is a file, use that
- * Search for keystone.conf in standard directories:
-
- * .
- * ~.keystone/
- * ~
- * /etc/keystone
- * /etc
-
- :param app_name: Name of the application to load config for, or None.
- None signifies to only load the [DEFAULT] section of
- the config file.
- :param options: Set of typed options returned from parse_options()
- :param args: Command line arguments from argv[1:]
- :returns: Tuple of (conf_file, conf)
- :raises: RuntimeError when config file cannot be located or there was a
- problem loading the configuration file.
- """
- conf_file = find_config_file(options, args)
- if not conf_file:
- raise RuntimeError("Unable to locate any configuration file. "\
- "Cannot load application %s" % app_name)
- try:
- conf = deploy.appconfig("config:%s" % conf_file, name=app_name)
- conf.global_conf.update(get_non_paste_configs(conf_file))
- return conf_file, conf
- except Exception, e:
- raise RuntimeError("Error loading config %s: %s" % (conf_file, e))
-
-
-def get_non_paste_configs(conf_file):
- load_config_files(conf_file)
- complete_conf = load_config_files(conf_file)
- #Add Non Paste global sections.Need to find a better way.
- global_conf = {}
- if complete_conf is not None:
- for section in complete_conf.sections():
- if not (section.startswith('filter:') or \
- section.startswith('app:') or \
- section.startswith('pipeline:')):
- section_items = complete_conf.items(section)
- section_items_dict = {}
- for section_item in section_items:
- section_items_dict[section_item[0]] = section_item[1]
- global_conf[section] = section_items_dict
- return global_conf
-
-
-def load_config_files(config_files):
- '''Load the config files.'''
- config = ConfigParser.ConfigParser()
- if config_files is not None:
- config.read(config_files)
- return config
-
-
-def load_paste_app(app_name, options, args):
- """
- Builds and returns a WSGI app from a paste config file.
-
- We search for the paste config file in the following order:
- * If --config-file option is used, use that
- * If args[0] is a file, use that
- * Search for keystone.conf in standard directories:
-
- * .
- * ~.keystone/
- * ~
- * /etc/keystone
- * /etc
-
- :param app_name: Name of the application to load (server, admin, proxy, ..)
- :param options: Set of typed options returned from parse_options()
- :param args: Command line arguments from argv[1:]
- :raises: RuntimeError when config file cannot be located or application
- cannot be loaded from config file
- """
- conf_file, conf = load_paste_config(app_name, options, args)
-
- try:
- # Setup logging early, supplying both the CLI options and the
- # configuration mapping from the config file
- if not conf.get('log_file'):
- options['log_file'] = "%s.log" % app_name
- setup_logging(options, conf)
-
- # We only update the conf dict for the verbose and debug
- # flags. Everything else must be set up in the conf file...
- debug = options.get('debug') or conf.get('debug', False)
- debug = debug in [True, "True", "1"]
- verbose = options.get('verbose') or conf.get('verbose', False)
- verbose = verbose in [True, "True", "1"]
- conf['debug'] = debug
- conf['verbose'] = verbose
- # Log the options used when starting if we're in debug mode...
- if debug:
- logger = logging.getLogger(app_name)
- logger.info("*" * 50)
- logger.info("Configuration options gathered from config file:")
- logger.info(conf_file)
- logger.info("================================================")
- items = dict([(k, v) for k, v in conf.items()
- if k not in ('__file__', 'here')])
- for key, value in sorted(items.items()):
- logger.info("%(key)-20s %(value)s" % locals())
- logger.info("*" * 50)
- app = deploy.loadapp("config:%s" % conf_file, name=app_name,
- global_conf=conf.global_conf)
- except (LookupError, ImportError) as e:
- raise RuntimeError("Unable to load %(app_name)s from "
- "configuration file %(conf_file)s."
- "\nGot: %(e)r" % locals())
- return conf, app
-
-
-def get_option(options, option, **kwargs):
- if option in options:
- value = options[option]
- type_ = kwargs.get('type', 'str')
- if type_ == 'bool':
- if hasattr(value, 'lower'):
- return value.lower() == 'true'
- else:
- return value
- elif type_ == 'int':
- return int(value)
- elif type_ == 'float':
- return float(value)
- else:
- return value
- elif 'default' in kwargs:
- return kwargs['default']
- else:
- raise KeyError("option '%s' not found" % option)
diff --git a/keystone/common/crypt.py b/keystone/common/crypt.py
deleted file mode 100644
index bb25620d..00000000
--- a/keystone/common/crypt.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Routines for URL-safe encrypting/decrypting
-
-Keep this file in sync with all copies:
-- glance/common/crypt.py
-- keystone/middleware/crypt.py
-- keystone/common/crypt.py
-
-"""
-
-import base64
-
-from Crypto.Cipher import AES
-from Crypto import Random
-from Crypto.Random import random
-
-
-def urlsafe_encrypt(key, plaintext, blocksize=16):
- """
- Encrypts plaintext. Resulting ciphertext will contain URL-safe characters
- :param key: AES secret key
- :param plaintext: Input text to be encrypted
- :param blocksize: Non-zero integer multiple of AES blocksize in bytes (16)
-
- :returns : Resulting ciphertext
- """
- def pad(text):
- """
- Pads text to be encrypted
- """
- pad_length = (blocksize - len(text) % blocksize)
- sr = random.StrongRandom()
- pad = ''.join(chr(sr.randint(1, 0xFF)) for i in range(pad_length - 1))
- # We use chr(0) as a delimiter between text and padding
- return text + chr(0) + pad
-
- # random initial 16 bytes for CBC
- init_vector = Random.get_random_bytes(16)
- cypher = AES.new(key, AES.MODE_CBC, init_vector)
- padded = cypher.encrypt(pad(str(plaintext)))
- return base64.urlsafe_b64encode(init_vector + padded)
-
-
-def urlsafe_decrypt(key, ciphertext):
- """
- Decrypts URL-safe base64 encoded ciphertext
- :param key: AES secret key
- :param ciphertext: The encrypted text to decrypt
-
- :returns : Resulting plaintext
- """
- # Cast from unicode
- ciphertext = base64.urlsafe_b64decode(str(ciphertext))
- cypher = AES.new(key, AES.MODE_CBC, ciphertext[:16])
- padded = cypher.decrypt(ciphertext[16:])
- return padded[:padded.rfind(chr(0))]
diff --git a/keystone/common/exception.py b/keystone/common/exception.py
deleted file mode 100755
index e734e94f..00000000
--- a/keystone/common/exception.py
+++ /dev/null
@@ -1,100 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-OpenStack base exception handling, including decorator for re-raising
-OpenStack-type exceptions. SHOULD include dedicated exception logging.
-"""
-
-import logging
-
-
-class ProcessExecutionError(IOError):
- def __init__(self, stdout=None, stderr=None, exit_code=None, cmd=None,
- description=None):
- if description is None:
- description = "Unexpected error while running command."
- if exit_code is None:
- exit_code = '-'
- message = "%s\nCommand: %s\nExit code: %s\nStdout: %r\nStderr: %r" % (
- description, cmd, exit_code, stdout, stderr)
- IOError.__init__(self, message)
-
-
-class Error(Exception):
- def __init__(self, message=None):
- super(Error, self).__init__(message)
-
-
-class ApiError(Error):
- def __init__(self, message='Unknown', code='Unknown'):
- self.message = message
- self.code = code
- super(ApiError, self).__init__('%s: %s' % (code, message))
-
-
-class NotFound(Error):
- pass
-
-
-class Duplicate(Error):
- pass
-
-
-class NotAuthorized(Error):
- pass
-
-
-class NotEmpty(Error):
- pass
-
-
-class Invalid(Error):
- pass
-
-
-class BadInputError(Exception):
- """Error resulting from a client sending bad input to a server"""
- pass
-
-
-class MissingArgumentError(Error):
- pass
-
-
-class DatabaseMigrationError(Error):
- pass
-
-
-class ClientError(Error):
- pass
-
-
-def wrap_exception(f):
- def _wrap(*args, **kw):
- try:
- return f(*args, **kw)
- except Exception, e:
- if not isinstance(e, Error):
- #exc_type, exc_value, exc_traceback = sys.exc_info()
- logging.exception('Uncaught exception')
- #logging.error(traceback.extract_stack(exc_traceback))
- raise Error(str(e))
- raise
- _wrap.func_name = f.func_name
- return _wrap
diff --git a/keystone/common/kvs.py b/keystone/common/kvs.py
new file mode 100644
index 00000000..795c2f70
--- /dev/null
+++ b/keystone/common/kvs.py
@@ -0,0 +1,24 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+
+class DictKvs(dict):
+ def set(self, key, value):
+ if type(value) is type({}):
+ self[key] = value.copy()
+ else:
+ self[key] = value[:]
+
+ def delete(self, key):
+ del self[key]
+
+
+INMEMDB = DictKvs()
+
+
+class Base(object):
+ def __init__(self, db=None):
+ if db is None:
+ db = INMEMDB
+ elif type(db) is type({}):
+ db = DictKvs(db)
+ self.db = db
diff --git a/keystone/common/logging.py b/keystone/common/logging.py
new file mode 100644
index 00000000..a9aaccfc
--- /dev/null
+++ b/keystone/common/logging.py
@@ -0,0 +1,55 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Wrapper for built-in logging module."""
+
+from __future__ import absolute_import
+
+import functools
+import logging
+import pprint
+
+from logging.handlers import SysLogHandler
+from logging.handlers import WatchedFileHandler
+
+# A list of things we want to replicate from logging.
+# levels
+CRITICAL = logging.CRITICAL
+FATAL = logging.FATAL
+ERROR = logging.ERROR
+WARNING = logging.WARNING
+WARN = logging.WARN
+INFO = logging.INFO
+DEBUG = logging.DEBUG
+NOTSET = logging.NOTSET
+
+
+# methods
+getLogger = logging.getLogger
+debug = logging.debug
+info = logging.info
+warning = logging.warning
+warn = logging.warn
+error = logging.error
+exception = logging.exception
+critical = logging.critical
+log = logging.log
+
+# classes
+root = logging.root
+Formatter = logging.Formatter
+
+# handlers
+StreamHandler = logging.StreamHandler
+WatchedFileHandler = WatchedFileHandler
+SysLogHandler = SysLogHandler
+
+
+def log_debug(f):
+ @functools.wraps(f)
+ def wrapper(*args, **kw):
+ logging.debug('%s(%s, %s) ->', f.func_name, str(args), str(kw))
+ rv = f(*args, **kw)
+ logging.debug(pprint.pformat(rv, indent=2))
+ logging.debug('')
+ return rv
+ return wrapper
diff --git a/keystone/common/manager.py b/keystone/common/manager.py
new file mode 100644
index 00000000..17c7d5e5
--- /dev/null
+++ b/keystone/common/manager.py
@@ -0,0 +1,36 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import functools
+
+from keystone import config
+from keystone.common import utils
+
+
+class Manager(object):
+ """Base class for intermediary request layer.
+
+ The Manager layer exists to support additional logic that applies to all
+ or some of the methods exposed by a service that are not specific to the
+ HTTP interface.
+
+ It also provides a stable entry point to dynamic backends.
+
+ An example of a probable use case is logging all the calls.
+
+ """
+
+ def __init__(self, driver_name):
+ self.driver = utils.import_object(driver_name)
+
+ def __getattr__(self, name):
+ """Forward calls to the underlying driver."""
+ # NOTE(termie): context is the first argument, we're going to strip
+ # that for now, in the future we'll probably do some
+ # logging and whatnot in this class
+ f = getattr(self.driver, name)
+
+ @functools.wraps(f)
+ def _wrapper(context, *args, **kw):
+ return f(*args, **kw)
+ setattr(self, name, _wrapper)
+ return _wrapper
diff --git a/keystone/common/sql/__init__.py b/keystone/common/sql/__init__.py
new file mode 100644
index 00000000..ae31c702
--- /dev/null
+++ b/keystone/common/sql/__init__.py
@@ -0,0 +1 @@
+from keystone.common.sql.core import *
diff --git a/keystone/common/sql/core.py b/keystone/common/sql/core.py
new file mode 100644
index 00000000..cb621865
--- /dev/null
+++ b/keystone/common/sql/core.py
@@ -0,0 +1,119 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""SQL backends for the various services."""
+
+
+import json
+
+import eventlet.db_pool
+import sqlalchemy as sql
+from sqlalchemy import types as sql_types
+from sqlalchemy.ext import declarative
+import sqlalchemy.orm
+import sqlalchemy.pool
+import sqlalchemy.engine.url
+
+from keystone import config
+
+
+CONF = config.CONF
+
+
+ModelBase = declarative.declarative_base()
+
+
+# For exporting to other modules
+Column = sql.Column
+String = sql.String
+ForeignKey = sql.ForeignKey
+DateTime = sql.DateTime
+
+
+# Special Fields
+class JsonBlob(sql_types.TypeDecorator):
+ impl = sql.Text
+
+ def process_bind_param(self, value, dialect):
+ return json.dumps(value)
+
+ def process_result_value(self, value, dialect):
+ return json.loads(value)
+
+
+class DictBase(object):
+ def to_dict(self):
+ return dict(self.iteritems())
+
+ def __setitem__(self, key, value):
+ setattr(self, key, value)
+
+ def __getitem__(self, key):
+ return getattr(self, key)
+
+ def get(self, key, default=None):
+ return getattr(self, key, default)
+
+ def __iter__(self):
+ self._i = iter(sqlalchemy.orm.object_mapper(self).columns)
+ return self
+
+ def next(self):
+ n = self._i.next().name
+ return n
+
+ def update(self, values):
+ """Make the model object behave like a dict."""
+ for k, v in values.iteritems():
+ setattr(self, k, v)
+
+ def iteritems(self):
+ """Make the model object behave like a dict.
+
+ Includes attributes from joins.
+
+ """
+ return dict([(k, getattr(self, k)) for k in self])
+ #local = dict(self)
+ #joined = dict([(k, v) for k, v in self.__dict__.iteritems()
+ # if not k[0] == '_'])
+ #local.update(joined)
+ #return local.iteritems()
+
+
+# Backends
+class Base(object):
+ _MAKER = None
+ _ENGINE = None
+
+ def get_session(self, autocommit=True, expire_on_commit=False):
+ """Return a SQLAlchemy session."""
+ if self._MAKER is None or self._ENGINE is None:
+ self._ENGINE = self.get_engine()
+ self._MAKER = self.get_maker(self._ENGINE,
+ autocommit,
+ expire_on_commit)
+
+ session = self._MAKER()
+ # TODO(termie): we may want to do something similar
+ #session.query = nova.exception.wrap_db_error(session.query)
+ #session.flush = nova.exception.wrap_db_error(session.flush)
+ return session
+
+ def get_engine(self):
+ """Return a SQLAlchemy engine."""
+ connection_dict = sqlalchemy.engine.url.make_url(CONF.sql.connection)
+
+ engine_args = {'pool_recycle': CONF.sql.idle_timeout,
+ 'echo': False,
+ }
+
+ if 'sqlite' in connection_dict.drivername:
+ engine_args['poolclass'] = sqlalchemy.pool.NullPool
+
+ return sql.create_engine(CONF.sql.connection, **engine_args)
+
+ def get_maker(self, engine, autocommit=True, expire_on_commit=False):
+ """Return a SQLAlchemy sessionmaker using the given engine."""
+ return sqlalchemy.orm.sessionmaker(bind=engine,
+ autocommit=autocommit,
+ expire_on_commit=expire_on_commit)
diff --git a/keystone/common/sql/legacy.py b/keystone/common/sql/legacy.py
new file mode 100644
index 00000000..d8bbb2c5
--- /dev/null
+++ b/keystone/common/sql/legacy.py
@@ -0,0 +1,141 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import re
+
+import sqlalchemy
+
+from keystone.identity.backends import sql as identity_sql
+
+
+def export_db(db):
+ table_names = db.table_names()
+
+ migration_data = {}
+ for table_name in table_names:
+ query = db.execute("select * from %s" % table_name)
+ table_data = []
+ for row in query.fetchall():
+ entry = {}
+ for k in row.keys():
+ entry[k] = row[k]
+ table_data.append(entry)
+
+ migration_data[table_name] = table_data
+
+ return migration_data
+
+
+def _translate_replacements(s):
+ if '%' not in str(s):
+ return s
+ return re.sub(r'%([\w_]+)%', r'$(\1)s', s)
+
+
+class LegacyMigration(object):
+ def __init__(self, db_string):
+ self.db = sqlalchemy.create_engine(db_string)
+ self.identity_driver = identity_sql.Identity()
+ self.identity_driver.db_sync()
+ self._data = {}
+ self._user_map = {}
+ self._tenant_map = {}
+ self._role_map = {}
+
+ def migrate_all(self):
+ self._export_legacy_db()
+ self._migrate_tenants()
+ self._migrate_users()
+ self._migrate_roles()
+ self._migrate_user_roles()
+ self._migrate_tokens()
+
+ def dump_catalog(self):
+ """Generate the contents of a catalog templates file."""
+ self._export_legacy_db()
+
+ services_by_id = dict((x['id'], x) for x in self._data['services'])
+ template = 'catalog.%(region)s.%(service_type)s.%(key)s = %(value)s'
+
+ o = []
+ for row in self._data['endpoint_templates']:
+ service = services_by_id[row['service_id']]
+ d = {'service_type': service['type'],
+ 'region': row['region']}
+
+ for x in ['internal_url', 'public_url', 'admin_url', 'enabled']:
+ d['key'] = x.replace('_u', 'U')
+ d['value'] = _translate_replacements(row[x])
+ o.append(template % d)
+
+ d['key'] = 'name'
+ d['value'] = service['desc']
+ o.append(template % d)
+
+ return o
+
+ def _export_legacy_db(self):
+ self._data = export_db(self.db)
+
+ def _migrate_tenants(self):
+ for x in self._data['tenants']:
+ # map
+ new_dict = {'description': x.get('desc', ''),
+ 'id': x.get('uid', x.get('id')),
+ 'enabled': x.get('enabled', True)}
+ new_dict['name'] = x.get('name', new_dict.get('id'))
+ # track internal ids
+ self._tenant_map[x.get('id')] = new_dict['id']
+ # create
+ #print 'create_tenant(%s, %s)' % (new_dict['id'], new_dict)
+ self.identity_driver.create_tenant(new_dict['id'], new_dict)
+
+ def _migrate_users(self):
+ for x in self._data['users']:
+ # map
+ new_dict = {'email': x.get('email', ''),
+ 'password': x.get('password', None),
+ 'id': x.get('uid', x.get('id')),
+ 'enabled': x.get('enabled', True)}
+ if x.get('tenant_id'):
+ new_dict['tenant_id'] = self._tenant_map.get(x['tenant_id'])
+ new_dict['name'] = x.get('name', new_dict.get('id'))
+ # track internal ids
+ self._user_map[x.get('id')] = new_dict['id']
+ # create
+ #print 'create_user(%s, %s)' % (new_dict['id'], new_dict)
+ self.identity_driver.create_user(new_dict['id'], new_dict)
+ if new_dict.get('tenant_id'):
+ self.identity_driver.add_user_to_tenant(new_dict['tenant_id'],
+ new_dict['id'])
+
+ def _migrate_roles(self):
+ for x in self._data['roles']:
+ # map
+ new_dict = {'id': x['id'],
+ 'name': x.get('name', x['id'])}
+ # track internal ids
+ self._role_map[x.get('id')] = new_dict['id']
+ # create
+ self.identity_driver.create_role(new_dict['id'], new_dict)
+
+ def _migrate_user_roles(self):
+ for x in self._data['user_roles']:
+ # map
+ if (not x.get('user_id')
+ or not x.get('tenant_id')
+ or not x.get('role_id')):
+ continue
+ user_id = self._user_map[x['user_id']]
+ tenant_id = self._tenant_map[x['tenant_id']]
+ role_id = self._role_map[x['role_id']]
+
+ try:
+ self.identity_driver.add_user_to_tenant(tenant_id, user_id)
+ except Exception:
+ pass
+
+ self.identity_driver.add_role_to_user_and_tenant(
+ user_id, tenant_id, role_id)
+
+ def _migrate_tokens(self):
+ pass
diff --git a/keystone/backends/sqlalchemy/migrate_repo/README b/keystone/common/sql/migrate_repo/README
index 6218f8ca..6218f8ca 100644
--- a/keystone/backends/sqlalchemy/migrate_repo/README
+++ b/keystone/common/sql/migrate_repo/README
diff --git a/keystone/backends/sqlalchemy/migrate_repo/__init__.py b/keystone/common/sql/migrate_repo/__init__.py
index e69de29b..e69de29b 100644
--- a/keystone/backends/sqlalchemy/migrate_repo/__init__.py
+++ b/keystone/common/sql/migrate_repo/__init__.py
diff --git a/keystone/backends/sqlalchemy/migrate_repo/manage.py b/keystone/common/sql/migrate_repo/manage.py
index 2a928c84..39fa3892 100755..100644
--- a/keystone/backends/sqlalchemy/migrate_repo/manage.py
+++ b/keystone/common/sql/migrate_repo/manage.py
@@ -1,3 +1,5 @@
#!/usr/bin/env python
from migrate.versioning.shell import main
-main(debug='False')
+
+if __name__ == '__main__':
+ main(debug='False')
diff --git a/keystone/backends/sqlalchemy/migrate_repo/migrate.cfg b/keystone/common/sql/migrate_repo/migrate.cfg
index 42986cf7..a8be6089 100644
--- a/keystone/backends/sqlalchemy/migrate_repo/migrate.cfg
+++ b/keystone/common/sql/migrate_repo/migrate.cfg
@@ -1,7 +1,7 @@
[db_settings]
# Used to identify which repository this database is versioned under.
# You can use the name of your project.
-repository_id=Keystone
+repository_id=keystone
# The name of the database table used to track the schema version.
# This name shouldn't already be used by your project.
@@ -18,3 +18,8 @@ version_table=migrate_version
# be using to ensure your updates to that database work properly.
# This must be a list; example: ['postgres','sqlite']
required_dbs=[]
+
+# When creating new change scripts, Migrate will stamp the new script with
+# a version number. By default this is latest_version + 1. You can set this
+# to 'true' to tell Migrate to use the UTC timestamp instead.
+use_timestamp_numbering=False
diff --git a/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py b/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py
new file mode 100644
index 00000000..ae54b476
--- /dev/null
+++ b/keystone/common/sql/migrate_repo/versions/001_add_initial_tables.py
@@ -0,0 +1,20 @@
+from sqlalchemy import *
+from migrate import *
+
+from keystone.common import sql
+
+# these are to make sure all the models we care about are defined
+import keystone.identity.backends.sql
+import keystone.token.backends.sql
+import keystone.contrib.ec2.backends.sql
+
+
+def upgrade(migrate_engine):
+ # Upgrade operations go here. Don't create your own engine; bind
+ # migrate_engine to your metadata
+ sql.ModelBase.metadata.create_all(migrate_engine)
+
+
+def downgrade(migrate_engine):
+ # Operations to reverse the above upgrade go here.
+ pass
diff --git a/keystone/backends/sqlalchemy/migrate_repo/versions/__init__.py b/keystone/common/sql/migrate_repo/versions/__init__.py
index e69de29b..e69de29b 100644
--- a/keystone/backends/sqlalchemy/migrate_repo/versions/__init__.py
+++ b/keystone/common/sql/migrate_repo/versions/__init__.py
diff --git a/keystone/common/sql/migration.py b/keystone/common/sql/migration.py
new file mode 100644
index 00000000..0ea9cd12
--- /dev/null
+++ b/keystone/common/sql/migration.py
@@ -0,0 +1,80 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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 os
+import sys
+
+import sqlalchemy
+from migrate.versioning import api as versioning_api
+
+from keystone import config
+
+
+CONF = config.CONF
+
+
+try:
+ from migrate.versioning import exceptions as versioning_exceptions
+except ImportError:
+ try:
+ # python-migration changed location of exceptions after 1.6.3
+ # See LP Bug #717467
+ from migrate import exceptions as versioning_exceptions
+ except ImportError:
+ sys.exit('python-migrate is not installed. Exiting.')
+
+
+def db_sync(version=None):
+ if version is not None:
+ try:
+ version = int(version)
+ except ValueError:
+ raise Exception('version should be an integer')
+
+ current_version = db_version()
+ repo_path = _find_migrate_repo()
+ if version is None or version > current_version:
+ return versioning_api.upgrade(
+ CONF.sql.connection, repo_path, version)
+ else:
+ return versioning_api.downgrade(
+ CONF.sql.connection, repo_path, version)
+
+
+def db_version():
+ repo_path = _find_migrate_repo()
+ try:
+ return versioning_api.db_version(
+ CONF.sql.connection, repo_path)
+ except versioning_exceptions.DatabaseNotControlledError:
+ return db_version_control(0)
+
+
+def db_version_control(version=None):
+ repo_path = _find_migrate_repo()
+ versioning_api.version_control(
+ CONF.sql.connection, repo_path, version)
+ return version
+
+
+def _find_migrate_repo():
+ """Get the path for the migrate repository."""
+ path = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+ 'migrate_repo')
+ assert os.path.exists(path)
+ return path
diff --git a/keystone/common/sql/util.py b/keystone/common/sql/util.py
new file mode 100644
index 00000000..a181c284
--- /dev/null
+++ b/keystone/common/sql/util.py
@@ -0,0 +1,18 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import os
+
+from keystone import config
+from keystone.common.sql import migration
+
+
+CONF = config.CONF
+
+
+def setup_test_database():
+ # TODO(termie): be smart about this
+ try:
+ os.unlink('bla.db')
+ except Exception:
+ pass
+ migration.db_sync()
diff --git a/keystone/common/template.py b/keystone/common/template.py
deleted file mode 100644
index 27073e70..00000000
--- a/keystone/common/template.py
+++ /dev/null
@@ -1,373 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-#
-# Template library copied from bottle: http://bottlepy.org/
-#
-# Copyright (c) 2011, Marcel Hellkamp.
-#
-# Permission is hereby granted, free of charge, to any person obtaining a copy
-# of this software and associated documentation files (the "Software"), to deal
-# in the Software without restriction, including without limitation the rights
-# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-# copies of the Software, and to permit persons to whom the Software is
-# furnished to do so, subject to the following conditions:
-#
-# The above copyright notice and this permission notice shall be included in
-# all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-# THE SOFTWARE.
-#
-
-
-import cgi
-import re
-import os
-import functools
-import time
-import tokenize
-import mimetypes
-from webob import Response
-from paste.util.template import TemplateError
-# from paste.util.datetimeutil import parse_date
-import datetime
-
-import keystone.logic.types.fault as fault
-from keystone.logic.types.fault import ForbiddenFault
-
-TEMPLATES = {}
-DEBUG = False
-TEMPLATE_PATH = ['./', './views/']
-
-
-class BaseTemplate(object):
- """ Base class and minimal API for template adapters """
- extentions = ['tpl', 'html', 'thtml', 'stpl']
- settings = {} # used in prepare()
- defaults = {} # used in render()
-
- def __init__(self, source=None, name=None, lookup=None, encoding='utf8',
- **settings):
- """ Create a new template.
- If the source parameter (str or buffer) is missing, the name argument
- is used to guess a template filename. Subclasses can assume that
- self.source and/or self.filename are set. Both are strings.
- The lookup, encoding and settings parameters are stored as instance
- variables.
- The lookup parameter stores a list containing directory paths.
- The encoding parameter should be used to decode byte strings or files.
- The settings parameter contains a dict for engine-specific settings.
- """
- lookup = lookup or []
-
- self.name = name
- self.source = source.read() if hasattr(source, 'read') else source
- self.filename = source.filename \
- if hasattr(source, 'filename') \
- else None
- self.lookup = [os.path.abspath(path) for path in lookup]
- self.encoding = encoding
- self.settings = self.settings.copy() # Copy from class variable
- self.settings.update(settings) # Apply
- if not self.source and self.name:
- self.filename = self.search(self.name, self.lookup)
- if not self.filename:
- raise TemplateError('Template %s not found' % repr(name),
- (0, 0), None)
- if not self.source and not self.filename:
- raise TemplateError('No template specified', (0, 0), None)
- self.prepare(**self.settings)
-
- @classmethod
- def search(cls, name, lookup=None):
- """ Search name in all directories specified in lookup.
- First without, then with common extensions. Return first hit. """
- lookup = lookup or []
-
- if os.path.isfile(name):
- return name
- for spath in lookup:
- fname = os.path.join(spath, name)
- if os.path.isfile(fname):
- return fname
- for ext in cls.extentions:
- if os.path.isfile('%s.%s' % (fname, ext)):
- return '%s.%s' % (fname, ext)
-
- @classmethod
- def global_config(cls, key, *args):
- '''This reads or sets the global settings stored in class.settings.'''
- if args:
- cls.settings[key] = args[0]
- else:
- return cls.settings[key]
-
- def prepare(self, **options):
- """Run preparations (parsing, caching, ...).
- It should be possible to call this again to refresh a template or to
- update settings.
- """
- raise NotImplementedError
-
- def render(self, **args):
- """Render the template with the specified local variables and return
- a single byte or unicode string. If it is a byte string, the encoding
- must match self.encoding. This method must be thread-safe!
- """
- raise NotImplementedError
-
-
-class SimpleTemplate(BaseTemplate):
- blocks = ('if', 'elif', 'else', 'try', 'except', 'finally', 'for', 'while',
- 'with', 'def', 'class')
- dedent_blocks = ('elif', 'else', 'except', 'finally')
- cache = None
- code = None
- compiled = None
- _str = None
- _escape = None
-
- def prepare(self, escape_func=cgi.escape, noescape=False):
- self.cache = {}
- if self.source:
- self.code = self.translate(self.source)
- self.compiled = compile(self.code, '<string>', 'exec')
- else:
- self.code = self.translate(open(self.filename).read())
- self.compiled = compile(self.code, self.filename, 'exec')
- enc = self.encoding
- touni = functools.partial(unicode, encoding=self.encoding)
- self._str = lambda x: touni(x, enc)
- self._escape = lambda x: escape_func(touni(x))
- if noescape:
- self._str, self._escape = self._escape, self._str
-
- def translate(self, template):
- stack = [] # Current Code indentation
- lineno = 0 # Current line of code
- ptrbuffer = [] # Buffer for printable strings and token tuples
- codebuffer = [] # Buffer for generated python code
- functools.partial(unicode, encoding=self.encoding)
- multiline = dedent = False
-
- def yield_tokens(line):
- for i, part in enumerate(re.split(r'\{\{(.*?)\}\}', line)):
- if i % 2:
- if part.startswith('!'):
- yield 'RAW', part[1:]
- else:
- yield 'CMD', part
- else:
- yield 'TXT', part
-
- def split_comment(codeline):
- """ Removes comments from a line of code. """
- line = codeline.splitlines()[0]
- try:
- tokens = list(tokenize.generate_tokens(iter(line).next))
- except tokenize.TokenError:
- return line.rsplit('#', 1) if '#' in line else (line, '')
- for token in tokens:
- if token[0] == tokenize.COMMENT:
- start, end = token[2][1], token[3][1]
- return (
- codeline[:start] + codeline[end:],
- codeline[start:end])
- return line, ''
-
- def flush():
- """Flush the ptrbuffer"""
- if not ptrbuffer:
- return
- cline = ''
- for line in ptrbuffer:
- for token, value in line:
- if token == 'TXT':
- cline += repr(value)
- elif token == 'RAW':
- cline += '_str(%s)' % value
- elif token == 'CMD':
- cline += '_escape(%s)' % value
- cline += ', '
- cline = cline[:-2] + '\\\n'
- cline = cline[:-2]
- if cline[:-1].endswith('\\\\\\\\\\n'):
- cline = cline[:-7] + cline[-1] # 'nobr\\\\\n' --> 'nobr'
- cline = '_printlist([' + cline + '])'
- del ptrbuffer[:] # Do this before calling code() again
- code(cline)
-
- def code(stmt):
- for line in stmt.splitlines():
- codebuffer.append(' ' * len(stack) + line.strip())
-
- for line in template.splitlines(True):
- lineno += 1
- line = line if isinstance(line, unicode)\
- else unicode(line, encoding=self.encoding)
- if lineno <= 2:
- m = re.search(r"%.*coding[:=]\s*([-\w\.]+)", line)
- if m:
- self.encoding = m.group(1)
- if m:
- line = line.replace('coding', 'coding (removed)')
- if line.strip()[:2].count('%') == 1:
- line = line.split('%', 1)[1].lstrip() # Rest of line after %
- cline = split_comment(line)[0].strip()
- cmd = re.split(r'[^a-zA-Z0-9_]', cline)[0]
- flush() # encodig (TODO: why?)
- if cmd in self.blocks or multiline:
- cmd = multiline or cmd
- dedent = cmd in self.dedent_blocks # "else:"
- if dedent and not multiline:
- cmd = stack.pop()
- code(line)
- oneline = not cline.endswith(':') # "if 1: pass"
- multiline = cmd if cline.endswith('\\') else False
- if not oneline and not multiline:
- stack.append(cmd)
- elif cmd == 'end' and stack:
- code('#end(%s) %s' % (stack.pop(), line.strip()[3:]))
- elif cmd == 'include':
- p = cline.split(None, 2)[1:]
- if len(p) == 2:
- code("_=_include(%s, _stdout, %s)" %
- (repr(p[0]), p[1]))
- elif p:
- code("_=_include(%s, _stdout)" % repr(p[0]))
- else: # Empty %include -> reverse of %rebase
- code("_printlist(_base)")
- elif cmd == 'rebase':
- p = cline.split(None, 2)[1:]
- if len(p) == 2:
- code("globals()['_rebase']=(%s, dict(%s))" % (
- repr(p[0]), p[1]))
- elif p:
- code("globals()['_rebase']=(%s, {})" % repr(p[0]))
- else:
- code(line)
- else: # Line starting with text (not '%') or '%%' (escaped)
- if line.strip().startswith('%%'):
- line = line.replace('%%', '%', 1)
- ptrbuffer.append(yield_tokens(line))
- flush()
- return '\n'.join(codebuffer) + '\n'
-
- def subtemplate(self, _name, _stdout, **args):
- if _name not in self.cache:
- self.cache[_name] = self.__class__(name=_name, lookup=self.lookup)
- return self.cache[_name].execute(_stdout, **args)
-
- def execute(self, _stdout, **args):
- env = self.defaults.copy()
- env.update({'_stdout': _stdout, '_printlist': _stdout.extend,
- '_include': self.subtemplate, '_str': self._str,
- '_escape': self._escape})
- env.update(args)
- eval(self.compiled, env)
- if '_rebase' in env:
- subtpl, rargs = env['_rebase']
- subtpl = self.__class__(name=subtpl, lookup=self.lookup)
- rargs['_base'] = _stdout[:] # copy stdout
- del _stdout[:] # clear stdout
- return subtpl.execute(_stdout, **rargs)
- return env
-
- def render(self, **args):
- """ Render the template using keyword arguments as local variables. """
- stdout = []
- self.execute(stdout, **args)
- return ''.join(stdout)
-
-
-def static_file(resp, req, filename, root, guessmime=True, mimetype=None,
- download=False):
- """ Opens a file in a safe way and returns a HTTPError object with status
- code 200, 305, 401 or 404. Sets Content-Type, Content-Length and
- Last-Modified header. Obeys If-Modified-Since header and HEAD requests.
- """
- root = os.path.abspath(root) + os.sep
- filename = os.path.abspath(os.path.join(root, filename.strip('/\\')))
- if not filename.startswith(root):
- return ForbiddenFault("Access denied.")
- if not os.path.exists(filename) or not os.path.isfile(filename):
- return fault.ItemNotFoundFault("File does not exist.")
- if not os.access(filename, os.R_OK):
- return ForbiddenFault(
- "You do not have permission to access this file.")
-
- if not mimetype and guessmime:
- resp.content_type = mimetypes.guess_type(filename)[0]
- else:
- resp.content_type = mimetype or 'text/plain'
-
- if download:
- download = os.path.basename(filename)
- resp.content_disposition = 'attachment; filename="%s"' % download
-
- stats = os.stat(filename)
- lm = time.strftime("%a, %d %b %Y %H:%M:%S GMT",
- time.gmtime(stats.st_mtime))
- resp.last_modified = lm
- ims = req.environ.get('HTTP_IF_MODIFIED_SINCE')
- if ims:
- ims = ims.split(";")[0].strip() # IE sends "<date>; length=146"
- try:
- ims = datetime.datetime.fromtimestamp(stats.st_mtime)
- ims = datetime.datetime.ctime(ims)
- filetime = datetime.datetime.fromtimestamp(stats.st_mtime)
- if ims is not None and ims >= filetime:
- resp.date = time.strftime(
- "%a, %d %b %Y %H:%M:%S GMT", time.gmtime())
- return Response(body=None, status=304,
- headerlist=resp.headerlist)
- except:
- # TODO(Ziad): handle this better
- pass
- resp.content_length = stats.st_size
- if req.method == 'HEAD':
- return Response(body=None, status=200, headerlist=resp.headerlist)
- else:
- return Response(body=open(filename).read(), status=200,
- headerlist=resp.headerlist)
-
-
-def template(tpl, template_adapter=SimpleTemplate, **kwargs):
- '''
- Get a rendered template as a string iterator.
- You can use a name, a filename or a template string as first parameter.
- '''
- if tpl not in TEMPLATES or DEBUG:
- settings = kwargs.get('template_settings', {})
- lookup = kwargs.get('template_lookup', TEMPLATE_PATH)
- if isinstance(tpl, template_adapter):
- TEMPLATES[tpl] = tpl
- if settings:
- TEMPLATES[tpl].prepare(**settings)
- elif "\n" in tpl or "{" in tpl or "%" in tpl or '$' in tpl:
- TEMPLATES[tpl] = template_adapter(source=tpl, lookup=lookup,
- **settings)
- else:
- TEMPLATES[tpl] = template_adapter(name=tpl, lookup=lookup,
- **settings)
- return TEMPLATES[tpl].render(**kwargs)
diff --git a/keystone/common/utils.py b/keystone/common/utils.py
new file mode 100644
index 00000000..96e595bb
--- /dev/null
+++ b/keystone/common/utils.py
@@ -0,0 +1,227 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# Copyright 2011 - 2012 Justin Santa Barbara
+# All Rights Reserved.
+#
+# 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 base64
+import hashlib
+import hmac
+import json
+import subprocess
+import sys
+import time
+import urllib
+
+import passlib.hash
+
+from keystone import config
+from keystone.common import logging
+
+
+CONF = config.CONF
+config.register_int('crypt_strength', default=40000)
+
+
+ISO_TIME_FORMAT = '%Y-%m-%dT%H:%M:%SZ'
+
+
+def import_class(import_str):
+ """Returns a class from a string including module and class."""
+ mod_str, _sep, class_str = import_str.rpartition('.')
+ try:
+ __import__(mod_str)
+ return getattr(sys.modules[mod_str], class_str)
+ except (ImportError, ValueError, AttributeError), exc:
+ logging.debug('Inner Exception: %s', exc)
+ raise
+
+
+def import_object(import_str, *args, **kw):
+ """Returns an object including a module or module and class."""
+ try:
+ __import__(import_str)
+ return sys.modules[import_str]
+ except ImportError:
+ cls = import_class(import_str)
+ return cls(*args, **kw)
+
+
+class SmarterEncoder(json.JSONEncoder):
+ """Help for JSON encoding dict-like objects."""
+ def default(self, obj):
+ if not isinstance(obj, dict) and hasattr(obj, 'iteritems'):
+ return dict(obj.iteritems())
+ return super(SmarterEncoder, self).default(obj)
+
+
+class Ec2Signer(object):
+ """Hacked up code from boto/connection.py"""
+
+ def __init__(self, secret_key):
+ secret_key = secret_key.encode()
+ self.hmac = hmac.new(secret_key, digestmod=hashlib.sha1)
+ if hashlib.sha256:
+ self.hmac_256 = hmac.new(secret_key, digestmod=hashlib.sha256)
+
+ def generate(self, credentials):
+ """Generate auth string according to what SignatureVersion is given."""
+ if credentials['params']['SignatureVersion'] == '0':
+ return self._calc_signature_0(credentials['params'])
+ if credentials['params']['SignatureVersion'] == '1':
+ return self._calc_signature_1(credentials['params'])
+ if credentials['params']['SignatureVersion'] == '2':
+ return self._calc_signature_2(credentials['params'],
+ credentials['verb'],
+ credentials['host'],
+ credentials['path'])
+ raise Exception('Unknown Signature Version: %s' %
+ credentials['params']['SignatureVersion'])
+
+ @staticmethod
+ def _get_utf8_value(value):
+ """Get the UTF8-encoded version of a value."""
+ if not isinstance(value, str) and not isinstance(value, unicode):
+ value = str(value)
+ if isinstance(value, unicode):
+ return value.encode('utf-8')
+ else:
+ return value
+
+ def _calc_signature_0(self, params):
+ """Generate AWS signature version 0 string."""
+ s = params['Action'] + params['Timestamp']
+ self.hmac.update(s)
+ return base64.b64encode(self.hmac.digest())
+
+ def _calc_signature_1(self, params):
+ """Generate AWS signature version 1 string."""
+ keys = params.keys()
+ keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
+ for key in keys:
+ self.hmac.update(key)
+ val = self._get_utf8_value(params[key])
+ self.hmac.update(val)
+ return base64.b64encode(self.hmac.digest())
+
+ def _calc_signature_2(self, params, verb, server_string, path):
+ """Generate AWS signature version 2 string."""
+ logging.debug('using _calc_signature_2')
+ string_to_sign = '%s\n%s\n%s\n' % (verb, server_string, path)
+ if self.hmac_256:
+ current_hmac = self.hmac_256
+ params['SignatureMethod'] = 'HmacSHA256'
+ else:
+ current_hmac = self.hmac
+ params['SignatureMethod'] = 'HmacSHA1'
+ keys = params.keys()
+ keys.sort()
+ pairs = []
+ for key in keys:
+ val = self._get_utf8_value(params[key])
+ val = urllib.quote(val, safe='-_~')
+ pairs.append(urllib.quote(key, safe='') + '=' + val)
+ qs = '&'.join(pairs)
+ logging.debug('query string: %s', qs)
+ string_to_sign += qs
+ logging.debug('string_to_sign: %s', string_to_sign)
+ current_hmac.update(string_to_sign)
+ b64 = base64.b64encode(current_hmac.digest())
+ logging.debug('len(b64)=%d', len(b64))
+ logging.debug('base64 encoded digest: %s', b64)
+ return b64
+
+
+def hash_password(password):
+ """Hash a password. Hard."""
+ password_utf8 = password.encode('utf-8')
+ if passlib.hash.sha512_crypt.identify(password_utf8):
+ return password_utf8
+ h = passlib.hash.sha512_crypt.encrypt(password_utf8,
+ rounds=CONF.crypt_strength)
+ return h
+
+
+def check_password(password, hashed):
+ """Check that a plaintext password matches hashed.
+
+ hashpw returns the salt value concatenated with the actual hash value.
+ It extracts the actual salt if this value is then passed as the salt.
+
+ """
+ if password is None:
+ return False
+ password_utf8 = password.encode('utf-8')
+ return passlib.hash.sha512_crypt.verify(password_utf8, hashed)
+
+
+# From python 2.7
+def check_output(*popenargs, **kwargs):
+ r"""Run command with arguments and return its output as a byte string.
+
+ If the exit code was non-zero it raises a CalledProcessError. The
+ CalledProcessError object will have the return code in the returncode
+ attribute and output in the output attribute.
+
+ The arguments are the same as for the Popen constructor. Example:
+
+ >>> check_output(['ls', '-l', '/dev/null'])
+ 'crw-rw-rw- 1 root root 1, 3 Oct 18 2007 /dev/null\n'
+
+ The stdout argument is not allowed as it is used internally.
+ To capture standard error in the result, use stderr=STDOUT.
+
+ >>> check_output(['/bin/sh', '-c',
+ ... 'ls -l non_existent_file ; exit 0'],
+ ... stderr=STDOUT)
+ 'ls: non_existent_file: No such file or directory\n'
+ """
+ if 'stdout' in kwargs:
+ raise ValueError('stdout argument not allowed, it will be overridden.')
+ logging.debug(' '.join(popenargs[0]))
+ process = subprocess.Popen(stdout=subprocess.PIPE, *popenargs, **kwargs)
+ output, unused_err = process.communicate()
+ retcode = process.poll()
+ if retcode:
+ cmd = kwargs.get('args')
+ if cmd is None:
+ cmd = popenargs[0]
+ raise subprocess.CalledProcessError(retcode, cmd)
+ return output
+
+
+def git(*args):
+ return check_output(['git'] + list(args))
+
+
+def isotime(dt_obj):
+ """Format datetime object as ISO compliant string.
+
+ :param dt_obj: datetime.datetime object
+ :returns: string representation of datetime object
+
+ """
+ return dt_obj.strftime(ISO_TIME_FORMAT)
+
+
+def unixtime(dt_obj):
+ """Format datetime object as unix timestamp
+
+ :param dt_obj: datetime.datetime object
+ :returns: float
+
+ """
+ return time.mktime(dt_obj.utctimetuple())
diff --git a/keystone/common/wsgi.py b/keystone/common/wsgi.py
index c3ce7975..7b6926d0 100755..100644
--- a/keystone/common/wsgi.py
+++ b/keystone/common/wsgi.py
@@ -17,102 +17,60 @@
# License for the specific language governing permissions and limitations
# under the License.
-# pylint: disable=W0613
-"""
-Utility methods for working with WSGI servers
-"""
+"""Utility methods for working with WSGI servers."""
import json
import logging
import sys
-import datetime
-import ssl
+import eventlet
import eventlet.wsgi
-eventlet.patcher.monkey_patch(all=False, socket=True)
+eventlet.patcher.monkey_patch(all=False, socket=True, time=True)
+import routes
import routes.middleware
-from webob import Response
+import webob
import webob.dec
+import webob.exc
-LOG = logging.getLogger(__name__)
-
-
-def find_console_handler(logger):
- """Returns a stream handler, if any"""
- for handler in logger.handlers:
- if isinstance(handler, logging.StreamHandler) and \
- handler.stream == sys.stderr:
- return handler
-
-
-def add_console_handler(logger, level=logging.INFO):
- """
- Add a Handler which writes log messages to sys.stderr (usually the console)
- """
- console = find_console_handler(logger)
-
- if not console:
- console = logging.StreamHandler()
- console.setLevel(level)
- # set a format which is simpler for console use
- formatter = logging.Formatter(
- "%(name)-12s: %(levelname)-8s %(message)s")
- # tell the handler to use this format
- console.setFormatter(formatter)
- # add the handler to the root logger
- LOG.debug("Adding console handler at level %s" % level)
- logger.addHandler(console)
- elif console.level != level:
- LOG.debug("Setting console handler level to %s from %s" % (level,
- console.level))
- console.setLevel(level)
- return console
+from keystone import exception
+from keystone.common import utils
class WritableLogger(object):
"""A thin wrapper that responds to `write` and logs."""
- def __init__(self, logger, level=logging.INFO):
+ def __init__(self, logger, level=logging.DEBUG):
self.logger = logger
self.level = level
- if level == logging.DEBUG:
- add_console_handler(logger, level)
def write(self, msg):
- self.logger.log(self.level, msg.strip("\n"))
-
-
-def run_server(application, port):
- """Run a WSGI server with the given application."""
- LOG.debug("Running WSGI server on 0.0.0.0:%s" % port)
- sock = eventlet.listen(('0.0.0.0', port))
- eventlet.wsgi.server(sock, application)
+ self.logger.log(self.level, msg)
class Server(object):
"""Server class to manage multiple WSGI sockets and applications."""
- started = False
- def __init__(self, application=None, port=None, threads=1000):
+ def __init__(self, application, port, threads=1000):
self.application = application
self.port = port
self.pool = eventlet.GreenPool(threads)
self.socket_info = {}
- self.threads = {}
+ self.greenthread = None
- def start(self, application=None, port=None, host='0.0.0.0', key=None,
- backlog=128):
+ def start(self, host='0.0.0.0', key=None, backlog=128):
"""Run a WSGI server with the given application."""
- if application is not None:
- self.application = application
- if port is not None:
- self.port = port
- LOG.debug("start server '%s' on %s:%s" % (key, host, self.port))
+ logging.debug('Starting %(arg0)s on %(host)s:%(port)s' % \
+ {'arg0': sys.argv[0],
+ 'host': host,
+ 'port': self.port})
socket = eventlet.listen((host, self.port), backlog=backlog)
- thread = self.pool.spawn(self._run, self.application, socket)
+ self.greenthread = self.pool.spawn(self._run, self.application, socket)
if key:
- self.socket_info[key] = socket
- self.threads[key] = thread
+ self.socket_info[key] = socket.getsockname()
+
+ def kill(self):
+ if self.greenthread:
+ self.greenthread.kill()
def wait(self):
"""Wait until all servers have completed running."""
@@ -123,50 +81,189 @@ class Server(object):
def _run(self, application, socket):
"""Start a WSGI server in a new green thread."""
- LOG.debug("_run called")
- eventlet_logger = logging.getLogger('eventlet.wsgi.server')
+ logger = logging.getLogger('eventlet.wsgi.server')
eventlet.wsgi.server(socket, application, custom_pool=self.pool,
- log=WritableLogger(eventlet_logger, logging.root.level))
-
-
-class SslServer(Server):
- """SSL Server class to manage multiple WSGI sockets and applications."""
- # pylint: disable=W0221,R0913
- def start(self, application, port, host='0.0.0.0', backlog=128,
- certfile=None, keyfile=None, ca_certs=None,
- cert_required='True', key=None):
- """Run a 2-way SSL WSGI server with the given application."""
- LOG.debug("start SSL server '%s' on %s:%s" % (key, host, port))
- socket = eventlet.listen((host, port), backlog=backlog)
- if cert_required == 'True':
- cert_reqs = ssl.CERT_REQUIRED
- else:
- cert_reqs = ssl.CERT_NONE
- sslsocket = eventlet.wrap_ssl(socket, certfile=certfile,
- keyfile=keyfile,
- server_side=True, cert_reqs=cert_reqs,
- ca_certs=ca_certs)
- thread = self.pool.spawn(self._run, application, sslsocket)
- if key:
- self.socket_info[key] = sslsocket
- self.threads[key] = thread
+ log=WritableLogger(logger))
-class Middleware(object):
- """
- Base WSGI middleware wrapper. These classes require an application to be
+class Request(webob.Request):
+ pass
+
+
+class BaseApplication(object):
+ """Base WSGI application wrapper. Subclasses need to implement __call__."""
+
+ @classmethod
+ def factory(cls, global_config, **local_config):
+ """Used for paste app factories in paste.deploy config files.
+
+ Any local configuration (that is, values under the [app:APPNAME]
+ section of the paste config) will be passed into the `__init__` method
+ as kwargs.
+
+ A hypothetical configuration would look like:
+
+ [app:wadl]
+ latest_version = 1.3
+ paste.app_factory = nova.api.fancy_api:Wadl.factory
+
+ which would result in a call to the `Wadl` class as
+
+ import nova.api.fancy_api
+ fancy_api.Wadl(latest_version='1.3')
+
+ You could of course re-implement the `factory` method in subclasses,
+ but using the kwarg passing it shouldn't be necessary.
+
+ """
+ return cls()
+
+ def __call__(self, environ, start_response):
+ r"""Subclasses will probably want to implement __call__ like this:
+
+ @webob.dec.wsgify(RequestClass=Request)
+ def __call__(self, req):
+ # Any of the following objects work as responses:
+
+ # Option 1: simple string
+ res = 'message\n'
+
+ # Option 2: a nicely formatted HTTP exception page
+ res = exc.HTTPForbidden(detail='Nice try')
+
+ # Option 3: a webob Response object (in case you need to play with
+ # headers, or you want to be treated like an iterable, or or or)
+ res = Response();
+ res.app_iter = open('somefile')
+
+ # Option 4: any wsgi app to be run next
+ res = self.application
+
+ # Option 5: you can get a Response object for a wsgi app, too, to
+ # play with headers etc
+ res = req.get_response(self.application)
+
+ # You can then just return your response...
+ return res
+ # ... or set req.response and return None.
+ req.response = res
+
+ See the end of http://pythonpaste.org/webob/modules/dec.html
+ for more info.
+
+ """
+ raise NotImplementedError('You must implement __call__')
+
+
+class Application(BaseApplication):
+ @webob.dec.wsgify
+ def __call__(self, req):
+ arg_dict = req.environ['wsgiorg.routing_args'][1]
+ action = arg_dict.pop('action')
+ del arg_dict['controller']
+ logging.debug('arg_dict: %s', arg_dict)
+
+ # allow middleware up the stack to provide context & params
+ context = req.environ.get('openstack.context', {})
+ context['query_string'] = dict(req.params.iteritems())
+ params = req.environ.get('openstack.params', {})
+ params.update(arg_dict)
+
+ # TODO(termie): do some basic normalization on methods
+ method = getattr(self, action)
+
+ # NOTE(vish): make sure we have no unicode keys for py2.6.
+ params = self._normalize_dict(params)
+
+ try:
+ result = method(context, **params)
+ except exception.Error as e:
+ logging.warning(e)
+ return render_exception(e)
+
+ if result is None or type(result) is str or type(result) is unicode:
+ return result
+ elif isinstance(result, webob.exc.WSGIHTTPException):
+ return result
+
+ response = webob.Response()
+ self._serialize(response, result)
+ return response
+
+ def _serialize(self, response, result):
+ response.content_type = 'application/json'
+ response.body = json.dumps(result, cls=utils.SmarterEncoder)
+
+ def _normalize_arg(self, arg):
+ return str(arg).replace(':', '_').replace('-', '_')
+
+ def _normalize_dict(self, d):
+ return dict([(self._normalize_arg(k), v)
+ for (k, v) in d.iteritems()])
+
+ def assert_admin(self, context):
+ if not context['is_admin']:
+ try:
+ user_token_ref = self.token_api.get_token(
+ context=context, token_id=context['token_id'])
+ except exception.TokenNotFound:
+ raise exception.Unauthorized()
+ creds = user_token_ref['metadata'].copy()
+ creds['user_id'] = user_token_ref['user'].get('id')
+ creds['tenant_id'] = user_token_ref['tenant'].get('id')
+ # NOTE(vish): this is pretty inefficient
+ creds['roles'] = [self.identity_api.get_role(context, role)['name']
+ for role in creds.get('roles', [])]
+ # Accept either is_admin or the admin role
+ assert self.policy_api.can_haz(context,
+ ('is_admin:1', 'roles:admin'),
+ creds)
+
+
+class Middleware(Application):
+ """Base WSGI middleware.
+
+ These classes require an application to be
initialized that will be called next. By default the middleware will
simply call its wrapped app, or you can override __call__ to customize its
behavior.
+
"""
+ @classmethod
+ def factory(cls, global_config, **local_config):
+ """Used for paste app factories in paste.deploy config files.
+
+ Any local configuration (that is, values under the [filter:APPNAME]
+ section of the paste config) will be passed into the `__init__` method
+ as kwargs.
+
+ A hypothetical configuration would look like:
+
+ [filter:analytics]
+ redis_host = 127.0.0.1
+ paste.filter_factory = nova.api.analytics:Analytics.factory
+
+ which would result in a call to the `Analytics` class as
+
+ import nova.api.analytics
+ analytics.Analytics(app_from_paste, redis_host='127.0.0.1')
+
+ You could of course re-implement the `factory` method in subclasses,
+ but using the kwarg passing it shouldn't be necessary.
+
+ """
+ def _factory(app):
+ conf = global_config.copy()
+ conf.update(local_config)
+ return cls(app)
+ return _factory
+
def __init__(self, application):
self.application = application
- @staticmethod
- def process_request(req):
- """
- Called on each request.
+ def process_request(self, req):
+ """Called on each request.
If this returns None, the next application down the stack will be
executed. If it returns a response then that response will be returned
@@ -175,13 +272,11 @@ class Middleware(object):
"""
return None
- @staticmethod
- def process_response(response):
+ def process_response(self, response):
"""Do whatever you'd like to the response."""
return response
- # pylint: disable=W1111
- @webob.dec.wsgify
+ @webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
response = self.process_request(req)
if response:
@@ -191,23 +286,30 @@ class Middleware(object):
class Debug(Middleware):
- """
- Helper class that can be inserted into any WSGI application chain
- to get information about the request and response.
+ """Helper class for debugging a WSGI application.
+
+ Can be inserted into any WSGI application chain to get information
+ about the request and response.
+
"""
- @webob.dec.wsgify
+ @webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
- print ("*" * 40) + " REQUEST ENVIRON"
+ logging.debug('%s %s %s', ('*' * 20), 'REQUEST ENVIRON', ('*' * 20))
for key, value in req.environ.items():
- print key, "=", value
- print
+ logging.debug('%s = %s', key, value)
+ logging.debug('')
+ logging.debug('%s %s %s', ('*' * 20), 'REQUEST BODY', ('*' * 20))
+ for line in req.body_file:
+ logging.debug(line)
+ logging.debug('')
+
resp = req.get_response(self.application)
- print ("*" * 40) + " RESPONSE HEADERS"
+ logging.debug('%s %s %s', ('*' * 20), 'RESPONSE HEADERS', ('*' * 20))
for (key, value) in resp.headers.iteritems():
- print key, "=", value
- print
+ logging.debug('%s = %s', key, value)
+ logging.debug('')
resp.app_iter = self.print_generator(resp.app_iter)
@@ -215,283 +317,158 @@ class Debug(Middleware):
@staticmethod
def print_generator(app_iter):
- """
- Iterator that prints the contents of a wrapper string iterator
- when iterated.
- """
- print ("*" * 40) + " BODY"
+ """Iterator that prints the contents of a wrapper string."""
+ logging.debug('%s %s %s', ('*' * 20), 'RESPONSE BODY', ('*' * 20))
for part in app_iter:
- sys.stdout.write(part)
- sys.stdout.flush()
+ #sys.stdout.write(part)
+ logging.debug(part)
+ #sys.stdout.flush()
yield part
print
-def debug_filter_factory(global_conf):
- """Filter factor to easily insert a debugging middleware into the
- paste.deploy pipeline"""
- def filter(app):
- return Debug(app)
- return filter
-
-
class Router(object):
- """
- WSGI middleware that maps incoming requests to WSGI apps.
- """
+ """WSGI middleware that maps incoming requests to WSGI apps."""
def __init__(self, mapper):
- """
- Create a router for the given routes.Mapper.
+ """Create a router for the given routes.Mapper.
Each route in `mapper` must specify a 'controller', which is a
WSGI app to call. You'll probably want to specify an 'action' as
- well and have your controller be a wsgi.Controller, who will route
- the request to the action method.
+ well and have your controller be an object that can route
+ the request to the action-specific method.
Examples:
mapper = routes.Mapper()
sc = ServerController()
# Explicit mapping of one route to a controller+action
- mapper.connect(None, "/svrlist", controller=sc, action="list")
+ mapper.connect(None, '/svrlist', controller=sc, action='list')
# Actions are all implicitly defined
- mapper.resource("server", "servers", controller=sc)
+ mapper.resource('server', 'servers', controller=sc)
# Pointing to an arbitrary WSGI app. You can specify the
# {path_info:.*} parameter so the target app can be handed just that
# section of the URL.
- mapper.connect(None, "/v2.0/{path_info:.*}", controller=TheApp())
+ mapper.connect(None, '/v1.0/{path_info:.*}', controller=BlogApp())
+
"""
self.map = mapper
self._router = routes.middleware.RoutesMiddleware(self._dispatch,
self.map)
- @webob.dec.wsgify
+ @webob.dec.wsgify(RequestClass=Request)
def __call__(self, req):
- """
- Route the incoming request to a controller based on self.map.
+ """Route the incoming request to a controller based on self.map.
+
If no match, return a 404.
+
"""
return self._router
@staticmethod
- @webob.dec.wsgify
+ @webob.dec.wsgify(RequestClass=Request)
def _dispatch(req):
- """
+ """Dispatch the request to the appropriate controller.
+
Called by self._router after matching the incoming request to a route
- and putting the information into req.environ. Returns the routed
- WSGI app's response or an Accept-appropriate 404.
+ and putting the information into req.environ. Either returns 404
+ or the routed WSGI app's response.
+
"""
- return req.environ['wsgiorg.routing_args'][1].get('controller') \
- or HTTPNotFound()
+ match = req.environ['wsgiorg.routing_args'][1]
+ if not match:
+ return webob.exc.HTTPNotFound()
+ app = match['controller']
+ return app
-class Controller(object):
- """
- WSGI app that reads routing information supplied by RoutesMiddleware
- and calls the requested action method upon itself. All action methods
- must, in addition to their normal parameters, accept a 'req' argument
- which is the incoming webob.Request. They raise a webob.exc exception,
- or return a dict which will be serialized by requested content type.
- """
+class ComposingRouter(Router):
+ def __init__(self, mapper=None, routers=None):
+ if mapper is None:
+ mapper = routes.Mapper()
+ if routers is None:
+ routers = []
+ for router in routers:
+ router.add_routes(mapper)
+ super(ComposingRouter, self).__init__(mapper)
- @webob.dec.wsgify
- def __call__(self, req):
- """
- Call the method specified in req.environ by RoutesMiddleware.
- """
- arg_dict = req.environ['wsgiorg.routing_args'][1]
- action = arg_dict['action']
- method = getattr(self, action)
- del arg_dict['controller']
- del arg_dict['action']
- arg_dict['req'] = req
- result = method(**arg_dict)
- if isinstance(result, dict):
- return self._serialize(result, req)
- else:
- return result
- def _serialize(self, data, request):
- """
- Serialize the given dict to the response type requested in request.
- Uses self._serialization_metadata if it exists, which is a dict mapping
- MIME types to information needed to serialize to that type.
- """
- _metadata = getattr(type(self), "_serialization_metadata", {})
- serializer = Serializer(request.environ, _metadata)
- return serializer.to_content_type(data)
+class ComposableRouter(Router):
+ """Router that supports use by ComposingRouter."""
+ def __init__(self, mapper=None):
+ if mapper is None:
+ mapper = routes.Mapper()
+ self.add_routes(mapper)
+ super(ComposableRouter, self).__init__(mapper)
-class Serializer(object):
- """
- Serializes a dictionary to a Content Type specified by a WSGI environment.
+ def add_routes(self, mapper):
+ """Add routes to given mapper."""
+ pass
+
+
+class ExtensionRouter(Router):
+ """A router that allows extensions to supplement or overwrite routes.
+
+ Expects to be subclassed.
"""
+ def __init__(self, application, mapper=None):
+ if mapper is None:
+ mapper = routes.Mapper()
+ self.application = application
+ self.add_routes(mapper)
+ mapper.connect('{path_info:.*}', controller=self.application)
+ super(ExtensionRouter, self).__init__(mapper)
- def __init__(self, environ, metadata=None):
- """
- Create a serializer based on the given WSGI environment.
- 'metadata' is an optional dict mapping MIME types to information
- needed to serialize a dictionary to that type.
- """
- if metadata is None:
- metadata = {}
- self.environ = environ
- self.metadata = metadata
- self._methods = {
- 'application/json': self._to_json,
- 'application/xml': self._to_xml}
-
- def to_content_type(self, data):
- """
- Serialize a dictionary into a string. The format of the string
- will be decided based on the Content Type requested in self.environ:
- by Accept: header, or by URL suffix.
- """
- # FIXME(sirp): for now, supporting json only
- #mimetype = 'application/xml'
- mimetype = 'application/json'
- LOG.debug("serializing: mimetype=%s" % mimetype)
- # TODO(gundlach): determine mimetype from request
- return self._methods.get(mimetype, repr)(data)
+ def add_routes(self, mapper):
+ pass
- @staticmethod
- def _to_json(data):
- def sanitizer(obj):
- if isinstance(obj, datetime.datetime):
- return obj.isoformat()
- return obj
-
- return json.dumps(data, default=sanitizer)
-
- def _to_xml(self, data):
- metadata = self.metadata.get('application/xml', {})
- # We expect data to contain a single key which is the XML root.
- root_key = data.keys()[0]
- from xml.dom import minidom
- doc = minidom.Document()
- node = self._to_xml_node(doc, metadata, root_key, data[root_key])
- return node.toprettyxml(indent=' ')
-
- def _to_xml_node(self, doc, metadata, nodename, data):
- """Recursive method to convert data members to XML nodes."""
- result = doc.createElement(nodename)
- if isinstance(data, list):
- singular = metadata.get('plurals', {}).get(nodename, None)
- if singular is None:
- if nodename.endswith('s'):
- singular = nodename[:-1]
- else:
- singular = 'item'
- for item in data:
- node = self._to_xml_node(doc, metadata, singular, item)
- result.appendChild(node)
- elif isinstance(data, dict):
- attrs = metadata.get('attributes', {}).get(nodename, {})
- for k, v in data.items():
- if k in attrs:
- result.setAttribute(k, str(v))
- else:
- node = self._to_xml_node(doc, metadata, k, v)
- result.appendChild(node)
- else: # atom
- node = doc.createTextNode(str(data))
- result.appendChild(node)
- return result
-
-
-class WSGIHTTPException(Response, webob.exc.HTTPException):
- """Returned when no matching route can be identified"""
-
- code = None
- label = None
- title = None
- explanation = None
-
- xml_template = """\
-<?xml version="1.0" encoding="UTF-8"?>
-<%s xmlns="http://docs.openstack.org/identity/api/v2.0" code="%s">
- <message>%s</message>
- <details>%s</details>
-</%s>"""
-
- def __init__(self, code, label, title, explanation, **kw):
- self.code = code
- self.label = label
- self.title = title
- self.explanation = explanation
-
- Response.__init__(self, status='%s %s' % (self.code, self.title), **kw)
- webob.exc.HTTPException.__init__(self, self.explanation, self)
-
- def xml_body(self):
- """Generate a XML body string using the available data"""
- return self.xml_template % (
- self.label, self.code, self.title, self.explanation, self.label)
-
- def json_body(self):
- """Generate a JSON body string using the available data"""
- json_dict = {self.label: {}}
- json_dict[self.label]['message'] = self.title
- json_dict[self.label]['details'] = self.explanation
- json_dict[self.label]['code'] = self.code
-
- return json.dumps(json_dict)
-
- def generate_response(self, environ, start_response):
- """Returns a response to the given environment"""
- if self.content_length is not None:
- del self.content_length
-
- headerlist = list(self.headerlist)
-
- accept = environ.get('HTTP_ACCEPT', '')
-
- # Return JSON by default
- if accept and 'xml' in accept:
- content_type = 'application/xml'
- body = self.xml_body()
- else:
- content_type = 'application/json'
- body = self.json_body()
-
- extra_kw = {}
-
- if isinstance(body, unicode):
- extra_kw.update(charset='utf-8')
-
- resp = Response(body,
- status=self.status,
- headerlist=headerlist,
- content_type=content_type,
- **extra_kw)
-
- # Why is this repeated?
- resp.content_type = content_type
-
- return resp(environ, start_response)
+ @classmethod
+ def factory(cls, global_config, **local_config):
+ """Used for paste app factories in paste.deploy config files.
- def __call__(self, environ, start_response):
- if environ['REQUEST_METHOD'] == 'HEAD':
- start_response(self.status, self.headerlist)
- return []
- if not self.body:
- return self.generate_response(environ, start_response)
- return webob.Response.__call__(self, environ, start_response)
-
- def exception(self):
- """Returns self as an exception response"""
- return webob.exc.HTTPException(self.explanation, self)
-
- exception = property(exception)
-
-
-class HTTPNotFound(WSGIHTTPException):
- """Represents a 404 Not Found webob response exception"""
- def __init__(self, code=404, label='itemNotFound', title='Item not found.',
- explanation='Error Details...', **kw):
- """Build a 404 WSGI response"""
- super(HTTPNotFound, self).__init__(code, label, title, explanation,
- **kw)
+ Any local configuration (that is, values under the [filter:APPNAME]
+ section of the paste config) will be passed into the `__init__` method
+ as kwargs.
+
+ A hypothetical configuration would look like:
+
+ [filter:analytics]
+ redis_host = 127.0.0.1
+ paste.filter_factory = nova.api.analytics:Analytics.factory
+
+ which would result in a call to the `Analytics` class as
+
+ import nova.api.analytics
+ analytics.Analytics(app_from_paste, redis_host='127.0.0.1')
+
+ You could of course re-implement the `factory` method in subclasses,
+ but using the kwarg passing it shouldn't be necessary.
+
+ """
+ def _factory(app):
+ conf = global_config.copy()
+ conf.update(local_config)
+ return cls(app)
+ return _factory
+
+
+def render_exception(error):
+ """Forms a WSGI response based on the current error."""
+ resp = webob.Response()
+ resp.status = '%s %s' % (error.code, error.title)
+ resp.headerlist = [('Content-Type', 'application/json')]
+
+ body = {
+ 'error': {
+ 'code': error.code,
+ 'title': error.title,
+ 'message': str(error),
+ }
+ }
+
+ resp.body = json.dumps(body)
+
+ return resp
diff --git a/keystone/config.py b/keystone/config.py
index 977c3df3..e95efe42 100644
--- a/keystone/config.py
+++ b/keystone/config.py
@@ -1,41 +1,22 @@
-#!/usr/bin/env python
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Routines for configuring OpenStack Service
-"""
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
import gettext
-import logging
-import logging.config
-import logging.handlers
import sys
import os
-from keystone import cfg
+from keystone.common import cfg
+from keystone.common import logging
-gettext.install("keystone", unicode=1)
+gettext.install('keystone', unicode=1)
-class Config(cfg.CommonConfigOpts):
- def __call__(self, config_files=None):
+class ConfigMixin(object):
+ def __call__(self, config_files=None, *args, **kw):
if config_files is not None:
- self._opts["config_file"]["opt"].default = config_files
- return super(Config, self).__call__()
+ self._opts['config_file']['opt'].default = config_files
+ kw.setdefault('args', [])
+ return super(ConfigMixin, self).__call__(*args, **kw)
def __getitem__(self, key, default=None):
return getattr(self, key, default)
@@ -44,21 +25,23 @@ class Config(cfg.CommonConfigOpts):
return setattr(self, key, value)
def iteritems(self):
- for key in self._opts:
- yield (key, getattr(self, key))
-
- def to_dict(self):
- """ Returns a representation of the CONF settings as a dict."""
- ret = {}
- for key, val in self.iteritems():
- if val is not None:
- ret[key] = val
- for grp_name in self._groups:
- ret[grp_name] = grp_dict = {}
- grp = self._get_group(grp_name)
- for opt in grp._opts: # pylint: disable=W0212
- grp_dict[opt] = self._get(opt, grp_name)
- return ret
+ for k in self._opts:
+ yield (k, getattr(self, k))
+
+ def print_help(self):
+ self._oparser.print_help()
+
+ def set_usage(self, usage):
+ self.usage = usage
+ self._oparser.usage = usage
+
+
+class Config(ConfigMixin, cfg.ConfigOpts):
+ pass
+
+
+class CommonConfig(ConfigMixin, cfg.CommonConfigOpts):
+ pass
def setup_logging(conf):
@@ -67,15 +50,16 @@ def setup_logging(conf):
:param conf: a cfg.ConfOpts object
"""
+
if conf.log_config:
# Use a logging configuration file for all settings...
- for location in (sys.argv[0], "."):
- pth = os.path.join(location, "etc", conf.log_config)
- if os.path.exists(pth):
- logging.config.fileConfig(pth)
- return
- raise RuntimeError("Unable to locate specified logging "
- "config file: %s" % conf.log_config)
+ if os.path.exists(conf.log_config):
+ logging.config.fileConfig(conf.log_config)
+ return
+ else:
+ raise RuntimeError('Unable to locate specified logging '
+ 'config file: %s' % conf.log_config)
+
root_logger = logging.root
if conf.debug:
root_logger.setLevel(logging.DEBUG)
@@ -83,94 +67,92 @@ def setup_logging(conf):
root_logger.setLevel(logging.INFO)
else:
root_logger.setLevel(logging.WARNING)
+
formatter = logging.Formatter(conf.log_format, conf.log_date_format)
if conf.use_syslog:
try:
- facility = getattr(logging.handlers.SysLogHandler,
+ facility = getattr(logging.SysLogHandler,
conf.syslog_log_facility)
except AttributeError:
- raise ValueError(_("Invalid syslog facility"))
+ raise ValueError(_('Invalid syslog facility'))
- handler = logging.handlers.SysLogHandler(address="/dev/log",
+ handler = logging.SysLogHandler(address='/dev/log',
facility=facility)
elif conf.log_file:
logfile = conf.log_file
if conf.log_dir:
logfile = os.path.join(conf.log_dir, logfile)
- handler = logging.handlers.WatchedFileHandler(logfile)
+ handler = logging.WatchedFileHandler(logfile)
else:
handler = logging.StreamHandler(sys.stdout)
+
handler.setFormatter(formatter)
root_logger.addHandler(handler)
def register_str(*args, **kw):
- group = _ensure_group(kw)
- return CONF.register_opt(cfg.StrOpt(*args, **kw), group=group)
+ conf = kw.pop('conf', CONF)
+ group = _ensure_group(kw, conf)
+ return conf.register_opt(cfg.StrOpt(*args, **kw), group=group)
def register_cli_str(*args, **kw):
- group = _ensure_group(kw)
- return CONF.register_opt(cfg.StrOpt(*args, **kw), group=group)
+ conf = kw.pop('conf', CONF)
+ group = _ensure_group(kw, conf)
+ return conf.register_cli_opt(cfg.StrOpt(*args, **kw), group=group)
def register_bool(*args, **kw):
- group = _ensure_group(kw)
- return CONF.register_opt(cfg.BoolOpt(*args, **kw), group=group)
+ conf = kw.pop('conf', CONF)
+ group = _ensure_group(kw, conf)
+ return conf.register_opt(cfg.BoolOpt(*args, **kw), group=group)
def register_cli_bool(*args, **kw):
- group = _ensure_group(kw)
- return CONF.register_cli_opt(cfg.BoolOpt(*args, **kw), group=group)
+ conf = kw.pop('conf', CONF)
+ group = _ensure_group(kw, conf)
+ return conf.register_cli_opt(cfg.BoolOpt(*args, **kw), group=group)
-def register_list(*args, **kw):
- group = _ensure_group(kw)
- return CONF.register_opt(cfg.ListOpt(*args, **kw), group=group)
+def register_int(*args, **kw):
+ conf = kw.pop('conf', CONF)
+ group = _ensure_group(kw, conf)
+ return conf.register_opt(cfg.IntOpt(*args, **kw), group=group)
-def register_multi_string(*args, **kw):
- group = _ensure_group(kw)
- return CONF.register_opt(cfg.MultiStrOpt(*args, **kw), group=group)
+def register_cli_int(*args, **kw):
+ conf = kw.pop('conf', CONF)
+ group = _ensure_group(kw, conf)
+ return conf.register_cli_opt(cfg.IntOpt(*args, **kw), group=group)
-def _ensure_group(kw):
- group = kw.pop("group", None)
+def _ensure_group(kw, conf):
+ group = kw.pop('group', None)
if group:
- CONF.register_group(cfg.OptGroup(name=group))
+ conf.register_group(cfg.OptGroup(name=group))
return group
-CONF = Config(project="keystone")
-
-register_str("default_store")
-register_str("service_header_mappings")
-register_list("extensions")
-register_str("service_host")
-register_str("service_port")
-register_bool("service_ssl")
-register_str("admin_host")
-register_str("admin_port")
-register_bool("admin_ssl")
-register_str("bind_host")
-register_str("bind_port")
-register_str("certfile")
-register_str("keyfile")
-register_str("ca_certs")
-register_bool("cert_required")
-register_str("keystone_admin_role")
-register_str("keystone_service_admin_role")
-register_bool("hash_password")
-register_str("backends")
-register_str("global_service_id")
-register_bool("disable_tokens_in_url")
-
-register_str("sql_connection", group="keystone.backends.sqlalchemy")
-register_str("backend_entities", group="keystone.backends.sqlalchemy")
-register_str("sql_idle_timeout", group="keystone.backends.sqlalchemy")
-# May need to initialize other backends, too.
-register_str("ldap_url", group="keystone.backends.ldap")
-register_str("ldap_user", group="keystone.backends.ldap")
-register_str("ldap_password", group="keystone.backends.ldap")
-register_list("backend_entities", group="kkeystone.backends.ldap")
+CONF = CommonConfig(project='keystone')
+
+
+register_str('admin_token', default='ADMIN')
+register_str('compute_port')
+register_str('admin_port')
+register_str('public_port')
+
+
+# sql options
+register_str('connection', group='sql')
+register_str('idle_timeout', group='sql')
+register_str('min_pool_size', group='sql')
+register_str('maz_pool_size', group='sql')
+register_str('pool_timeout', group='sql')
+
+
+register_str('driver', group='catalog')
+register_str('driver', group='identity')
+register_str('driver', group='policy')
+register_str('driver', group='token')
+register_str('driver', group='ec2')
diff --git a/keystone/content/admin/HP-IDM-admin-devguide.pdf b/keystone/content/admin/HP-IDM-admin-devguide.pdf
deleted file mode 100644
index 7ab314ac..00000000
--- a/keystone/content/admin/HP-IDM-admin-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/admin/HP-IDM-admin.wadl b/keystone/content/admin/HP-IDM-admin.wadl
deleted file mode 100644
index 4fcb25d4..00000000
--- a/keystone/content/admin/HP-IDM-admin.wadl
+++ /dev/null
@@ -1,150 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent HP-IDM-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "https://raw.github.com/openstack/keystone/master/keystone/content/common/common.ent">
- %common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:HP-IDM="http://docs.openstack.org/identity/api/ext/HP-IDM/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0">
-
- <grammars>
- <include href="https://raw.github.com/openstack/keystone/master/keystone/content/common/xsd/api.xsd"/>
- <include href="https://raw.github.com/openstack/keystone/master/keystone/content/common/xsd/api-common.xsd"/>
- </grammars>
-
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <resource id="tokens" path="tokens">
- <resource id="tokenById" path="{tokenId}">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <param name="tokenId" style="template" type="xsd:string" required="true"/>
- <param name="belongsTo" style="query" type="xsd:string" required="false"/>
- <param name="HP-IDM-serviceId" style="query" type="xsd:string" required="false"/>
- <method href="#validateToken"/>
- <method href="#checkToken"/>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
-
- <!-- Token Operations -->
- <method name="GET" id="validateToken">
- <doc xml:lang="EN" title="Validate Token">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Check that a token is valid and that it belongs to a supplied tenant
- and services and return the permissions relevant to a particular client.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Valid tokens will exist in the
- <code>/tokens/{tokenId}</code> path and invalid
- tokens will not. In other words, a user should expect an
- itemNotFound (<code>404</code>) fault for an
- invalid token.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- If 'HP-IDM-serviceId' is provided, it must be a comma-separated string of
- service IDs. If any of the service IDs is invalid or if there are no
- roles associated with the service IDs, a user should expect a 401.
- </p>
- </doc>
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Validates a token has the supplied tenant in scope.
- </p>
- </doc>
- </param>
- <param name="HP-IDM-serviceId" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- If provided, filter the roles to be returned by the given service IDs.
- </p>
- </doc>
- </param>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:access">
- <doc>
- <xsdxt:code href="../samples/validatetoken.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../samples/validatetoken.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="HEAD" id="checkToken">
- <doc xml:lang="EN" title="Check Token">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Check that a token is valid and that it belongs to a particular tenant and services
- (For performance).
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Valid tokens will exist in the
- <code>/tokens/{tokenId}</code> path and invalid
- tokens will not. In other words, a user should expect an
- itemNotFound (<code>404</code>) fault for an
- invalid token.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- If `belongsTo` is provided, validates that a token has a specific tenant in scope.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- If 'HP-IDM-serviceId' is provided, it must be a comma-separated string of
- service IDs. If any of the service ID is invalid or if there are no
- roles associated with the service IDs, a user should expect a 401.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- No response body is returned for this method.
- </p>
- </doc>
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Validates a token has the supplied tenant in scope. (for performance).
- </p>
- </doc>
- </param>
- <param name="HP-IDM-serviceId" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Check the roles against the given service IDs.
- </p>
- </doc>
- </param>
- </request>
- <response status="200 203"/>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/admin/OS-KSADM-admin-devguide.pdf b/keystone/content/admin/OS-KSADM-admin-devguide.pdf
deleted file mode 100644
index 7a433dc7..00000000
--- a/keystone/content/admin/OS-KSADM-admin-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/admin/OS-KSADM-admin.wadl b/keystone/content/admin/OS-KSADM-admin.wadl
deleted file mode 100644
index 3f034427..00000000
--- a/keystone/content/admin/OS-KSADM-admin.wadl
+++ /dev/null
@@ -1,793 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent OS-KSADM-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSADM="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0 ../common/xsd/OS-KSADM.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/OS-KSADM.xsd" />
- </grammars>
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <resource id="users" path="users">
- <method href="#listUsers"/>
- <method href="#addUser"/>
- <resource id="userById" path="{userId}">
- <param name="userId" style="template" required="true" type="xsd:string"/>
- <method href="#updateUser"/>
- <method href="#deleteUser"/>
-
- <resource id="userRoles" path="roles">
- <resource id="user-roles-OS-KSADM" path="OS-KSADM">
- <resource id="userRoleById" path="{roleId}">
- <param name="roleId" style="template" type="xsd:string"/>
- <method href="#addUserRole"/>
- <method href="#deleteUserRole"/>
- </resource>
- </resource>
- </resource>
-
- <resource id="user-OS-KSADM" path="OS-KSADM">
- <resource id="enabled" path="enabled">
- <method href="#setUserEnabled"/>
- </resource>
-
- <resource id="userCredentials" path="credentials">
- <method href="#addUserCredential"/>
- <method href="#listCredentials"/>
- <resource id="userCredentialsByType" path="{credential-type}">
- <param name="credentialType" style="template" type="OS-KSADM:extensibleCredentialsType" required="true"/>
- <method href="#updateUserCredential"/>
- <method href="#deleteUserCredential"/>
- <method href="#getUserCredential"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
-
- <resource id="tenants" path="tenants">
- <method href="#addTenant"/>
- <resource id="tenantById" path="{tenantId}">
- <param name="tenantId" style="template" type="xsd:string"/>
- <method href="#updateTenant"/>
- <method href="#deleteTenant"/>
- <resource id="usersForTenant" path="users">
- <method href="#listUsersForTenant"/>
- <resource id="userForTenant" path="{userId}">
- <param name="userId" style="template" type="xsd:string"/>
- <resource id="userRolesForTenant" path="roles">
- <resource id="tenant-user-role-OS-KSADM" path="OS-KSADM">
- <resource id="userSpecificRoleForTenant" path="{roleId}">
- <param name="roleId" style="template" type="xsd:string"/>
- <method href="#addRolesToUserOnTenant"/>
- <method href="#deleteRoleFromUserOnTenant"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
-
- <resource id="role-service-OS-KSADM" path="OS-KSADM">
- <resource id="roles" path="roles">
- <method href="#getRoleByName"/>
- <method href="#listRoles"/>
- <method href="#addRole"/>
- <resource id="roleId" path="{roleId}">
- <param name="roleId" style="template" type="xsd:string"/>
- <method href="#getRole"/>
- <method href="#deleteRole"/>
- </resource>
- </resource>
- <resource id="services" path="services">
- <method href="#listServices"/>
- <method href="#addService"/>
- <method href="#getServiceByName"/>
- <resource id="serviceId" path="{serviceId}">
- <param name="serviceId" style="template" type="xsd:string"/>
- <method href="#getService"/>
- <method href="#deleteService"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
- <!-- Tenant Operations -->
- <method name="POST" id="addTenant">
- <doc xml:lang="EN" title="Add Tenant">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Creates a tenant.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">This call creates a tenant.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:tenant">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenantwithoutid.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenantwithoutid.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="identity:tenant">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenant.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenant.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- </method>
-
- <method name="POST" id="updateTenant">
- <doc xml:lang="EN" title="Update Tenant">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Updates a tenant.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">This call updates a tenant.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:tenant">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenant.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenant.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="identity:tenant">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenant.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/tenant.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- &postPutFaults;
- </method>
-
- <method name="DELETE" id="deleteTenant">
- <doc xml:lang="EN" title="Delete a Tenant">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Deletes a tenant.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">This call deletes a tenant.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listUsersForTenant">
- <doc xml:lang="EN" title="List users for a Tenant.">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">Lists all the users for a tenant.</p>
- <p xmlns="http://www.w3.org/1999/xhtml">Lists all the users for a tenant.</p>
-
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:users">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/users.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/users.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="PUT" id="addRolesToUserOnTenant">
- <doc xml:lang="EN" title="Add roles to a user on a tenant.">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a specific role to a user for a tenant.</p>
- </doc>
- <response status="201"/>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteRoleFromUserOnTenant">
- <doc xml:lang="EN" title="Delete roles from a user on tenant.">
- <p xmlns="http://www.w3.org/1999/xhtml">Deletes a specific role from a user for a tenant.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-
- <!--User Operations-->
- <method name="GET" id="listUsers">
- <doc xml:lang="EN" title="List users">
- <p xmlns="http://www.w3.org/1999/xhtml">List users.</p>
-
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:userss">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/users.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/users.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
-
- <method name="POST" id="addUser">
- <doc xml:lang="EN" title="Add user">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a user.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:user">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/userwithoutid.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/userwithoutid.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="identity:user">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- &postPutFaults;
- </method>
-
- <method name="POST" id="updateUser">
- <doc xml:lang="EN" title="Update user">
- <p xmlns="http://www.w3.org/1999/xhtml">Update a user.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:user">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="identity:user">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteUser">
- <doc xml:lang="EN" title="Delete user">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete a user.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="PUT" id="setUserEnabled">
- <doc xml:lang="EN" title="Set user enabled.">
- <p xmlns="http://www.w3.org/1999/xhtml">Enable user.</p>
-
-
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:user">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/userwithenabledonly.xml"/>
- </doc>
- <param name="user" style="plain" path="/" type="OS-KSADM:UserWithOnlyEnabled"/></representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/userwithenabledonly.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="identity:user">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/user.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <!--User Roles-->
- <method name="PUT" id="addUserRole">
- <doc xml:lang="EN" title="Add Global roles to a user.">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a specific global role to a user.</p>
- </doc>
- <response status="201"/>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteUserRole">
- <doc xml:lang="EN" title="Delete Global Roles on User.">
- <p xmlns="http://www.w3.org/1999/xhtml">Deletes a specific global role from a user.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-
-
- <!-- User Credentials-->
- <method name="POST" id="addUserCredential">
- <doc xml:lang="EN" title="Add user Credential.">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a credential to a user.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:credential">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="identity:credential">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentials">
- <doc xml:lang="EN" title="List Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials.</p>
-
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentialsByType">
- <doc xml:lang="EN" title="List Credentials by type">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials by type.</p>
-
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="updateUserCredential">
- <doc xml:lang="EN" title="Update user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Update credentials.</p>
-
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:credential">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="identity:credential">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteUserCredential">
- <doc xml:lang="EN" title="Delete user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete User credentials.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getUserCredential">
- <doc xml:lang="EN" title="Get user Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">Get user credentials.</p>
-
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credential">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/passwordcredentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!--Roles-->
- <method name="GET" id="listRoles">
- <doc xml:lang="EN" title="List Roles">
- <p xmlns="http://www.w3.org/1999/xhtml">List roles.</p>
-
- </doc>
- <request>
- <param name="serviceId" style="query" required="false" type="xsd:string"/>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:roles">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/roles.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/roles.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="addRole">
- <doc xml:lang="EN" title="Add Role">
- <p xmlns="http://www.w3.org/1999/xhtml">Add a Role.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:role">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="identity:role">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.xml"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.json"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getRoleByName">
- <doc xml:lang="EN" title="Get Role By Name">
- <p xmlns="http://www.w3.org/1999/xhtml">Get a role by Name.</p>
- </doc>
- <request>
- <param name="name" style="query" type="xsd:string" required="true"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:role">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.xml"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.json"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
-
- <method name="GET" id="getRole">
- <doc xml:lang="EN" title="Get Role">
- <p xmlns="http://www.w3.org/1999/xhtml">Get a role.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:role">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.xml"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/role.json"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteRole">
- <doc xml:lang="EN" title="Delete Role">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete a role.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Service Operations -->
- <method name="GET" id="listServices">
- <doc xml:lang="EN" title="List Services">
- <p xmlns="http://www.w3.org/1999/xhtml">List services.</p>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSADM:services">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/services.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/services.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="getServiceByName">
- <doc xml:lang="EN" title="Get Service">
- <p xmlns="http://www.w3.org/1999/xhtml">Get a service by name.</p>
- </doc>
- <request>
- <param name="name" style="query" type="xsd:string" required="true"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSADM:service">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="getService">
- <doc xml:lang="EN" title="Get Service">
- <p xmlns="http://www.w3.org/1999/xhtml">Get a service.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSADM:service">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="POST" id="addService">
- <doc xml:lang="EN" title="Add Service">
- <p xmlns="http://www.w3.org/1999/xhtml">Add a service.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSADM:service">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="OS-KSADM:service">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.xml"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/service.json"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
- <method name="DELETE" id="deleteService">
- <doc xml:lang="EN" title="Delete Service">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete a service.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/admin/OS-KSCATALOG-admin-devguide.pdf b/keystone/content/admin/OS-KSCATALOG-admin-devguide.pdf
deleted file mode 100644
index fef083bb..00000000
--- a/keystone/content/admin/OS-KSCATALOG-admin-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/admin/OS-KSCATALOG-admin.wadl b/keystone/content/admin/OS-KSCATALOG-admin.wadl
deleted file mode 100644
index 2ed3558c..00000000
--- a/keystone/content/admin/OS-KSCATALOG-admin.wadl
+++ /dev/null
@@ -1,295 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent OS-KSCATALOG-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSCATALOG="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0 ../common/xsd/OS-KSCATALOG.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/OS-KSCATALOG.xsd"/>
- </grammars>
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
-
- <resource id="tenants" path="tenants">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true"/>
- <resource id="tenantId" path="{tenantId}">
- <param name="tenantId" style="template" type="xsd:string"/>
- <resource id="endpoints-OS-KSCATALOG" path="OS-KSCATALOG">
- <resource id="endpoints" path="endpoints">
- <method href="#listEndpoints"/>
- <method href="#addEndpoint"/>
- <resource id="endpoint" path="{endpointId}">
- <param name="endpointId" style="template" type="xsd:string"/>
- <method href="#getEndpoint"/>
- <method href="#deleteEndpoint"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
-
- <resource id="role-service-OS-KSCATALOG" path="OS-KSCATALOG">
- <resource id="endpointTemplates" path="endpointTemplates">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true"/>
- <method href="#listEndpointTemplates"/>
- <method href="#addEndpointTemplate"/>
- <resource id="endpointTemplateId" path="{endpointTemplateId}">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true"/>
- <param name="endpointTemplateId" style="template" type="xsd:string"/>
- <method href="#getEndpointTemplate"/>
- <method href="#updateEndpointTemplate"/>
- <method href="#deleteEndpointTemplate"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
- <!-- EndPoint Templates -->
-
- <method name="GET" id="listEndpointTemplates">
- <doc xml:lang="EN" title="List Endpoint Templates">
- <p xmlns="http://www.w3.org/1999/xhtml">List Endpoint Templates.</p>
-
- </doc>
- <request>
- <param name="serviceId" style="query" required="false" type="xsd:string"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplates">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplates.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplates.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getEndpointTemplate">
- <doc xml:lang="EN" title="Get Endpoint Template">
- <p xmlns="http://www.w3.org/1999/xhtml">Get Endpoint Template.</p>
-
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplate">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="addEndpointTemplate">
- <doc xml:lang="EN" title="Add Endpoint Template">
- <p xmlns="http://www.w3.org/1999/xhtml">Add Endpoint Template.</p>
-
-
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplate">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplate">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.xml"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.json"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- &postPutFaults;
- </method>
-
- <method name="PUT" id="updateEndpointTemplate">
- <doc xml:lang="EN" title="Update Endpoint Template">
- <p xmlns="http://www.w3.org/1999/xhtml">Update Endpoint Template.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplate">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplate">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplate.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- &postPutFaults;
- </method>
-
- <method name="DELETE" id="deleteEndpointTemplate">
- <doc xml:lang="EN" title="Delete Endpoint Template.">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete a Endpoint Template.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="addEndpoint">
- <doc xml:lang="EN" title="Add Endpoint">
- <p xmlns="http://www.w3.org/1999/xhtml">Add Endpoint to a tenant.</p>
-
-
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSCATALOG:endpointTemplate">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplateWithOnlyId.xml"/>
- </doc>
- <param name="endpoint" style="plain" path="/"
- type="OS-KSCATALOG:EndpointTemplateWithOnlyId"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpointTemplateWithOnlyId.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="identity:endpoint">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpoint.xml"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpoint.json"/>
- </doc>
- <param name="Location" type="xsd:anyURI" style="header"/>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- &postPutFaults;
- </method>
-
- <method name="GET" id="listEndpoints">
- <doc xml:lang="EN" title="List Endpoints">
- <p xmlns="http://www.w3.org/1999/xhtml">List Endpoints of a Tenant.</p>
-
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:endpoints">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpoints.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpoints.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getEndpoint">
- <doc xml:lang="EN" title="Get Endpoint">
- <p xmlns="http://www.w3.org/1999/xhtml">Get Endpoint of a Tenant.</p>
-
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:endpoint">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpoint.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/endpoint.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteEndpoint">
- <doc xml:lang="EN" title="Delete Endpoint.">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete a Endpoint from a Tenant.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/admin/OS-KSEC2-admin-devguide.pdf b/keystone/content/admin/OS-KSEC2-admin-devguide.pdf
deleted file mode 100644
index 084a26c4..00000000
--- a/keystone/content/admin/OS-KSEC2-admin-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/admin/OS-KSEC2-admin.wadl b/keystone/content/admin/OS-KSEC2-admin.wadl
deleted file mode 100644
index 8c2f62bd..00000000
--- a/keystone/content/admin/OS-KSEC2-admin.wadl
+++ /dev/null
@@ -1,212 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent OS-KSEC2-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSEC2="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0 ../common/xsd/OS-KSEC2-credentials.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/OS-KSEC2-credentials.xsd" />
- </grammars>
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <resource id="users" path="users">
- <resource id="userById" path="{userId}">
- <param name="userId" style="template" required="true" type="xsd:string"/>
- <resource id="user-OS-KSADM" path="OS-KSADM">
- <resource id="userCredentials" path="credentials">
- <method href="#addUserCredential"/>
- <method href="#listCredentials"/>
- <resource id="userCredentialsByType" path="OS-KSEC2:ec2Credentials">
- <method href="#updateUserCredential"/>
- <method href="#deleteUserCredential"/>
- <method href="#getUserCredential"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
-
-
- <!-- User Credentials-->
- <method name="POST" id="addUserCredential">
- <doc xml:lang="EN" title="Add user Credential.">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a credential to a user.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSEC2:ec2Credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="OS-KSEC2:ec2Credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentials">
- <doc xml:lang="EN" title="List Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials.</p>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentialswithec2.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentialswithec2.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentialsByType">
- <doc xml:lang="EN" title="List Credentials by type">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials by type.</p>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="updateUserCredential">
- <doc xml:lang="EN" title="Update user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Update credentials.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSEC2:ec2Credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="OS-KSEC2:ec2Credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteUserCredential">
- <doc xml:lang="EN" title="Delete user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete User credentials.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getUserCredential">
- <doc xml:lang="EN" title="Get user Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">Get user credentials.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSEC2:ec2Credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/ec2Credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/admin/OS-KSS3-admin.wadl b/keystone/content/admin/OS-KSS3-admin.wadl
deleted file mode 100644
index fcffb6eb..00000000
--- a/keystone/content/admin/OS-KSS3-admin.wadl
+++ /dev/null
@@ -1,212 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent OS-KSEC2-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSEC2="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0 ../common/xsd/OS-KSEC2-credentials.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/OS-KSEC2-credentials.xsd" />
- </grammars>
- <!--*******************************************************-->
- <!-- All Resoruces -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <resource id="users" path="users">
- <resource id="userById" path="{userId}">
- <param name="userId" style="template" required="true" type="xsd:string"/>
- <resource id="user-OS-KSADM" path="OS-KSADM">
- <resource id="userCredentials" path="credentials">
- <method href="#addUserCredential"/>
- <method href="#listCredentials"/>
- <resource id="userCredentialsByType" path="OS-KSEC2:s3Credentials">
- <method href="#updateUserCredential"/>
- <method href="#deleteUserCredential"/>
- <method href="#getUserCredential"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
-
-
- <!-- User Credentials-->
- <method name="POST" id="addUserCredential">
- <doc xml:lang="EN" title="Add user Credential.">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a credential to a user.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSS3:s3credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="OS-KSS3:s3credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentials">
- <doc xml:lang="EN" title="List Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials.</p>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentialswiths3.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentialswiths3.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentialsByType">
- <doc xml:lang="EN" title="List Credentials by type">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials by type.</p>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="updateUserCredential">
- <doc xml:lang="EN" title="Update user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Update credentials.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="OS-KSS3:s3credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="OS-KSS3:s3credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteUserCredential">
- <doc xml:lang="EN" title="Delete user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete User credentials.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getUserCredential">
- <doc xml:lang="EN" title="Get user Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">Get user credentials.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="OS-KSS3:s3credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/s3Credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/admin/OS-KSVALIDATE-admin.wadl b/keystone/content/admin/OS-KSVALIDATE-admin.wadl
deleted file mode 100644
index c477131d..00000000
--- a/keystone/content/admin/OS-KSVALIDATE-admin.wadl
+++ /dev/null
@@ -1,192 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent OS-KSVALIDATE-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "https://raw.github.com/openstack/keystone/master/keystone/content/common/common.ent">
- %common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSVALIDATE="http://docs.openstack.org/identity/api/ext/OS-KSVALIDATE/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- ">
-
- <grammars>
- <include href="https://raw.github.com/openstack/keystone/master/keystone/content/common/xsd/api.xsd"/>
- <include href="https://raw.github.com/openstack/keystone/master/keystone/content/common/xsd/api-common.xsd"/>
- </grammars>
-
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <resource id="extension" path="OS-KSVALIDATE">
- <resource id="token" path="token">
- <resource id="validate" path="validate">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <param name="X-Subject-Token" style="header" type="xsd:string" required="true">
- <doc>You need to supply a token to validate.</doc>
- </param>
- <param name="belongsTo" style="query" type="xsd:string" required="false"/>
- <param name="HP-IDM-serviceId" style="query" type="xsd:string" required="false"/>
- <method href="#validateToken"/>
- <method href="#checkToken"/>
- </resource>
-
- <resource id="endpointsForToken" path="endpoints">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <param name="X-Subject-Token" style="header" type="xsd:string" required="true">
- <doc>You need to supply a token to validate.</doc>
- </param>
- <param name="HP-IDM-serviceId" style="query" type="xsd:string" required="false"/>
- <method href="#listEndpointsForToken"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
-
- <!-- Token Operations -->
- <method name="GET" id="validateToken">
- <doc xml:lang="EN" title="Validate Token">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Check that a token is valid and that it belongs to a supplied tenant
- and services and return the permissions relevant to a particular client.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Behaviour is similar to <code>/tokens/{tokenId}</code>. In
- other words, a user should expect an
- itemNotFound (<code>404</code>) fault for an
- invalid token.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- 'X-Subject-Token' is encrypted, but can still be used for
- caching. This extension will basically decrypt this header and
- internally call Keystone's normal validation, passing along all
- headers and query parameters. It should therefore support
- all exsting calls on <code>/tokens/{tokenId}</code>, including
- extensions such as HP-IDM.
- </p>
- </doc>
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Validates a token has the supplied tenant in scope.
- </p>
- </doc>
- </param>
- <param name="OS-KSVALIDATE-serviceId" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- If provided, filter the roles to be returned by the given service IDs.
- </p>
- </doc>
- </param>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:access">
- <doc>
- <xsdxt:code href="../samples/validatetoken.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../samples/validatetoken.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="HEAD" id="checkToken">
- <doc xml:lang="EN" title="Check Token">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Check that a token is valid and that it belongs to a particular
- tenant and services (For performance).
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Behaviour is similar to <code>/tokens/{tokenId}</code>. In
- other words, a user should expect an
- itemNotFound (<code>404</code>) fault for an
- invalid token.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- 'X-Subject-Token' is encrypted, but can still be used for
- caching. This extension will basically decrypt this header and
- internally call Keystone's normal validation, passing along all
- headers and query parameters. It should therefore support
- all exsting calls on <code>/tokens/{tokenId}</code>, including
- extensions such as HP-IDM.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- No response body is returned for this method.
- </p>
- </doc>
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Validates a token has the supplied tenant in scope. (for performance).
- </p>
- </doc>
- </param>
- <param name="OS-KSVALIDATE-serviceId" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Check the roles against the given service IDs.
- </p>
- </doc>
- </param>
- </request>
- <response status="200 203"/>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="listEndpointsForToken">
- <doc xml:lang="EN" title="List Endoints for a Token">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns a list of endpoints associated with a specific token.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:endpoints">
- <doc>
- <xsdxt:code href="../common/samples/endpoints.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/endpoints.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
-</application>
diff --git a/keystone/content/admin/RAX-KSGRP-admin.wadl b/keystone/content/admin/RAX-KSGRP-admin.wadl
deleted file mode 100644
index 01548029..00000000
--- a/keystone/content/admin/RAX-KSGRP-admin.wadl
+++ /dev/null
@@ -1,74 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent RAX-KSGRP-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSGRP="http://docs.openstack.org/identity/api/ext/RAX-KSGRP/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.openstack.org/identity/api/ext/RAX-KSGRP/v1.0 ../common/xsd/RAX-KSGRP-groups.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/RAX-KSGRP-groups.xsd"/>
- </grammars>
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <resource id="users" path="users">
- <resource id="userById" path="{userId}">
- <param name="userId" style="template" type="xsd:string"/>
- <resource id="user-groups-RAX-KSGRP" path="RAX-KSGRP">
- <method href="#listUserGroups"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <method name="GET" id="listUserGroups">
- <doc xml:lang="EN" title="List Groups for a User">
- <p xmlns="http://www.w3.org/1999/xhtml">List all the groups for a user.</p>
-
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="RAX-KSGRP:groups">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSGRP-groups.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSGRP-groups.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- </application>
-
diff --git a/keystone/content/admin/RAX-KSKEY-admin-devguide.pdf b/keystone/content/admin/RAX-KSKEY-admin-devguide.pdf
deleted file mode 100644
index 224cd999..00000000
--- a/keystone/content/admin/RAX-KSKEY-admin-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/admin/RAX-KSKEY-admin.wadl b/keystone/content/admin/RAX-KSKEY-admin.wadl
deleted file mode 100644
index 3bebb1b3..00000000
--- a/keystone/content/admin/RAX-KSKEY-admin.wadl
+++ /dev/null
@@ -1,212 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent RAX-KSKEY-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSKEY="http://docs.openstack.org/identity/api/ext/RAX-KSKEY/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0 ../common/xsd/RAX-KSKEY-credentials.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/RAX-KSKEY-credentials.xsd" />
- </grammars>
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <resource id="users" path="users">
- <resource id="userById" path="{userId}">
- <param name="userId" style="template" required="true" type="xsd:string"/>
- <resource id="user-OS-KSADM" path="OS-KSADM">
- <resource id="userCredentials" path="credentials">
- <method href="#addUserCredential"/>
- <method href="#listCredentials"/>
- <resource id="userCredentialsByType" path="RAX-KSKEY:apiKeyCredentials">
- <method href="#updateUserCredential"/>
- <method href="#deleteUserCredential"/>
- <method href="#getUserCredential"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
- <!-- User Credentials-->
- <method name="POST" id="addUserCredential">
- <doc xml:lang="EN" title="Add user Credential.">
- <p xmlns="http://www.w3.org/1999/xhtml">Adds a credential to a user.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="RAX-KSKEY:apiKeyCredentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="RAX-KSKEY:apiKeyCredentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentials">
- <doc xml:lang="EN" title="List Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials.</p>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentialswithapikey.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentialswithapikey.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listCredentialsByType">
- <doc xml:lang="EN" title="List Credentials by type">
- <p xmlns="http://www.w3.org/1999/xhtml">List credentials by type.</p>
-
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:credentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/credentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="POST" id="updateUserCredential">
- <doc xml:lang="EN" title="Update user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Update credentials.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="RAX-KSKEY:apiKeyCredentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="RAX-KSKEY:apiKeyCredentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="DELETE" id="deleteUserCredential">
- <doc xml:lang="EN" title="Delete user credential">
- <p xmlns="http://www.w3.org/1999/xhtml">Delete User credentials.</p>
- </doc>
- <response status="204"/>
- &commonFaults;
- &postPutFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="getUserCredential">
- <doc xml:lang="EN" title="Get user Credentials">
- <p xmlns="http://www.w3.org/1999/xhtml">Get user credentials.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="RAX-KSKEY:apiKeyCredentials">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/apiKeyCredentials.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-</application>
-
diff --git a/keystone/content/admin/RAX-KSQA-admin.wadl b/keystone/content/admin/RAX-KSQA-admin.wadl
deleted file mode 100644
index 23d201fd..00000000
--- a/keystone/content/admin/RAX-KSQA-admin.wadl
+++ /dev/null
@@ -1,106 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent RAX-KSQA-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
-<!ENTITY % common SYSTEM "../common/common.ent">
-%common;
-]>
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSQA="http://docs.openstack.org/identity/api/ext/RAX-KSQA/v1.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- http://docs.openstack.org/identity/api/ext/RAX-KSQA/v1.0 ../common/xsd/RAX-KSQA-secretQA.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- <include href="../common/xsd/RAX-KSQA-secretQA.xsd"/>
- </grammars>
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <resource id="users" path="users">
- <resource id="userById" path="{userId}">
- <param name="userId" style="template" type="xsd:string"/>
- <resource id="user-RAX-KSQA" path="RAX-KSQA">
- <resource id="secretqa" path="secretqa">
- <method href="#getUserSecretQA"/>
- <method href="#updateUserSecretQA"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <method name="GET" id="getUserSecretQA">
- <doc xml:lang="EN" title="Get User SecretQA">
- <p xmlns="http://www.w3.org/1999/xhtml">Gets a User secret Question and Answer.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="RAX-KSQA:secretQA">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSQA-secretQA.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSQA-secretQA.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="PUT" id="updateUserSecretQA">
- <doc xml:lang="EN" title="Update User SecretQA">
- <p xmlns="http://www.w3.org/1999/xhtml">Updates a User secret Question and Answer.</p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="RAX-KSQA:secretQA">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSQA-secretQA.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSQA-secretQA.json"/>
- </doc>
- </representation>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="RAX-KSQA:secretQA">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSQA-secretQA.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc xml:lang="EN">
- <xsdxt:code href="../common/samples/RAX-KSQA-secretQA.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &postPutFaults;
- </method>
- </application>
diff --git a/keystone/content/admin/extensions.json b/keystone/content/admin/extensions.json
deleted file mode 100644
index 7a514fd7..00000000
--- a/keystone/content/admin/extensions.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "extensions": {
- "values": []
- }
-}
diff --git a/keystone/content/admin/extensions.xml b/keystone/content/admin/extensions.xml
deleted file mode 100644
index ed5ee9c6..00000000
--- a/keystone/content/admin/extensions.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<extensions xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
-</extensions>
diff --git a/keystone/content/admin/identity-admin.wadl b/keystone/content/admin/identity-admin.wadl
deleted file mode 100644
index a6ded2ac..00000000
--- a/keystone/content/admin/identity-admin.wadl
+++ /dev/null
@@ -1,508 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent identity-admin.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
- <!ENTITY % common SYSTEM "../common/common.ent">
- %common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- </grammars>
-
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:35357">
- <resource id="version" path="v2.0">
- <method href="#getVersionInfo"/>
-
- <resource id="extensions" path="extensions">
- <method href="#listExtensions"/>
-
- <resource id="extension" path="{alias}">
- <param name="alias" style="template" type="xsd:string"/>
- <method href="#getExtension"/>
- </resource>
- </resource>
-
- <resource id="tokens" path="tokens">
- <method href="#authenticate"/>
- <resource id="tokenById" path="{tokenId}">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <param name="tokenId" style="template" type="xsd:string" required="true"/>
- <param name="belongsTo" style="query" type="xsd:string" required="false"/>
- <method href="#validateToken"/>
- <method href="#checkToken"/>
- <resource id="endpointsForToken" path="endpoints">
- <method href="#listEndpointsForToken"/>
- </resource>
- </resource>
- </resource>
-
- <resource id="users" path="users">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>You need a valid admin token for access.</doc>
- </param>
- <method href="#getUserByName"/>
- <resource id="userid" path="{user_id}">
- <param name="user_id" style="template" type="xsd:string" required="true"/>
- <method href="#getUserById"/>
-
- <resource id="userRoles" path="roles">
- <method href="#listUserGlobalRoles"/>
- </resource>
- </resource>
- </resource>
-
- <resource id="tenants" path="tenants">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true">
- <doc>
- <p xmlns="http://www.w3.org/1999/xhtml">
- You need a valid admin token for access.
- </p>
- </doc>
- </param>
- <method href="#listTenants"/>
- <method href="#getTenantByName"/>
- <resource id="tenantById" path="{tenantId}">
- <param name="tenantId" style="template" type="xsd:string" required="true"/>
- <method href="#getTenantById"/>
-
- <resource id="usersForTenant" path="users">
- <resource id="getTenantUser" path="{user_id}">
- <param name="user_id" style="template" type="xsd:string" required="true"/>
-
- <resource id="userRolesForTenant" path="roles">
- <method href="#listRolesForUserOnTenant"/>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resource>
- </resources>
-
- <!--*******************************************************-->
- <!-- Resource Types -->
- <!--*******************************************************-->
-
- <resource_type id="VersionDetails">
- <method href="#getVersionInfo"/>
- </resource_type>
-
- <resource_type id="ExtensionList">
- <doc xml:lang="EN" title="Extension List">
- <p xmlns="http://www.w3.org/1999/xhtml">
- A list of supported extensions.
- </p>
- </doc>
- <method href="#listExtensions"/>
- </resource_type>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
- <!-- Version -->
-
- <method name="GET" id="getVersionInfo">
- <doc xml:lang="EN" title="Version Details">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns detailed information about this specific version of the API.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:version">
- <param name="location" style="plain" type="xsd:anyURI" required="true" path="/capi:version/atom:link[@rel='self']/@href">
- <link resource_type="#VersionDetails" rel="self"/>
- </param>
- </representation>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Extensions -->
-
- <method name="GET" id="listExtensions">
- <doc xml:lang="EN" title="List Extensions">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Lists supported extensions.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:extensions">
- <param name="next" style="plain" type="xsd:anyURI" path="/capi:extensions/atom:link[@rel='next']/@href">
- <link resource_type="#ExtensionList" rel="next"/>
- </param>
- <param name="previous" style="plain" type="xsd:anyURI" path="/capi:extensions/atom:link[@rel='previous']/@href">
- <link resource_type="#ExtensionList" rel="previous"/>
- </param>
- </representation>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- </method>
- <method name="GET" id="getExtension">
- <doc xml:lang="EN" title="Get Extension Details">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Gets details about a specific extension.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:extension"/>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Token Operations -->
-
- <method name="POST" id="authenticate">
- <doc xml:lang="EN" title="Authenticate for Service API">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Authenticate to generate a token.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- This call will return a token if successful. Each ReST request against other services (or other
- calls on Keystone such as the GET /tenants call)
- requires the inclusion of a specific authorization token HTTP x-header, defined as X-Auth-Token.
- Clients obtain
- this token, along with the URL to other service APIs, by first authenticating against the
- Keystone Service and supplying valid credentials.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Client authentication is provided via a ReST interface using the POST method,
- with v2.0/tokens supplied as the path. A payload of credentials must be included
- in the body.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- The Keystone Service is a ReSTful web service. It is the entry point to all service APIs.
- To access the Keystone Service, you must know URL of the Keystone service.
- </p>
- </doc>
- <request>
- <representation mediaType="application/xml" element="identity:auth">
- <doc>
- <xsdxt:code href="../common/samples/auth_credentials.xml"/>
- <xsdxt:code href="../common/samples/auth_with_token.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/auth_credentials.json"/>
- <xsdxt:code href="../common/samples/auth_with_token.json"/>
- </doc>
- </representation>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:access">
- <doc>
- <xsdxt:code href="../common/samples/auth.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/auth.json"/>
- </doc>
- </representation>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:userDisabled"/>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="validateToken">
- <doc xml:lang="EN" title="Validate Token">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Check that a token is valid and that it belongs to a supplied tenant
- and return the permissions relevant to a particular client.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Valid tokens will exist in the
- <code>/tokens/{tokenId}</code> path and invalid
- tokens will not. In other words, a user should expect an
- itemNotFound (<code>404</code>) fault for an
- invalid token.
- </p>
- </doc>
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Validates a token has the supplied tenant in scope.
- </p>
- </doc>
- </param>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:access">
- <doc>
- <xsdxt:code href="../common/samples/validatetoken.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/validatetoken.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="HEAD" id="checkToken">
- <doc xml:lang="EN" title="Check Token">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Check that a token is valid and that it belongs to a particular tenant
- (For performance).
- </p>
- </doc>
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string">
- <doc xml:lang="EN">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Validates a token has the supplied tenant in scope. (for performance).
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- Valid tokens will exist in the
- <code>/tokens/{tokenId}</code> path and invalid
- tokens will not. In other words, a user should expect an
- itemNotFound (<code>404</code>) fault for an
- invalid token.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- If `belongsTo` is provided, validates that a token has a specific tenant in scope.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- No response body is returned for this method.
- </p>
- </doc>
- </param>
- </request>
- <response status="200 203"/>
- &commonFaults;
- &getFaults;
- </method>
-
- <!--User Operations-->
- <method name="GET" id="getUserByName">
- <doc xml:lang="EN" title="Get a User by Name">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns detailed information about a specific user, by user name.
- </p>
- </doc>
- <request>
- <param name="name" style="query" type="xsd:string" required="true"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:user">
- <doc>
- <xsdxt:code href="../common/samples/user.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/user.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="getUserById">
- <doc xml:lang="EN" title="Get a User by ID">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns detailed information about a specific user, by user id.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:user">
- <doc>
- <xsdxt:code href="../common/samples/user.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/user.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="listUserGlobalRoles">
- <doc xml:lang="EN" title="List User Global Roles">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Returns global roles for a specific user (excludes tenant roles).
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">Returns a list of global roles associated with a specific
- user (excludes tenant roles).</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:roles">
- <doc>
- <xsdxt:code href="../common/samples/roles.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/roles.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Tenant Operations -->
-
- <method name="GET" id="listTenants">
- <doc xml:lang="EN" title="Get Tenants">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Get a list of tenants.
- </p>
- <p xmlns="http://www.w3.org/1999/xhtml">
- The operation returns a list of tenants which the supplied token provides
- access to. This call must be authenticated, so a valid token must
- be passed in as a header.
- </p>
- <xsdxt:samples>
- <xsdxt:sample xmlns="http://docs.rackspace.com/api" title="Tenants Request with Auth Token">
- <xsdxt:code href="../common/samples/tenants-request.txt" language="text"/>
- </xsdxt:sample>
- </xsdxt:samples>
- </doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:tenants">
- <doc>
- <xsdxt:code href="../common/samples/tenants.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/tenants.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="getTenantByName">
- <doc xml:lang="EN" title="Get tenants by name">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Returns detailed information about a tenant, by name.
- </p>
- </doc>
- <request>
- <param name="name" style="query" type="xsd:string" required="true"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:tenant">
- <doc>
- <xsdxt:code href="../common/samples/tenant.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/tenant.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="getTenantById">
- <doc xml:lang="EN" title="Get Tenants by ID">
- <p xmlns="http://www.w3.org/1999/xhtml" class="shortdesc">
- Returns detailed information about a tenant, by id.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:tenant">
- <doc>
- <xsdxt:code href="../common/samples/tenant.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/tenant.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="listEndpointsForToken">
- <doc xml:lang="EN" title="List Endoints for a Token">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns a list of endpoints associated with a specific token.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:endpoints">
- <doc>
- <xsdxt:code href="../common/samples/endpoints.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/endpoints.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <method name="GET" id="listRolesForUserOnTenant">
- <doc xml:lang="EN" title="List Roles for User on Tenant">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns roles for a specific user on a specific tenant (excludes global roles).
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:roles">
- <doc>
- <xsdxt:code href="../common/samples/roles.xml"/>
- </doc>
- </representation>
- <representation mediaType="application/json">
- <doc>
- <xsdxt:code href="../common/samples/roles.json"/>
- </doc>
- </representation>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/admin/identityadminguide.pdf b/keystone/content/admin/identityadminguide.pdf
deleted file mode 100644
index 5229e5d4..00000000
--- a/keystone/content/admin/identityadminguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/admin/version.atom.tpl b/keystone/content/admin/version.atom.tpl
deleted file mode 100644
index e39250d5..00000000
--- a/keystone/content/admin/version.atom.tpl
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
- <title type="text">Available API Versions</title>
- <updated>2010-12-22T00:00:00.00Z</updated>
- <id>http://identity.api.openstack.org/</id>
- <author><name>OpenStack</name><uri>http://www.openstack.org/</uri></author>
- <link rel="self" href="http://identity.api.openstack.org/"/>
- <entry>
- <id>http://identity.api.openstack.org/v2.0/</id>
- <title type="text">Version v2.0</title>
- <updated>2011-09-30T00:00:00.00Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v2.0/"/>
- <content type="text">Version v2.0 BETA (2011-09-30T00:00:00.00Z)</content>
- </entry>
- <entry>
- <id>http://identity.api.openstack.org/v1.1/</id>
- <title type="text">Version v1.1</title>
- <updated>2011-01-21T11:33:21-06:00</updated>
- <link rel="self" href="http://identity.api.openstack.org/v1.1/"/>
- <content type="text">Version v1.1 CURRENT (2011-01-21T11:33:21-06:00)</content>
- </entry>
- <entry>
- <id>http://identity.api.openstack.org/v1.0/</id>
- <title type="text">Version v1.0</title>
- <updated>2009-10-09T11:30:00Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v1.0/"/>
- <content type="text">Version v1.0 DEPRECATED (2009-10-09T11:30:00Z)</content>
- </entry>
-</feed>
diff --git a/keystone/content/admin/version.json.tpl b/keystone/content/admin/version.json.tpl
deleted file mode 100644
index 112ba1b8..00000000
--- a/keystone/content/admin/version.json.tpl
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "versions": {
- "values": [{
- "id": "v{{API_VERSION}}",
- "status": "{{API_VERSION_STATUS}}",
- "updated": "{{API_VERSION_DATE}}",
- "links": [{
- "rel": "self",
- "href": "http://{{HOST}}:{{PORT}}/v{{API_VERSION}}/"
- }, {
- "rel": "describedby",
- "type": "text/html",
- "href": "http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/content/"
- }, {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/identity-dev-guide-{{API_VERSION}}.pdf"
- }, {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "http://{{HOST}}:{{PORT}}/v2.0/identity-admin.wadl"
- }],
- "media-types": [{
- "base": "application/xml",
- "type": "application/vnd.openstack.identity-v{{API_VERSION}}+xml"
- }, {
- "base": "application/json",
- "type": "application/vnd.openstack.identity-v{{API_VERSION}}+json"
- }]
- }]
- }
-} \ No newline at end of file
diff --git a/keystone/content/admin/version.xml.tpl b/keystone/content/admin/version.xml.tpl
deleted file mode 100644
index b62c9b6a..00000000
--- a/keystone/content/admin/version.xml.tpl
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<versions xmlns="http://docs.openstack.org/common/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
-
- <version id="v{{API_VERSION}}" status="{{API_VERSION_STATUS}}" updated="{{API_VERSION_DATE}}">
-
- <media-types>
- <media-type base="application/xml"
- type="application/vnd.openstack.identity-v{{API_VERSION}}+xml"/>
- <media-type base="application/json"
- type="application/vnd.openstack.identity-v{{API_VERSION}}+json"/>
- </media-types>
-
- <atom:link rel="self"
- href="http://{{HOST}}:{{PORT}}/v{{API_VERSION}}/"/>
-
- <atom:link rel="describedby"
- type="text/html"
- href="http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/content/" />
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/identity-dev-guide-{{API_VERSION}}.pdf" />
-
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="http://{{HOST}}:{{PORT}}/v2.0/identity-admin.wadl" />
- </version>
-</versions> \ No newline at end of file
diff --git a/keystone/content/common/common.ent b/keystone/content/common/common.ent
deleted file mode 100644
index b492c5d2..00000000
--- a/keystone/content/common/common.ent
+++ /dev/null
@@ -1,56 +0,0 @@
-
- <!--
- A collection of common faults, these are pretty much expected
- in every request.
- -->
- <!ENTITY commonFaults
- '
- <response xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="400" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="403" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="405" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:badMethod"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="413" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:overLimit"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="503" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- <representation mediaType="application/json"/>
- </response>
- '>
- <!--
- Faults on GET
- -->
- <!ENTITY getFaults
- '
- <response status="404" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- <representation mediaType="application/json"/>
- </response>
- '>
- <!--
- Faults on POST/PUT
- -->
- <!ENTITY postPutFaults
- '
- <response status="415" xmlns="http://wadl.dev.java.net/2009/02">
- <representation mediaType="application/xml" element="identity:badMediaType"/>
- <representation mediaType="application/json"/>
- </response>
- '>
diff --git a/keystone/content/common/js/shjs/sh_java.js b/keystone/content/common/js/shjs/sh_java.js
deleted file mode 100644
index 731fc9f3..00000000
--- a/keystone/content/common/js/shjs/sh_java.js
+++ /dev/null
@@ -1,337 +0,0 @@
-if (! this.sh_languages) {
- this.sh_languages = {};
-}
-sh_languages['java'] = [
- [
- [
- /\b(?:import|package)\b/g,
- 'sh_preproc',
- -1
- ],
- [
- /\/\/\//g,
- 'sh_comment',
- 1
- ],
- [
- /\/\//g,
- 'sh_comment',
- 7
- ],
- [
- /\/\*\*/g,
- 'sh_comment',
- 8
- ],
- [
- /\/\*/g,
- 'sh_comment',
- 9
- ],
- [
- /\b[+-]?(?:(?:0x[A-Fa-f0-9]+)|(?:(?:[\d]*\.)?[\d]+(?:[eE][+-]?[\d]+)?))u?(?:(?:int(?:8|16|32|64))|L)?\b/g,
- 'sh_number',
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 10
- ],
- [
- /'/g,
- 'sh_string',
- 11
- ],
- [
- /(\b(?:class|interface))([ \t]+)([$A-Za-z0-9_]+)/g,
- ['sh_keyword', 'sh_normal', 'sh_classname'],
- -1
- ],
- [
- /\b(?:abstract|assert|break|case|catch|class|const|continue|default|do|else|extends|false|final|finally|for|goto|if|implements|instanceof|interface|native|new|null|private|protected|public|return|static|strictfp|super|switch|synchronized|throw|throws|true|this|transient|try|volatile|while)\b/g,
- 'sh_keyword',
- -1
- ],
- [
- /\b(?:int|byte|boolean|char|long|float|double|short|void)\b/g,
- 'sh_type',
- -1
- ],
- [
- /~|!|%|\^|\*|\(|\)|-|\+|=|\[|\]|\\|:|;|,|\.|\/|\?|&|<|>|\|/g,
- 'sh_symbol',
- -1
- ],
- [
- /\{|\}/g,
- 'sh_cbracket',
- -1
- ],
- [
- /(?:[A-Za-z]|_)[A-Za-z0-9_]*(?=[ \t]*\()/g,
- 'sh_function',
- -1
- ],
- [
- /([A-Za-z](?:[^`~!@#$%&*()_=+{}|;:",<.>\/?'\\[\]\^\-\s]|[_])*)((?:<.*>)?)(\s+(?=[*&]*[A-Za-z][^`~!@#$%&*()_=+{}|;:",<.>\/?'\\[\]\^\-\s]*\s*[`~!@#$%&*()_=+{}|;:",<.>\/?'\\[\]\^\-\[\]]+))/g,
- ['sh_usertype', 'sh_usertype', 'sh_normal'],
- -1
- ]
- ],
- [
- [
- /$/g,
- null,
- -2
- ],
- [
- /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
- 'sh_url',
- -1
- ],
- [
- /<\?xml/g,
- 'sh_preproc',
- 2,
- 1
- ],
- [
- /<!DOCTYPE/g,
- 'sh_preproc',
- 4,
- 1
- ],
- [
- /<!--/g,
- 'sh_comment',
- 5
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /&(?:[A-Za-z0-9]+);/g,
- 'sh_preproc',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /@[A-Za-z]+/g,
- 'sh_type',
- -1
- ],
- [
- /(?:TODO|FIXME|BUG)(?:[:]?)/g,
- 'sh_todo',
- -1
- ]
- ],
- [
- [
- /\?>/g,
- 'sh_preproc',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 3
- ]
- ],
- [
- [
- /\\(?:\\|")/g,
- null,
- -1
- ],
- [
- /"/g,
- 'sh_string',
- -2
- ]
- ],
- [
- [
- />/g,
- 'sh_preproc',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 3
- ]
- ],
- [
- [
- /-->/g,
- 'sh_comment',
- -2
- ],
- [
- /<!--/g,
- 'sh_comment',
- 5
- ]
- ],
- [
- [
- /(?:\/)?>/g,
- 'sh_keyword',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 3
- ]
- ],
- [
- [
- /$/g,
- null,
- -2
- ]
- ],
- [
- [
- /\*\//g,
- 'sh_comment',
- -2
- ],
- [
- /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
- 'sh_url',
- -1
- ],
- [
- /<\?xml/g,
- 'sh_preproc',
- 2,
- 1
- ],
- [
- /<!DOCTYPE/g,
- 'sh_preproc',
- 4,
- 1
- ],
- [
- /<!--/g,
- 'sh_comment',
- 5
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /&(?:[A-Za-z0-9]+);/g,
- 'sh_preproc',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /@[A-Za-z]+/g,
- 'sh_type',
- -1
- ],
- [
- /(?:TODO|FIXME|BUG)(?:[:]?)/g,
- 'sh_todo',
- -1
- ]
- ],
- [
- [
- /\*\//g,
- 'sh_comment',
- -2
- ],
- [
- /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
- 'sh_url',
- -1
- ],
- [
- /(?:TODO|FIXME|BUG)(?:[:]?)/g,
- 'sh_todo',
- -1
- ]
- ],
- [
- [
- /"/g,
- 'sh_string',
- -2
- ],
- [
- /\\./g,
- 'sh_specialchar',
- -1
- ]
- ],
- [
- [
- /'/g,
- 'sh_string',
- -2
- ],
- [
- /\\./g,
- 'sh_specialchar',
- -1
- ]
- ]
-];
diff --git a/keystone/content/common/js/shjs/sh_javascript.js b/keystone/content/common/js/shjs/sh_javascript.js
deleted file mode 100644
index ae4fa0ec..00000000
--- a/keystone/content/common/js/shjs/sh_javascript.js
+++ /dev/null
@@ -1,347 +0,0 @@
-if (! this.sh_languages) {
- this.sh_languages = {};
-}
-sh_languages['javascript'] = [
- [
- [
- /\/\/\//g,
- 'sh_comment',
- 1
- ],
- [
- /\/\//g,
- 'sh_comment',
- 7
- ],
- [
- /\/\*\*/g,
- 'sh_comment',
- 8
- ],
- [
- /\/\*/g,
- 'sh_comment',
- 9
- ],
- [
- /\b(?:abstract|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|false|final|finally|for|function|goto|if|implements|in|instanceof|interface|native|new|null|private|protected|prototype|public|return|static|super|switch|synchronized|throw|throws|this|transient|true|try|typeof|var|volatile|while|with)\b/g,
- 'sh_keyword',
- -1
- ],
- [
- /(\+\+|--|\)|\])(\s*)(\/=?(?![*\/]))/g,
- ['sh_symbol', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /(0x[A-Fa-f0-9]+|(?:[\d]*\.)?[\d]+(?:[eE][+-]?[\d]+)?)(\s*)(\/(?![*\/]))/g,
- ['sh_number', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /([A-Za-z$_][A-Za-z0-9$_]*\s*)(\/=?(?![*\/]))/g,
- ['sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /\/(?:\\.|[^*\\\/])(?:\\.|[^\\\/])*\/[gim]*/g,
- 'sh_regexp',
- -1
- ],
- [
- /\b[+-]?(?:(?:0x[A-Fa-f0-9]+)|(?:(?:[\d]*\.)?[\d]+(?:[eE][+-]?[\d]+)?))u?(?:(?:int(?:8|16|32|64))|L)?\b/g,
- 'sh_number',
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 10
- ],
- [
- /'/g,
- 'sh_string',
- 11
- ],
- [
- /~|!|%|\^|\*|\(|\)|-|\+|=|\[|\]|\\|:|;|,|\.|\/|\?|&|<|>|\|/g,
- 'sh_symbol',
- -1
- ],
- [
- /\{|\}/g,
- 'sh_cbracket',
- -1
- ],
- [
- /\b(?:Math|Infinity|NaN|undefined|arguments)\b/g,
- 'sh_predef_var',
- -1
- ],
- [
- /\b(?:Array|Boolean|Date|Error|EvalError|Function|Number|Object|RangeError|ReferenceError|RegExp|String|SyntaxError|TypeError|URIError|decodeURI|decodeURIComponent|encodeURI|encodeURIComponent|eval|isFinite|isNaN|parseFloat|parseInt)\b/g,
- 'sh_predef_func',
- -1
- ],
- [
- /(?:[A-Za-z]|_)[A-Za-z0-9_]*(?=[ \t]*\()/g,
- 'sh_function',
- -1
- ]
- ],
- [
- [
- /$/g,
- null,
- -2
- ],
- [
- /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
- 'sh_url',
- -1
- ],
- [
- /<\?xml/g,
- 'sh_preproc',
- 2,
- 1
- ],
- [
- /<!DOCTYPE/g,
- 'sh_preproc',
- 4,
- 1
- ],
- [
- /<!--/g,
- 'sh_comment',
- 5
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /&(?:[A-Za-z0-9]+);/g,
- 'sh_preproc',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /@[A-Za-z]+/g,
- 'sh_type',
- -1
- ],
- [
- /(?:TODO|FIXME|BUG)(?:[:]?)/g,
- 'sh_todo',
- -1
- ]
- ],
- [
- [
- /\?>/g,
- 'sh_preproc',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 3
- ]
- ],
- [
- [
- /\\(?:\\|")/g,
- null,
- -1
- ],
- [
- /"/g,
- 'sh_string',
- -2
- ]
- ],
- [
- [
- />/g,
- 'sh_preproc',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 3
- ]
- ],
- [
- [
- /-->/g,
- 'sh_comment',
- -2
- ],
- [
- /<!--/g,
- 'sh_comment',
- 5
- ]
- ],
- [
- [
- /(?:\/)?>/g,
- 'sh_keyword',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 3
- ]
- ],
- [
- [
- /$/g,
- null,
- -2
- ]
- ],
- [
- [
- /\*\//g,
- 'sh_comment',
- -2
- ],
- [
- /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
- 'sh_url',
- -1
- ],
- [
- /<\?xml/g,
- 'sh_preproc',
- 2,
- 1
- ],
- [
- /<!DOCTYPE/g,
- 'sh_preproc',
- 4,
- 1
- ],
- [
- /<!--/g,
- 'sh_comment',
- 5
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /&(?:[A-Za-z0-9]+);/g,
- 'sh_preproc',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z][A-Za-z0-9]*/g,
- 'sh_keyword',
- 6,
- 1
- ],
- [
- /@[A-Za-z]+/g,
- 'sh_type',
- -1
- ],
- [
- /(?:TODO|FIXME|BUG)(?:[:]?)/g,
- 'sh_todo',
- -1
- ]
- ],
- [
- [
- /\*\//g,
- 'sh_comment',
- -2
- ],
- [
- /(?:<?)[A-Za-z0-9_\.\/\-_~]+@[A-Za-z0-9_\.\/\-_~]+(?:>?)|(?:<?)[A-Za-z0-9_]+:\/\/[A-Za-z0-9_\.\/\-_~]+(?:>?)/g,
- 'sh_url',
- -1
- ],
- [
- /(?:TODO|FIXME|BUG)(?:[:]?)/g,
- 'sh_todo',
- -1
- ]
- ],
- [
- [
- /"/g,
- 'sh_string',
- -2
- ],
- [
- /\\./g,
- 'sh_specialchar',
- -1
- ]
- ],
- [
- [
- /'/g,
- 'sh_string',
- -2
- ],
- [
- /\\./g,
- 'sh_specialchar',
- -1
- ]
- ]
-];
diff --git a/keystone/content/common/js/shjs/sh_main.js b/keystone/content/common/js/shjs/sh_main.js
deleted file mode 100644
index 1fe3ea07..00000000
--- a/keystone/content/common/js/shjs/sh_main.js
+++ /dev/null
@@ -1,538 +0,0 @@
-/*
-SHJS - Syntax Highlighting in JavaScript
-Copyright (C) 2007, 2008 gnombat@users.sourceforge.net
-License: http://shjs.sourceforge.net/doc/gplv3.html
-*/
-
-if (! this.sh_languages) {
- this.sh_languages = {};
-}
-var sh_requests = {};
-
-function sh_isEmailAddress(url) {
- if (/^mailto:/.test(url)) {
- return false;
- }
- return url.indexOf('@') !== -1;
-}
-
-function sh_setHref(tags, numTags, inputString) {
- var url = inputString.substring(tags[numTags - 2].pos, tags[numTags - 1].pos);
- if (url.length >= 2 && url.charAt(0) === '<' && url.charAt(url.length - 1) === '>') {
- url = url.substr(1, url.length - 2);
- }
- if (sh_isEmailAddress(url)) {
- url = 'mailto:' + url;
- }
- tags[numTags - 2].node.href = url;
-}
-
-/*
-Konqueror has a bug where the regular expression /$/g will not match at the end
-of a line more than once:
-
- var regex = /$/g;
- var match;
-
- var line = '1234567890';
- regex.lastIndex = 10;
- match = regex.exec(line);
-
- var line2 = 'abcde';
- regex.lastIndex = 5;
- match = regex.exec(line2); // fails
-*/
-function sh_konquerorExec(s) {
- var result = [''];
- result.index = s.length;
- result.input = s;
- return result;
-}
-
-/**
-Highlights all elements containing source code in a text string. The return
-value is an array of objects, each representing an HTML start or end tag. Each
-object has a property named pos, which is an integer representing the text
-offset of the tag. Every start tag also has a property named node, which is the
-DOM element started by the tag. End tags do not have this property.
-@param inputString a text string
-@param language a language definition object
-@return an array of tag objects
-*/
-function sh_highlightString(inputString, language) {
- if (/Konqueror/.test(navigator.userAgent)) {
- if (! language.konquered) {
- for (var s = 0; s < language.length; s++) {
- for (var p = 0; p < language[s].length; p++) {
- var r = language[s][p][0];
- if (r.source === '$') {
- r.exec = sh_konquerorExec;
- }
- }
- }
- language.konquered = true;
- }
- }
-
- var a = document.createElement('a');
- var span = document.createElement('span');
-
- // the result
- var tags = [];
- var numTags = 0;
-
- // each element is a pattern object from language
- var patternStack = [];
-
- // the current position within inputString
- var pos = 0;
-
- // the name of the current style, or null if there is no current style
- var currentStyle = null;
-
- var output = function(s, style) {
- var length = s.length;
- // this is more than just an optimization - we don't want to output empty <span></span> elements
- if (length === 0) {
- return;
- }
- if (! style) {
- var stackLength = patternStack.length;
- if (stackLength !== 0) {
- var pattern = patternStack[stackLength - 1];
- // check whether this is a state or an environment
- if (! pattern[3]) {
- // it's not a state - it's an environment; use the style for this environment
- style = pattern[1];
- }
- }
- }
- if (currentStyle !== style) {
- if (currentStyle) {
- tags[numTags++] = {pos: pos};
- if (currentStyle === 'sh_url') {
- sh_setHref(tags, numTags, inputString);
- }
- }
- if (style) {
- var clone;
- if (style === 'sh_url') {
- clone = a.cloneNode(false);
- }
- else {
- clone = span.cloneNode(false);
- }
- clone.className = style;
- tags[numTags++] = {node: clone, pos: pos};
- }
- }
- pos += length;
- currentStyle = style;
- };
-
- var endOfLinePattern = /\r\n|\r|\n/g;
- endOfLinePattern.lastIndex = 0;
- var inputStringLength = inputString.length;
- while (pos < inputStringLength) {
- var start = pos;
- var end;
- var startOfNextLine;
- var endOfLineMatch = endOfLinePattern.exec(inputString);
- if (endOfLineMatch === null) {
- end = inputStringLength;
- startOfNextLine = inputStringLength;
- }
- else {
- end = endOfLineMatch.index;
- startOfNextLine = endOfLinePattern.lastIndex;
- }
-
- var line = inputString.substring(start, end);
-
- var matchCache = [];
- for (;;) {
- var posWithinLine = pos - start;
-
- var stateIndex;
- var stackLength = patternStack.length;
- if (stackLength === 0) {
- stateIndex = 0;
- }
- else {
- // get the next state
- stateIndex = patternStack[stackLength - 1][2];
- }
-
- var state = language[stateIndex];
- var numPatterns = state.length;
- var mc = matchCache[stateIndex];
- if (! mc) {
- mc = matchCache[stateIndex] = [];
- }
- var bestMatch = null;
- var bestPatternIndex = -1;
- for (var i = 0; i < numPatterns; i++) {
- var match;
- if (i < mc.length && (mc[i] === null || posWithinLine <= mc[i].index)) {
- match = mc[i];
- }
- else {
- var regex = state[i][0];
- regex.lastIndex = posWithinLine;
- match = regex.exec(line);
- mc[i] = match;
- }
- if (match !== null && (bestMatch === null || match.index < bestMatch.index)) {
- bestMatch = match;
- bestPatternIndex = i;
- if (match.index === posWithinLine) {
- break;
- }
- }
- }
-
- if (bestMatch === null) {
- output(line.substring(posWithinLine), null);
- break;
- }
- else {
- // got a match
- if (bestMatch.index > posWithinLine) {
- output(line.substring(posWithinLine, bestMatch.index), null);
- }
-
- var pattern = state[bestPatternIndex];
-
- var newStyle = pattern[1];
- var matchedString;
- if (newStyle instanceof Array) {
- for (var subexpression = 0; subexpression < newStyle.length; subexpression++) {
- matchedString = bestMatch[subexpression + 1];
- output(matchedString, newStyle[subexpression]);
- }
- }
- else {
- matchedString = bestMatch[0];
- output(matchedString, newStyle);
- }
-
- switch (pattern[2]) {
- case -1:
- // do nothing
- break;
- case -2:
- // exit
- patternStack.pop();
- break;
- case -3:
- // exitall
- patternStack.length = 0;
- break;
- default:
- // this was the start of a delimited pattern or a state/environment
- patternStack.push(pattern);
- break;
- }
- }
- }
-
- // end of the line
- if (currentStyle) {
- tags[numTags++] = {pos: pos};
- if (currentStyle === 'sh_url') {
- sh_setHref(tags, numTags, inputString);
- }
- currentStyle = null;
- }
- pos = startOfNextLine;
- }
-
- return tags;
-}
-
-////////////////////////////////////////////////////////////////////////////////
-// DOM-dependent functions
-
-function sh_getClasses(element) {
- var result = [];
- var htmlClass = element.className;
- if (htmlClass && htmlClass.length > 0) {
- var htmlClasses = htmlClass.split(' ');
- for (var i = 0; i < htmlClasses.length; i++) {
- if (htmlClasses[i].length > 0) {
- result.push(htmlClasses[i]);
- }
- }
- }
- return result;
-}
-
-function sh_addClass(element, name) {
- var htmlClasses = sh_getClasses(element);
- for (var i = 0; i < htmlClasses.length; i++) {
- if (name.toLowerCase() === htmlClasses[i].toLowerCase()) {
- return;
- }
- }
- htmlClasses.push(name);
- element.className = htmlClasses.join(' ');
-}
-
-/**
-Extracts the tags from an HTML DOM NodeList.
-@param nodeList a DOM NodeList
-@param result an object with text, tags and pos properties
-*/
-function sh_extractTagsFromNodeList(nodeList, result) {
- var length = nodeList.length;
- for (var i = 0; i < length; i++) {
- var node = nodeList.item(i);
- switch (node.nodeType) {
- case 1:
- if (node.nodeName.toLowerCase() === 'br') {
- var terminator;
- if (/MSIE/.test(navigator.userAgent)) {
- terminator = '\r';
- }
- else {
- terminator = '\n';
- }
- result.text.push(terminator);
- result.pos++;
- }
- else {
- result.tags.push({node: node.cloneNode(false), pos: result.pos});
- sh_extractTagsFromNodeList(node.childNodes, result);
- result.tags.push({pos: result.pos});
- }
- break;
- case 3:
- case 4:
- result.text.push(node.data);
- result.pos += node.length;
- break;
- }
- }
-}
-
-/**
-Extracts the tags from the text of an HTML element. The extracted tags will be
-returned as an array of tag objects. See sh_highlightString for the format of
-the tag objects.
-@param element a DOM element
-@param tags an empty array; the extracted tag objects will be returned in it
-@return the text of the element
-@see sh_highlightString
-*/
-function sh_extractTags(element, tags) {
- var result = {};
- result.text = [];
- result.tags = tags;
- result.pos = 0;
- sh_extractTagsFromNodeList(element.childNodes, result);
- return result.text.join('');
-}
-
-/**
-Merges the original tags from an element with the tags produced by highlighting.
-@param originalTags an array containing the original tags
-@param highlightTags an array containing the highlighting tags - these must not overlap
-@result an array containing the merged tags
-*/
-function sh_mergeTags(originalTags, highlightTags) {
- var numOriginalTags = originalTags.length;
- if (numOriginalTags === 0) {
- return highlightTags;
- }
-
- var numHighlightTags = highlightTags.length;
- if (numHighlightTags === 0) {
- return originalTags;
- }
-
- var result = [];
- var originalIndex = 0;
- var highlightIndex = 0;
-
- while (originalIndex < numOriginalTags && highlightIndex < numHighlightTags) {
- var originalTag = originalTags[originalIndex];
- var highlightTag = highlightTags[highlightIndex];
-
- if (originalTag.pos <= highlightTag.pos) {
- result.push(originalTag);
- originalIndex++;
- }
- else {
- result.push(highlightTag);
- if (highlightTags[highlightIndex + 1].pos <= originalTag.pos) {
- highlightIndex++;
- result.push(highlightTags[highlightIndex]);
- highlightIndex++;
- }
- else {
- // new end tag
- result.push({pos: originalTag.pos});
-
- // new start tag
- highlightTags[highlightIndex] = {node: highlightTag.node.cloneNode(false), pos: originalTag.pos};
- }
- }
- }
-
- while (originalIndex < numOriginalTags) {
- result.push(originalTags[originalIndex]);
- originalIndex++;
- }
-
- while (highlightIndex < numHighlightTags) {
- result.push(highlightTags[highlightIndex]);
- highlightIndex++;
- }
-
- return result;
-}
-
-/**
-Inserts tags into text.
-@param tags an array of tag objects
-@param text a string representing the text
-@return a DOM DocumentFragment representing the resulting HTML
-*/
-function sh_insertTags(tags, text) {
- var doc = document;
-
- var result = document.createDocumentFragment();
- var tagIndex = 0;
- var numTags = tags.length;
- var textPos = 0;
- var textLength = text.length;
- var currentNode = result;
-
- // output one tag or text node every iteration
- while (textPos < textLength || tagIndex < numTags) {
- var tag;
- var tagPos;
- if (tagIndex < numTags) {
- tag = tags[tagIndex];
- tagPos = tag.pos;
- }
- else {
- tagPos = textLength;
- }
-
- if (tagPos <= textPos) {
- // output the tag
- if (tag.node) {
- // start tag
- var newNode = tag.node;
- currentNode.appendChild(newNode);
- currentNode = newNode;
- }
- else {
- // end tag
- currentNode = currentNode.parentNode;
- }
- tagIndex++;
- }
- else {
- // output text
- currentNode.appendChild(doc.createTextNode(text.substring(textPos, tagPos)));
- textPos = tagPos;
- }
- }
-
- return result;
-}
-
-/**
-Highlights an element containing source code. Upon completion of this function,
-the element will have been placed in the "sh_sourceCode" class.
-@param element a DOM <pre> element containing the source code to be highlighted
-@param language a language definition object
-*/
-function sh_highlightElement(element, language) {
- sh_addClass(element, 'sh_sourceCode');
- var originalTags = [];
- var inputString = sh_extractTags(element, originalTags);
- var highlightTags = sh_highlightString(inputString, language);
- var tags = sh_mergeTags(originalTags, highlightTags);
- var documentFragment = sh_insertTags(tags, inputString);
- while (element.hasChildNodes()) {
- element.removeChild(element.firstChild);
- }
- element.appendChild(documentFragment);
-}
-
-function sh_getXMLHttpRequest() {
- if (window.ActiveXObject) {
- return new ActiveXObject('Msxml2.XMLHTTP');
- }
- else if (window.XMLHttpRequest) {
- return new XMLHttpRequest();
- }
- throw 'No XMLHttpRequest implementation available';
-}
-
-function sh_load(language, element, prefix, suffix) {
- if (language in sh_requests) {
- sh_requests[language].push(element);
- return;
- }
- sh_requests[language] = [element];
- var request = sh_getXMLHttpRequest();
- var url = prefix + 'sh_' + language + suffix;
- request.open('GET', url, true);
- request.onreadystatechange = function () {
- if (request.readyState === 4) {
- try {
- if (! request.status || request.status === 200) {
- eval(request.responseText);
- var elements = sh_requests[language];
- for (var i = 0; i < elements.length; i++) {
- sh_highlightElement(elements[i], sh_languages[language]);
- }
- }
- else {
- throw 'HTTP error: status ' + request.status;
- }
- }
- finally {
- request = null;
- }
- }
- };
- request.send(null);
-}
-
-/**
-Highlights all elements containing source code on the current page. Elements
-containing source code must be "pre" elements with a "class" attribute of
-"sh_LANGUAGE", where LANGUAGE is a valid language identifier; e.g., "sh_java"
-identifies the element as containing "java" language source code.
-*/
-function sh_highlightDocument(prefix, suffix) {
- var nodeList = document.getElementsByTagName('pre');
- for (var i = 0; i < nodeList.length; i++) {
- var element = nodeList.item(i);
- var htmlClasses = sh_getClasses(element);
- for (var j = 0; j < htmlClasses.length; j++) {
- var htmlClass = htmlClasses[j].toLowerCase();
- if (htmlClass === 'sh_sourcecode') {
- continue;
- }
- if (htmlClass.substr(0, 3) === 'sh_') {
- var language = htmlClass.substring(3);
- if (language in sh_languages) {
- sh_highlightElement(element, sh_languages[language]);
- }
- else if (typeof(prefix) === 'string' && typeof(suffix) === 'string') {
- sh_load(language, element, prefix, suffix);
- }
- else {
- throw 'Found <pre> element with class="' + htmlClass + '", but no such language exists';
- }
- break;
- }
- }
- }
-}
diff --git a/keystone/content/common/js/shjs/sh_xml.js b/keystone/content/common/js/shjs/sh_xml.js
deleted file mode 100644
index d6748ad4..00000000
--- a/keystone/content/common/js/shjs/sh_xml.js
+++ /dev/null
@@ -1,115 +0,0 @@
-if (! this.sh_languages) {
- this.sh_languages = {};
-}
-sh_languages['xml'] = [
- [
- [
- /<\?xml/g,
- 'sh_preproc',
- 1,
- 1
- ],
- [
- /<!DOCTYPE/g,
- 'sh_preproc',
- 3,
- 1
- ],
- [
- /<!--/g,
- 'sh_comment',
- 4
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)(?:\/)?>/g,
- 'sh_keyword',
- -1
- ],
- [
- /<(?:\/)?[A-Za-z](?:[A-Za-z0-9_:.-]*)/g,
- 'sh_keyword',
- 5,
- 1
- ],
- [
- /&(?:[A-Za-z0-9]+);/g,
- 'sh_preproc',
- -1
- ]
- ],
- [
- [
- /\?>/g,
- 'sh_preproc',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 2
- ]
- ],
- [
- [
- /\\(?:\\|")/g,
- null,
- -1
- ],
- [
- /"/g,
- 'sh_string',
- -2
- ]
- ],
- [
- [
- />/g,
- 'sh_preproc',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 2
- ]
- ],
- [
- [
- /-->/g,
- 'sh_comment',
- -2
- ],
- [
- /<!--/g,
- 'sh_comment',
- 4
- ]
- ],
- [
- [
- /(?:\/)?>/g,
- 'sh_keyword',
- -2
- ],
- [
- /([^=" \t>]+)([ \t]*)(=?)/g,
- ['sh_type', 'sh_normal', 'sh_symbol'],
- -1
- ],
- [
- /"/g,
- 'sh_string',
- 2
- ]
- ]
-];
diff --git a/keystone/content/common/js/trc/schema/controller.js b/keystone/content/common/js/trc/schema/controller.js
deleted file mode 100644
index b72d4015..00000000
--- a/keystone/content/common/js/trc/schema/controller.js
+++ /dev/null
@@ -1,184 +0,0 @@
-/**
- controller.js
-
- (C) 2009 Rackspace Hosting, All Rights Reserved
-
- This file definas a single object in global scope:
-
- trc.schema.controller
-
- The controller object is responsible for displaying a menu that
- allows users to view schema source and jump to various definitions
- in the schema.
- **/
-
-
-//
-// Initialization code...
-//
-(function()
- {
- //
- // Make sure dependecies are defined in the global scope, throw
- // an error if they are not.
- //
- if ((!window.trc) ||
- (!trc.util))
- {
- throw new Error("Require trc/util.js to be loaded.");
- }
-
- //
- // We use YUI to build our controller menu make sure we have the
- // proper dependecies loaded, call init when we do...
- //
-
- function InitController()
- {
- trc.schema.controller._init();
- }
-
- trc.util.yui.loadYUIDeps (["menu"], InitController);
- })();
-
-
-if (!trc.schema)
-{
- trc.schema = new Object();
-}
-
-trc.schema.controller = {
- //
- // Internal and external links by type:
- //
- // type --> array of links
- //
- // possible types include: import, include, element,
- // attribute, complextype, simpleType
- //
- // each link contains the following properties:
- // name : the name of the link
- // href : the link itself
- // title : a description of the link
- links : new Object(),
-
- //
- // A single link that points to the schema index document.
- //
- index : null,
-
- //
- // Our initialization function
- //
- _init : function() {
- //
- // Load the menu...
- //
- var controllerDiv = document.getElementById("Controller");
- var mainMenu = this._menuMarkup("mainmenu");
-
- for (var linkType in this.links)
- {
- var subItem = this._menuItemMarkup(mainMenu, linkType, "#", null);
- var subMenu = this._menuMarkup (linkType+"_subMenu");
-
- var items = this.links[linkType];
- for (var i=0;i<items.length;i++)
- {
- this._menuItemMarkup (subMenu,
- items[i].name,
- items[i].href,
- items[i].title);
- }
- subItem.item.appendChild (subMenu.main);
- }
-
- //
- // Toggle view source menu
- //
- this._menuItemMarkup (mainMenu, "toggle src view",
- "javascript:trc.schema.sampleManager.toggleSrcView()", null);
-
- //
- // Index schema document
- //
- if (this.index != null)
- {
- this._menuItemMarkup (mainMenu, this.index.name,
- this.index.href, this.index.title);
- }
-
- controllerDiv.appendChild (mainMenu.main);
- var oMenu = new YAHOO.widget.Menu("mainmenu", {position: "static"});
- oMenu.render();
- oMenu.show();
- },
-
- //
- // Builds menu markup returns the associated divs in the
- // properties main, body, header, footer, and list
- //
- _menuMarkup : function(id /*Id for main part*/)
- {
- //
- // Build our menu div...
- //
- var mainDiv = document.createElement("div");
- var headerDiv = document.createElement("div");
- var bodyDiv = document.createElement("div");
- var footerDiv = document.createElement("div");
- var listDiv = document.createElement("ul");
-
- mainDiv.setAttribute ("id", id);
- trc.util.dom.setClassName (mainDiv, "yuimenu");
- trc.util.dom.setClassName (headerDiv, "hd");
- trc.util.dom.setClassName (bodyDiv, "bd");
- trc.util.dom.setClassName (footerDiv, "ft");
-
- mainDiv.appendChild (headerDiv);
- mainDiv.appendChild (bodyDiv);
- mainDiv.appendChild (footerDiv);
- bodyDiv.appendChild (listDiv);
-
- return {
- main : mainDiv,
- body : bodyDiv,
- header : headerDiv,
- footer : footerDiv,
- list : listDiv
- };
- },
-
- //
- // Adds a menu item to existing markup.
- //
- _menuItemMarkup : function (menu, /*Markup returned from _menuMarkup*/
- name, /* String, menu item name */
- href, /* String, menu item href */
- title /* String, title (tool tip)*/
- )
- {
- var listItem = document.createElement ("li");
- var link = document.createElement ("a");
-
- trc.util.dom.setClassName (listItem, "yuimenuitem");
- trc.util.dom.setClassName (link, "yuimenuitemlabel");
-
- link.setAttribute ("href", href);
-
- if (title != null)
- {
- link.setAttribute ("title", title);
- }
-
- link.appendChild (document.createTextNode(name));
-
- listItem.appendChild (link);
- menu.list.appendChild(listItem);
-
- return {
- item : listItem,
- anchor : link
- };
- }
-};
diff --git a/keystone/content/common/js/trc/schema/layoutManager.js b/keystone/content/common/js/trc/schema/layoutManager.js
deleted file mode 100644
index f7a24b08..00000000
--- a/keystone/content/common/js/trc/schema/layoutManager.js
+++ /dev/null
@@ -1,137 +0,0 @@
-/**
- layoutManager.js
-
- (C) 2009 Rackspace Hosting, All Rights Reserved
-
- This file contains code that adjusts the layout of a schema
- document after a dom has been loaded. It does not modify the
- global scope.
-**/
-
-(function()
- {
- //
- // Make sure dependecies are defined in the global scope, throw
- // an error if they are not.
- //
- if ((!window.trc) ||
- (!trc.util))
- {
- throw new Error("Require trc/util.js to be loaded.");
- }
-
- //
- // This function should be called when the DOM is loaded so we
- // can get to work adjusting things.
- //
- function InitLayoutManager()
- {
- layoutManager._init();
- }
- trc.util.browser.addInitFunction (InitLayoutManager);
-
- var layoutManager={
- //
- // Initialization function...
- //
- _init : function()
- {
- this._adjustMain();
- this._adjustSubElements();
- },
-
- //
- // Applies appropriate styles to body and other main content
- // tags.
- //
- _adjustMain : function()
- {
- //
- // Change the class name for the correct YUI skin name.
- //
- var bodyTags = document.getElementsByTagName("body");
- if (bodyTags.length == 0)
- {
- throw new Error ("Couldn't find body element, bad DOM?");
- }
- else
- {
- trc.util.dom.setClassName(bodyTags[0], "yui-skin-sam");
- }
-
- //
- // Setout the layout...
- //
- var docDiv = document.getElementById("doc");
- var mainDiv = document.getElementById("Main");
-
- trc.util.dom.setClassName (docDiv, "yui-t1");
- docDiv.setAttribute ("id", "doc3");
- mainDiv.setAttribute ("id", "yui-main");
-
- //
- // Old IE browser hacks...
- //
- switch (trc.util.browser.detectIEVersion())
- {
- //
- // IE 6 does not support fixed positioning. The
- // following is a little hack to get it to work.
- //
- //
- case 6:
- var controllerDiv = document.getElementById("Controller");
- controllerDiv.style.position="absolute";
- window.setInterval((function(){
- /* avoid leak by constantly querying for the
- * controller. */
- var ctrlDiv = document.getElementById("Controller");
- ctrlDiv.style.top = document.documentElement.scrollTop+10;
- }), 1000);
- break;
-
- //
- // The controler doesn't work **at all** in IE 7
- // don't even show it.
- //
- case 7:
- var controllerDiv = document.getElementById("Controller");
- controllerDiv.style.display = "none";
- break;
- }
- },
-
- //
- // Adds appropriate classes for subElements...
- //
- _adjustSubElements : function()
- {
- var divs = document.getElementsByTagName("div");
- for (var i=0;i<divs.length;i++)
- {
- var currentClass = divs[i].getAttribute ("class");
- var newClassName = currentClass;
- switch (currentClass)
- {
- case "SubItem" :
- newClassName += " yui-gd";
- break;
- case "SubItemProps" :
- newClassName += " yui-gd first";
- break;
- case "SubName" :
- newClassName += " yui-u first";
- break;
- case "SubAttributes" :
- case "SubDocumentation" :
- newClassName += " yui-u";
- break;
- }
- if (currentClass != newClassName)
- {
- trc.util.dom.setClassName (divs[i], newClassName);
- }
- }
- }
- };
- })();
diff --git a/keystone/content/common/js/trc/schema/sampleManager.js b/keystone/content/common/js/trc/schema/sampleManager.js
deleted file mode 100644
index edb05b79..00000000
--- a/keystone/content/common/js/trc/schema/sampleManager.js
+++ /dev/null
@@ -1,342 +0,0 @@
-/**
- schemaManager.js:
-
- (C) 2009 Rackspace Hosting, All Rights Reserved
-
- This file defines a single object in global scope:
-
- trc.schema.sampleManager
-
- The object is responsible for loading, formatting, and displaying
- samples in schema files. It expects trc.util to be defined which is
- provided in trc/util.js.
-
- Code highlighting is provided by SHJS
- (http://shjs.sourceforge.net/). It should also be loaded before
- this code is initialized.
-
- All methods/properties prepended with an underscore (_) are meant
- for internal use.
- **/
-
-//
-// Initialization code...
-//
-(function()
- {
- //
- // Make sure dependecies are defined in the global scope, throw
- // an error if they are not.
- //
- if ((!window.trc) ||
- (!trc.util))
- {
- throw new Error("Require trc/util.js to be loaded.");
- }
-
- //
- // Make sure syntax highlighter scripts are loaded, if not then
- // load them.
- //
- if (!window.sh_highlightDocument)
- {
- trc.util.dom.addStyle ("../style/shjs/sh_darkblue.css");
-
- trc.util.dom.addScript ("../js/shjs/sh_main.js");
- trc.util.dom.addScript ("../js/shjs/sh_xml.js");
- trc.util.dom.addScript ("../js/shjs/sh_javascript.js");
- trc.util.dom.addScript ("../js/shjs/sh_java.js");
- }
-
- function InitSchemaSampleManager()
- {
- trc.schema.sampleManager._init();
- }
-
- trc.util.browser.addInitFunction(InitSchemaSampleManager);
- })();
-
-//
-// Define trc.schema.sampleManager...
-//
-if (!trc.schema)
-{
- trc.schema = new Object();
-}
-trc.schema.sampleManager = {
- //
- // All sample data in an associative array:
- //
- // Select Element ID -> Array of sample ids.
- //
- samples : new Object(),
-
- //
- // An array of code data..
- //
- // Code data is defined as an object with the following
- // properties:
- //
- // type: The mimetype of the code...href: The location of the code
- // or null if it's inline
- //
- // id: The id of the pre that contains the code.
- //
- // The initial object is the source code for the current document.
- //
- codes : new Array({
- id : "SrcContentCode",
- type : "application/xml",
- href : (function() {
- var ret = location.href;
- if (location.hash && (location.hash.length != 0))
- {
- ret = ret.replace (location.hash, "");
- }
- return ret;
- })()
- }),
-
- //
- // Sets up the manager, begins the loading process...
- //
- _init : function() {
- //
- // Setup an array to hold data items to load, this is used by
- // the loadSample method.
- //
- this._toLoad = new Array();
-
- for (var i=0;i<this.codes.length;i++)
- {
- if ((this.codes[i] != null) &&
- (this.codes[i].href != null))
- {
- this._toLoad.push (this.codes[i]);
- }
- }
-
- //
- // Loads the code text
- //
- this._loadCode();
- },
-
- //
- // Loads the next sample in the toLoad array.
- //
- _loadCode : function() {
- if (this._toLoad.length == 0)
- {
- //
- // All samples have been loaded, fire the loadComplete
- // method.
- //
- this._loadComplete();
- return;
- }
-
- var codeData = this._toLoad.pop();
- var request = trc.util.net.getHTTPRequest();
- var manager = this;
-
- request.onreadystatechange = function() {
- if (request.readyState == 4 /* Ready */) {
- if (request.status == 200 /* OKAY */) {
- manager._setCodeText (codeData, request.responseText);
- }
- else
- {
- manager._setCodeText (codeData, "Could not load sample ("+request.status+") "+request.responseText);
- }
- manager._loadCode();
- }
- };
-
- request.open ("GET", codeData.href);
- request.send(null);
- },
-
- //
- // Called after all samples are loaded into the DOM.
- //
- _loadComplete : function()
- {
- //
- // Normalize all code samples..
- //
- this._normalizeCodeText(1, 1, 5);
-
- //
- // Perform syntax highlighting...
- //
- sh_highlightDocument();
-
- //
- // All samples are initially hidden, show the selected
- // samples...
- //
- for (var optionID in this.samples)
- {
- this.showSample(optionID);
- }
-
- //
- // We've adjusted the document, we need to setup the view so
- // that we're still pointing to the hash target.
- //
- if (window.location.hash &&
- (window.location.hash.length != 0))
- {
- window.location.href = window.location.hash;
- }
- },
-
- //
- // Sets code text replacing any text already existing there.
- //
- _setCodeText : function ( codeData /* Info of the code to set (code object) */,
- code /* Code text to set (string) */)
- {
- //
- // Preprocess the txt if nessesary...
- //
- var ieVersion = trc.util.browser.detectIEVersion();
- if ((ieVersion > -1) &&
- (ieVersion < 8))
- {
- code = trc.util.text.unix2dos (code);
- }
-
- var pre = document.getElementById(codeData.id);
- var preNodes = pre.childNodes;
- //
- // Remove placeholder data...
- //
- while (preNodes.length != 0)
- {
- pre.removeChild (preNodes[0]);
- }
-
- //
- // Set the correct class type...
- //
- switch (codeData.type)
- {
- /*
- Javascript mimetypes
- */
- case 'application/json':
- case 'application/javascript':
- case 'application/x-javascript':
- case 'application/ecmascript':
- case 'text/ecmascript':
- case 'text/javascript':
- trc.util.dom.setClassName (pre, "sh_javascript");
- break;
- /*
- Not real mimetypes but this is what we'll use for Java.
- */
- case 'application/java':
- case 'text/java':
- trc.util.dom.setClassName (pre, "sh_java");
- break;
- default:
- trc.util.dom.setClassName (pre, "sh_xml");
- break;
- }
-
- //
- // Add new code...
- //
- pre.appendChild (document.createTextNode (code));
- },
-
- //
- // Retrives source code text
- //
- _getCodeText : function (codeData /* Info for the code to get*/)
- {
- var pre = document.getElementById(codeData.id);
- pre.normalize();
- //
- // Should be a single text node after pre...
- //
- return pre.firstChild.nodeValue;
- },
-
-
- //
- // Normalizes text by ensuring that top, bottom, right indent
- // levels are equal for all samples.
- //
- _normalizeCodeText : function (top, /* integer, top indent in lines */
- bottom, /* integer, bottom indent in lines */
- right /* integer, right indent in spaces */
- )
- {
- for (var i=0;i<this.codes.length;i++)
- {
- if (this.codes[i] != null)
- {
- var code = this._getCodeText (this.codes[i]);
- code = trc.util.text.setIndent (code, top, bottom, right);
- this._setCodeText (this.codes[i], code);
- }
- }
- },
-
- //
- // This event handler shows the appropriate sample given an ID
- // to the select element.
- //
- showSample : function (selectID) /* ID of the Select element */
- {
- //
- // Get the selected value
- //
- var selected = document.getElementById(selectID);
- var selectedValue = selected.options[selected.selectedIndex].value;
- var samples = this.samples[selectID];
-
- //
- // Undisplay old samples, display selected ones.
- //
- for (var i=0;i<samples.length;i++)
- {
- if (samples[i] != null)
- {
- var sample = document.getElementById (samples[i]);
- if (samples[i] == selectedValue)
- {
- sample.style.display = "block";
- }
- else
- {
- sample.style.display = "none";
- }
- }
- }
- },
-
- //
- // Toggles the current source view. If the source is displayed it
- // undisplays it and vice versa.
- //
- toggleSrcView : function()
- {
- var content = document.getElementById ("Content");
- var src = document.getElementById ("SrcContent");
-
- if (content.style.display != "none")
- {
- content.style.display = "none";
- src.style.display = "block";
- }
- else
- {
- content.style.display = "block";
- src.style.display = "none";
- }
- }
-};
diff --git a/keystone/content/common/js/trc/util.js b/keystone/content/common/js/trc/util.js
deleted file mode 100644
index 28267cf0..00000000
--- a/keystone/content/common/js/trc/util.js
+++ /dev/null
@@ -1,564 +0,0 @@
-/**
- util.js:
-
- (C) 2009 Rackspace Hosting, All Rights Reserved
-
- This file defines a single object in global scope:
-
- trc.util
-
- The util object contains internal objects which contain useful
- utility properties and methods.
-
- trc.util.browser: contains methods for browser detection.
-
- trc.util.dom: contains methods for manipulating the DOM.
-
- trc.util.text: contains methods and properties useful when working
- with plain text.
-
- trc.util.net: contains methods for creating HTTP requests.
-
- trc.util.yui : contains methods for working with the YUI toolkit.
-
- All methods/properties prepended with an underscore (_) are meant
- for internal use.
-**/
-
-//
-// Define TRC
-//
-if (!window.trc)
-{
- trc= new Object();
-}
-trc.util = new Object();
-trc.util.browser = {
- //
- // Returns the current version of IE, or -1 if it's not an IE
- // browser. This is one of the recomended ways of detecting IE
- // see:
- //
- // http://msdn.microsoft.com/en-us/library/ms537509%28VS.85%29.aspx
- //
- detectIEVersion : function() {
- var rv = -1; // Return value assumes failure.
- if (navigator.appName == 'Microsoft Internet Explorer')
- {
- var ua = navigator.userAgent;
- var re = new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})");
- if (re.exec(ua) != null)
- rv = parseFloat( RegExp.$1 );
- }
- return rv;
- },
-
- //
- // A list of functions to execute on init.
- //
- _initFuns : new Array(),
-
- //
- // Has the init function event been set?
- //
- _initFunSet: false,
-
- //
- // Function called when the DOM has loaded. It launches all init
- // functions.
- //
- _onInit : function()
- {
- //
- // Sort by order...
- //
- this._initFuns.sort(function(a, b){ return a.order - b.order; });
- for (var i=0;i<this._initFuns.length;i++)
- {
- this._initFuns[i]();
- }
- },
-
- //
- // Adds a function that should be executed when the dom is
- // loaded.
- //
- addInitFunction : function(init, /*Function to call after dom
- * is loaded*/
-
- order /* An optional it specifing
- * order. The bigger the int the
- * later it will run. Default is
- * 1.*/
- ) {
- if (arguments.length < 2)
- {
- init.order = 1;
- }
- else
- {
- init.order = order;
- }
- this._initFuns.push (init);
-
- if (!this._initFunSet)
- {
- var butil = this;
- function initFun()
- {
- return (function(){ butil._onInit(); });
- }
-
- //
- // Try event listeners, attachEvent and if that fails use
- // window.onload...
- //
- if (window.addEventListener)
- {
- window.addEventListener("load", initFun(), false);
- } else if (window.attachEvent)
- {
- window.attachEvent ("onload", initFun());
- } else
- {
- window.onload = initFun();
- }
-
- this._initFunSet = true;
- }
- }
-};
-
-trc.util.dom = {
- //
- // Adds a new script tag to the current DOM.
- //
- addScript : function (src /* Script href */)
- {
- var scriptElement = document.createElement ("script");
- scriptElement.setAttribute ("type", "text/javascript");
- scriptElement.setAttribute ("src", src);
-
- this.addToHead (scriptElement);
- },
-
- //
- // Adds a new stylesheet to the current DOM.
- //
- addStyle : function (src /* Stylesheet href */)
- {
- var linkElement = document.createElement ("link");
- linkElement.setAttribute ("rel", "stylesheet");
- linkElement.setAttribute ("type", "text/css");
- linkElement.setAttribute ("href", src);
-
- this.addToHead (linkElement);
- },
-
- //
- // Adds a DOM node to the HTTP head element. The element is
- // always added as the last child an error is thrown if the
- // head element can't be found.
- //
- addToHead : function (node /* A DOM node */)
- {
- var headArray = document.getElementsByTagName("head");
- if (headArray.length == 0)
- {
- throw new Error("Couldn't find head element, bad DOM?");
- }
- else
- {
- headArray[0].appendChild (node);
- }
- },
-
- //
- // Dum utility function for setting the class name of an
- // element. Eventually we'll move completely to XHTML, but
- // this will never work in IE 6, so for now we need this
- // method for setting the class name.
- //
- setClassName : function (element, /* DOM Element*/
- name /* Class name to use */
- )
- {
- var ieVersion = trc.util.browser.detectIEVersion();
-
- if ((ieVersion > -1) &&
- (ieVersion < 7))
- {
- element.className = name;
- }
- else
- {
- element.setAttribute ("class",name);
- }
- }
-};
-
-trc.util.text = {
- //
- // Useful RegExps
- //
- blank : new RegExp ("^\\s*$"), /* A blank string */
- indent : new RegExp ("^\\s+"), /* Line indent */
- lines : new RegExp ("$","m"), /* All lines */
- linechars : new RegExp ("(\n|\r)"), /* EOL line characters */
- tabs : new RegExp ("\t","g"), /* All tabs */
-
- //
- // We need this because microsoft browsers before IE 7, connot
- // display pre-formatted text correctly win unix style line
- // endings.
- //
- unix2dos : function(txt /* String */) {
- //if already DOS...
- if (txt.search(/\r\n/) != -1)
- {
- return txt;
- }
- return txt.replace (/\n/g, "\r\n");
- },
-
- //
- // Useful to normalize text.
- //
- dos2unix : function(txt /* String */) {
- //if already unix...
- if (txt.search(/\r\n/) == -1)
- {
- return txt;
- }
-
- return txt.replace(/\r/g, "");
- },
-
- //
- // Create a string with a character repeated x times.
- //
- repString : function (length, /* integer, size of the string to create */
- ch /* string, The character to set the string to */
- )
- {
- var ret = new String();
- for (var i=0;i<length;i++) {ret=ret.concat(ch);}
-
- return ret;
- },
-
- //
- // Replace tabs in a text with strings.
- //
- replaceTabs : function (txt, /* String to modify */
- length /* integer, tab length in spaces */
- )
- {
- var tabs = this.repString(length, " ");
- return txt.replace (this.tabs, tabs);
- },
-
- //
- // Given multi-line text returns Adjust top and bottom indent
- // (in lines) and right indent (in spaces)
- //
- setIndent : function (txt, /* String */
- top, /* integer, top indent in lines */
- bottom, /* integer, bottom indent in lines */
- right /* integer, right indent in spaces */
- )
- {
- //
- // Can't indent an empty string..
- //
- if (txt.length == 0)
- {
- return txt;
- }
-
- //
- // If not 0, bottom will be off by one...
- //
- if (bottom != 0)
- {
- bottom++;
- }
-
- var head=this.repString (top, "\n");
- var tail=this.repString (bottom, "\n");
- var marg=this.repString (right, " ");
- var ntxt = this.dos2unix(txt);
- var ntxt = this.replaceTabs (ntxt, 8);
- var lines = ntxt.split (this.lines);
- var origIndent=Number.MAX_VALUE;
- var origIndentStr;
-
- //
- // Look up indent.
- //
- for (var i=0;i<lines.length;i++)
- {
- //
- // Remove EOL characters...
- //
- lines[i] = lines[i].replace (this.linechars, "");
-
- //
- // Ignore blank lines
- //
- if (lines[i].match(this.blank) != null)
- {
- continue;
- }
-
- //
- // Detect the indent if any...
- //
- var result = lines[i].match(this.indent);
- if (result == null)
- {
- origIndent = 0;
- origIndentStr = "";
- }
- else if (result[0].length < origIndent)
- {
- origIndent = result[0].length;
- origIndentStr = result[0];
- }
- }
-
- //
- // This implys all line are blank...can't indent.
- //
- if (origIndent == Number.MAX_VALUE)
- {
- return txt;
- }
-
- if (origIndent != 0)
- {
- var regExStr = "^";
- for (var i=0;i<origIndent;i++)
- {
- regExStr=regExStr.concat("\\s");
- }
- var indent = new RegExp(regExStr);
- for (var i=0;i<lines.length;i++)
- {
- lines[i] = lines[i].replace(indent,marg);
- }
- }
- else
- {
- for (var i=0;i<lines.length;i++)
- {
- lines[i] = marg.concat (lines[i]);
- }
- }
-
- //
- // Remove top...
- //
- while (lines.length != 0)
- {
- if (lines[0].match(this.blank))
- {
- lines.shift();
- }
- else
- {
- break;
- }
- }
-
- //
- // Remove bottom...
- //
- while (lines.length != 0)
- {
- if (lines[lines.length-1].match(this.blank))
- {
- lines.pop();
- }
- else
- {
- break;
- }
- }
-
- var indented = lines.join("\n");
- indented=head.concat(indented, tail);
-
- return indented;
- }
-};
-
-trc.util.net = {
- //
- // A list of possible factories for creating an XMLHTTPRequest
- //
- _HTTPReqFactories :
- [
- function() { return new XMLHttpRequest(); },
- function() { return new ActiveXObject("Msxml2.XMLHTTP"); },
- function() { return new ActiveXObject("Microsoft.XMLHTTP"); }
- ],
-
- //
- // A cached XMLHTTPRequest factory that we know works in this
- // browser
- //
- _HTTPReqFactory : null,
-
- //
- // Provides a way of getting an HTTPRequest object in a
- // platform independent manner
- //
- getHTTPRequest : function()
- {
- //
- // Use cache if available..
- //
- if (this._HTTPReqFactory != null) return this._HTTPReqFactory();
-
- //
- // Search for a factory..
- //
- for (var i=0; i< this._HTTPReqFactories.length; i++)
- {
- try {
- var factory = this._HTTPReqFactories[i];
- var request = factory();
- if (request != null)
- {
- this._HTTPReqFactory = factory;
- return request;
- }
- } catch (e) {
- continue;
- }
- }
-
- //
- // Looks like we don't have support for XMLHttpRequest...
- //
- this._HTTPReqFactory = function() {throw new Error("XMLHttpRequest not supported");}
- this._HTTPReqFactory();
- return;
- }
-};
-
-
-//
-// Init code for trc.util.yui...
-//
-(function()
- {
- //
- // Menu make sure we have the YUI loader as it's used by our
- // init function to load YUI components.
- //
- if (!window.YAHOO)
- {
- //
- // We are currently using YUI on YAHOO!'s servers we may
- // want to change this.
- //
- var YUI_BASE="http://yui.yahooapis.com/2.7.0/";
-
- trc.util.dom.addScript (YUI_BASE+"build/yuiloader/yuiloader-min.js");
- }
-
- function InitYUIUtil()
- {
- trc.util.yui._init();
- }
- trc.util.browser.addInitFunction (InitYUIUtil);
- })();
-
-trc.util.yui = {
- //
- // A list of dependecies to be passed to the YUI loader. This is
- // essentially a hash set: dep->dep.
- //
- _deps : new Object(),
-
- //
- // An array of callback functions, these should be called when all
- // dependecies are loaded.
- //
- _callbacks : new Array(),
-
- //
- // The init function simply calls the YUI loader...
- //
- _init : function() {
- var yuiUtil = this;
-
- //
- // It takes safari a while to load the YUI Loader if it hasn't
- // loaded yet keep trying at 1/4 second intervals
- //
- if (!window.YAHOO)
- {
- window.setTimeout (function() {
- yuiUtil._init();
- }, 250);
- return;
- }
-
- //
- // Collect requirements...
- //
- var required = new Array();
- for (var req in this._deps)
- {
- required.push (req);
- }
-
- //
- // Load YUI dependecies...
- //
- var loader = new YAHOO.util.YUILoader({
- require: required,
- loadOptional: true,
- filter: "RAW",
- onSuccess: function() {
- yuiUtil._depsLoaded();
- },
- timeout: 10000,
- combine: true
- });
- loader.insert();
- },
-
- //
- // Called after all dependecies have been loaded
- //
- _depsLoaded : function() {
- //
- // Dependecies are loaded let everyone know.
- //
- for (var i=0;i<this._callbacks.length;i++)
- {
- this._callbacks[i]();
- }
- },
-
- //
- // Request that one or more YUI dependecies are loaded.
- //
- loadYUIDeps : function (deps, /*An array of dep strings */
- callback /*A function to call when deps are loaded*/
- )
- {
- for (var i=0;i<deps.length;i++)
- {
- this._deps[deps[i]] = deps[i];
- }
- if (callback != null)
- {
- this._callbacks.push (callback);
- }
- }
-};
diff --git a/keystone/content/common/samples/RAX-KSADM-userWithPassword.json b/keystone/content/common/samples/RAX-KSADM-userWithPassword.json
deleted file mode 100644
index 3f852ebe..00000000
--- a/keystone/content/common/samples/RAX-KSADM-userWithPassword.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "user": {
- "username": "jqsmith",
- "password": "Secret0",
- "email": "john.smith@example.org",
- "enabled": true
- }
-} \ No newline at end of file
diff --git a/keystone/content/common/samples/RAX-KSADM-userWithPassword.xml b/keystone/content/common/samples/RAX-KSADM-userWithPassword.xml
deleted file mode 100644
index 68b82692..00000000
--- a/keystone/content/common/samples/RAX-KSADM-userWithPassword.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<user xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:type="UserWithPassword"
- enabled="true" email="john.smith@example.org"
- username="jqsmith" password="Secret0" /> \ No newline at end of file
diff --git a/keystone/content/common/samples/RAX-KSGRP-groups.json b/keystone/content/common/samples/RAX-KSGRP-groups.json
deleted file mode 100644
index 7e5ac29d..00000000
--- a/keystone/content/common/samples/RAX-KSGRP-groups.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "RAX-KSGRP:groups": [
- {
- "id": "test_global_group_add",
- "description": "A description ..."
- }
- ],
- "RAX-KSGRP:groups_links": []
-}
diff --git a/keystone/content/common/samples/RAX-KSGRP-groups.xml b/keystone/content/common/samples/RAX-KSGRP-groups.xml
deleted file mode 100644
index 3a6a43ba..00000000
--- a/keystone/content/common/samples/RAX-KSGRP-groups.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<groups xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSGRP/v1.0">
- <group xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSGRP/v1.0" id="test_global_group_add">
- <description>A Description of the group</description>
- </group>
-</groups>
diff --git a/keystone/content/common/samples/RAX-KSQA-secretQA.json b/keystone/content/common/samples/RAX-KSQA-secretQA.json
deleted file mode 100644
index 6baf6e32..00000000
--- a/keystone/content/common/samples/RAX-KSQA-secretQA.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "RAX-KSQA:secretQA": {
- "question": "What is the color of my eyes?",
- "answer": "Leonardo Da Vinci"
- }
-}
diff --git a/keystone/content/common/samples/RAX-KSQA-secretQA.xml b/keystone/content/common/samples/RAX-KSQA-secretQA.xml
deleted file mode 100644
index c6570af6..00000000
--- a/keystone/content/common/samples/RAX-KSQA-secretQA.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<secretQA xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSQA/v1.0"
- question="What is the color of my eyes?"
- answer="Leonardo Da Vinci" />
-
-
diff --git a/keystone/content/common/samples/apiKeyCredentials.json b/keystone/content/common/samples/apiKeyCredentials.json
deleted file mode 100644
index 4b59ac3b..00000000
--- a/keystone/content/common/samples/apiKeyCredentials.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "RAX-KSKEY:apiKeyCredentials": {
- "username": "test_user",
- "apiKey": "aaaaa-bbbbb-ccccc-12345678"
- }
-}
diff --git a/keystone/content/common/samples/apiKeyCredentials.xml b/keystone/content/common/samples/apiKeyCredentials.xml
deleted file mode 100644
index 7a4b0fdb..00000000
--- a/keystone/content/common/samples/apiKeyCredentials.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<apiKeyCredentials
- xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
- username="testuser"
- apiKey="aaaaa-bbbbb-ccccc-12345678"/>
-
diff --git a/keystone/content/common/samples/auth.json b/keystone/content/common/samples/auth.json
deleted file mode 100644
index 6730360f..00000000
--- a/keystone/content/common/samples/auth.json
+++ /dev/null
@@ -1,98 +0,0 @@
-{
- "access": {
- "token": {
- "id": "ab48a9efdfedb23ty3494",
- "expires": "2010-11-01T03:32:15-05:00",
- "tenant": {
- "id": "t1000",
- "name": "My Project"
- },
- "tenants": [{
- "id": "t1000",
- "name": "My Project"
- }]
- },
- "user": {
- "id": "u123",
- "name": "jqsmith",
- "roles": [
- {
- "id": "100",
- "name": "compute:admin"
- },
- {
- "id": "101",
- "name": "object-store:admin",
- "tenantId": "t1000"
- }
- ],
- "roles_links": []
- },
- "serviceCatalog": [
- {
- "name": "Cloud Servers",
- "type": "compute",
- "endpoints": [
- {
- "id": "1",
- "tenantId": "t1000",
- "publicURL": "https://compute.north.host.com/v1/t1000",
- "internalURL": "https://compute.north.internal/v1/t1000",
- "region": "North",
- "versionId": "1",
- "versionInfo": "https://compute.north.host.com/v1/",
- "versionList": "https://compute.north.host.com/"
- },
- {
- "id": "2",
- "tenantId": "t1000",
- "publicURL": "https://compute.north.host.com/v1.1/t1000",
- "internalURL": "https://compute.north.internal/v1.1/t1000",
- "region": "North",
- "versionId": "1.1",
- "versionInfo": "https://compute.north.host.com/v1.1/",
- "versionList": "https://compute.north.host.com/"
- }
- ],
- "endpoints_links": []
- },
- {
- "name": "Cloud Files",
- "type": "object-store",
- "endpoints": [
- {
- "tenantId": "t1000",
- "publicURL": "https://storage.north.host.com/v1/t1000",
- "internalURL": "https://storage.north.internal/v1/t1000",
- "region": "North",
- "versionId": "1",
- "versionInfo": "https://storage.north.host.com/v1/",
- "versionList": "https://storage.north.host.com/"
- },
- {
- "tenantId": "t1000",
- "publicURL": "https://storage.south.host.com/v1/t1000",
- "internalURL": "https://storage.south.internal/v1/t1000",
- "region": "South",
- "versionId": "1",
- "versionInfo": "https://storage.south.host.com/v1/",
- "versionList": "https://storage.south.host.com/"
- }
- ]
- },
- {
- "name": "DNS-as-a-Service",
- "type": "dnsextension:dns",
- "endpoints": [
- {
- "tenantId": "t1000",
- "publicURL": "https://dns.host.com/v2.0/t1000",
- "versionId": "2.0",
- "versionInfo": "https://dns.host.com/v2.0/",
- "versionList": "https://dns.host.com/"
- }
- ]
- }
- ]
- }
-}
diff --git a/keystone/content/common/samples/auth.xml b/keystone/content/common/samples/auth.xml
deleted file mode 100644
index 21efa79d..00000000
--- a/keystone/content/common/samples/auth.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<access xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <token id="ab48a9efdfedb23ty3494" expires="2010-11-01T03:32:15-05:00">
- <tenant id="t1000" name="My Project" />
- </token>
- <user id="u123" name="jqsmith">
- <roles>
- <role id="100" name="compute:admin"/>
- <role id="101" name="object-store:admin" tenantId="t1000"/>
- </roles>
- </user>
- <serviceCatalog>
- <service type="compute" name="Cloud Servers">
- <endpoint
- id="1"
- tenantId="t1000"
- region="North"
- publicURL="https://compute.north.host.com/v1/t1000"
- internalURL="https://compute.north.host.internal/v1/t1000">
- <version
- id="1"
- info="https://compute.north.host.com/v1/"
- list="https://compute.north.host.com/"
- />
- </endpoint>
- <endpoint
- id="2"
- tenantId="t1000"
- region="North"
- publicURL="https://compute.north.host.com/v1.1/t1000"
- internalURL="https://compute.north.host.internal/v1.1/t1000">
- <version
- id="1.1"
- info="https://compute.north.host.com/v1.1/"
- list="https://compute.north.host.com/" />
- </endpoint>
- </service>
- <service type="object-store" name="Cloud Files">
- <endpoint
- id="3"
- tenantId="t1000"
- region="North"
- publicURL="https://storage.north.host.com/v1/t1000"
- internalURL="https://storage.north.host.internal/v1/t1000">
- <version
- id="1"
- info="https://storage.north.host.com/v1/"
- list="https://storage.north.host.com/" />
- </endpoint>
- <endpoint
- id="4"
- tenantId="t1000"
- region="South"
- publicURL="https://storage.south.host.com/v1/t1000"
- internalURL="https://storage.south.host.internal/v1/t1000">
- <version
- id="1"
- info="https://storage.south.host.com/v1/"
- list="https://storage.south.host.com/" />
- </endpoint>
- </service>
- <service type="dnsextension:dns" name="DNS-as-a-Service">
- <endpoint
- id="5"
- tenantId="t1000"
- publicURL="https://dns.host.com/v2.0/t1000">
- <version
- id="2.0"
- info="https://dns.host.com/v2.0/"
- list="https://dns.host.com/" />
- </endpoint>
- </service>
- </serviceCatalog>
-</access>
diff --git a/keystone/content/common/samples/auth_credentials-OS-KSEC2.json b/keystone/content/common/samples/auth_credentials-OS-KSEC2.json
deleted file mode 100644
index 45c987e6..00000000
--- a/keystone/content/common/samples/auth_credentials-OS-KSEC2.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "auth": {
- "OS-KSEC2:ec2Credentials": {
- "username": "test_user",
- "secret": "aaaaa",
- "signature": "bbb"
- },
- "tenantId": "77654"
- }
-}
diff --git a/keystone/content/common/samples/auth_credentials-OS-KSEC2.xml b/keystone/content/common/samples/auth_credentials-OS-KSEC2.xml
deleted file mode 100644
index ec4f3314..00000000
--- a/keystone/content/common/samples/auth_credentials-OS-KSEC2.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<auth
- xmlns="http://docs.openstack.org/identity/api/v2.0"
- tenantId="1234">
- <ec2Credentials
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- username="testuser"
- key="aaaaa"
- signature="bbbbb"/>
-</auth>
diff --git a/keystone/content/common/samples/auth_credentials-RAX-KSKEY.json b/keystone/content/common/samples/auth_credentials-RAX-KSKEY.json
deleted file mode 100644
index 29f78dcd..00000000
--- a/keystone/content/common/samples/auth_credentials-RAX-KSKEY.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "auth": {
- "RAX-KSKEY:apiKeyCredentials": {
- "username": "test_user",
- "apiKey": "aaaaa-bbbbb-ccccc-12345678"
- },
- "tenantId": "1234"
- }
-}
diff --git a/keystone/content/common/samples/auth_credentials-RAX-KSKEY.xml b/keystone/content/common/samples/auth_credentials-RAX-KSKEY.xml
deleted file mode 100644
index a4284f95..00000000
--- a/keystone/content/common/samples/auth_credentials-RAX-KSKEY.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<auth xmlns="http://docs.openstack.org/identity/api/v2.0">
- <apiKeyCredentials
- xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
- username="testuser"
- apiKey="aaaaa-bbbbb-ccccc-12345678"/>
-</auth>
diff --git a/keystone/content/common/samples/auth_credentials.json b/keystone/content/common/samples/auth_credentials.json
deleted file mode 100644
index 00fb7826..00000000
--- a/keystone/content/common/samples/auth_credentials.json
+++ /dev/null
@@ -1,9 +0,0 @@
-{
- "auth": {
- "passwordCredentials": {
- "username": "test_user",
- "password": "mypass"
- },
- "tenantName": "customer-x"
- }
-}
diff --git a/keystone/content/common/samples/auth_credentials.xml b/keystone/content/common/samples/auth_credentials.xml
deleted file mode 100644
index 6621b83a..00000000
--- a/keystone/content/common/samples/auth_credentials.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0"
- tenantName="customer-x">
- <passwordCredentials username="test_user" password="test"/>
-</auth>
diff --git a/keystone/content/common/samples/auth_with_token.json b/keystone/content/common/samples/auth_with_token.json
deleted file mode 100644
index 7a765eba..00000000
--- a/keystone/content/common/samples/auth_with_token.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "auth": {
- "tenantName": "customer-x",
- "token": {
- "id": "abcdefghijk"
- }
- }
-}
diff --git a/keystone/content/common/samples/auth_with_token.xml b/keystone/content/common/samples/auth_with_token.xml
deleted file mode 100644
index 5190f62a..00000000
--- a/keystone/content/common/samples/auth_with_token.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0"
- tenantName="customer-x">
- <token id="abcdefghijk" />
-</auth>
-
diff --git a/keystone/content/common/samples/authwithgroups.json b/keystone/content/common/samples/authwithgroups.json
deleted file mode 100644
index d364ebb4..00000000
--- a/keystone/content/common/samples/authwithgroups.json
+++ /dev/null
@@ -1,94 +0,0 @@
-{
- "access": {
- "token": {
- "id": "asdasdasd-adsasdads-asdasdasd-adsadsasd",
- "expires": "2010-11-01T03:32:15-05:00"
- },
- "user": {
- "id": "123",
- "name": "testName",
- "roles": [
- {
- "id": "234",
- "name": "compute:admin"
- },
- {
- "id": "235",
- "name": "object-store:admin",
- "tenantId": "1"
- }
- ],
- "roles_links": [],
- "RAX-KSGRP:groups": [
- {
- "id": "test_global_group_add",
- "description": "A description ..."
- }
- ],
- "RAX-KSGRP:groups_links": []
- },
- "serviceCatalog": [
- {
- "name": "Cloud Servers",
- "type": "compute",
- "endpoints": [
- {
- "publicURL": "https://compute.north.host/v1/1234",
- "internalURL": "https://compute.north.host/v1/1234",
- "region": "North",
- "tenantId": "1234",
- "versionId": "1.0",
- "versionInfo": "https://compute.north.host/v1.0/",
- "versionList": "https://compute.north.host/"
- },
- {
- "publicURL": "https://compute.north.host/v1.1/3456",
- "internalURL": "https://compute.north.host/v1.1/3456",
- "region": "North",
- "tenantId": "3456",
- "versionId": "1.1",
- "versionInfo": "https://compute.north.host/v1.1/",
- "versionList": "https://compute.north.host/"
- }
- ],
- "endpoints_links": []
- },
- {
- "name": "Cloud Files",
- "type": "object-store",
- "endpoints": [
- {
- "publicURL": "https://compute.north.host/v1/blah-blah",
- "internalURL": "https://compute.north.host/v1/blah-blah",
- "region": "South",
- "tenantId": "1234",
- "versionId": "1.0",
- "versionInfo": "uri",
- "versionList": "uri"
- },
- {
- "publicURL": "https://compute.north.host/v1.1/blah-blah",
- "internalURL": "https://compute.north.host/v1.1/blah-blah",
- "region": "South",
- "tenantId": "1234",
- "versionId": "1.1",
- "versionInfo": "https://compute.north.host/v1.1/",
- "versionList": "https://compute.north.host/"
- }
- ],
- "endpoints_links": [
- {
- "rel": "next",
- "href": "https://identity.north.host/v2.0/endpoints?marker=2"
- }
- ]
- }
- ],
- "serviceCatalog_links": [
- {
- "rel": "next",
- "href": "https://identity.host/v2.0/endpoints?session=2hfh8Ar&marker=2"
- }
- ]
- }
-}
diff --git a/keystone/content/common/samples/authwithgroups.xml b/keystone/content/common/samples/authwithgroups.xml
deleted file mode 100644
index f8c6981b..00000000
--- a/keystone/content/common/samples/authwithgroups.xml
+++ /dev/null
@@ -1,70 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<access xmlns="http://docs.openstack.org/identity/api/v2.0">
- <token expires="2010-11-01T03:32:15-05:00"
- id="ab48a9efdfedb23ty3494"/>
- <serviceCatalog>
- <service type="compute" name="Computers in the Cloud">
- <endpoint region="North" tenantId="1"
- publicURL="https://north.compute.public.com/v2.0/1234"
- internalURL="https://north.compute.internal.com/v2.0/1234">
- <version id="2.0"
- info="https://north.compute.public.com/v2.0/"
- list="https://north.compute.public.com/"/>
- </endpoint>
- <endpoint
- region="South"
- tenantId="3456"
- publicURL="https://south.compute.public.com/v2.0/3456"
- internalURL="https://south.compute.internal.com/v2.0/3456">
- <version
- id="2.0"
- info="https://south.compute.public.com/v2.0/"
- list="https://south.compute.public.com/" />
- </endpoint>
- </service>
- <service type="object-store" name="HTTP Object Store">
- <endpoint
- region="North"
- tenantId="1234"
- publicURL="https://north.object-store.public.com/v1/1234"
- internalURL="https://north.object-store.internal.com/v1/1234">
- <version
- id="1"
- info="https://north.object-store.public.com/v1/"
- list="https://north.object-store.public.com/" />
- </endpoint>
- <endpoint
- region="South"
- tenantId="3456"
- publicURL="https://south.object-store.public.com/v2.0/3456"
- internalURL="https://south.object-store.internal.com/v2.0/3456">
- <version
- id="2.0"
- info="https://south.object-store.public.com/v1/"
- list="https://south.object-store.public.com/" />
- </endpoint>
- </service>
- <service type="dns" name="DNS-as-a-Service">
- <endpoint
- publicURL="https://dns.public.com/v2.0/blah-blah">
- <version
- id="2.0"
- info="https://dns.public.com/v2.0/"
- list="https://dns.public.com/" />
- </endpoint>
- </service>
- </serviceCatalog>
- <user xmlns="http://docs.openstack.org/identity/api/v2.0"
- id="123" username="jqsmith">
- <roles xmlns="http://docs.openstack.org/identity/api/v2.0">
- <role id="123" name="Admin" tenantId="1234" description="All Access" />
- <role id="234" name="object-store:admin" tenantId="1"/>
-
- </roles>
- <groups xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSGRP/v1.0">
- <group id="test_global_group_add">
- <description>A Description of the group</description>
- </group>
- </groups>
- </user>
-</auth>
diff --git a/keystone/content/common/samples/choices.json b/keystone/content/common/samples/choices.json
deleted file mode 100644
index 259b8c42..00000000
--- a/keystone/content/common/samples/choices.json
+++ /dev/null
@@ -1,71 +0,0 @@
-{
- "choices": [
- {
- "id": "v1.0",
- "status": "DEPRECATED",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v1.0"
- }
- ],
- "media-types": {
- "values": [
- {
- "base": "application/xml",
- "type": "application/vnd.openstack.identity+xml;version=1.0"
- },
- {
- "base": "application/json",
- "type": "application/vnd.openstack.identity+json;version=1.0"
- }
- ]
- }
- },
- {
- "id": "v1.1",
- "status": "CURRENT",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v1.1"
- }
- ],
- "media-types": {
- "values": [
- {
- "base": "application/xml",
- "type": "application/vnd.openstack.identity+xml;version=1.1"
- },
- {
- "base": "application/json",
- "type": "application/vnd.openstack.identity+json;version=1.1"
- }
- ]
- }
- },
- {
- "id": "v2.0",
- "status": "BETA",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v2.0"
- }
- ],
- "media-types": {
- "values": [
- {
- "base": "application/xml",
- "type": "application/vnd.openstack.identity+xml;version=2.0"
- },
- {
- "base": "application/json",
- "type": "application/vnd.openstack.identity+json;version=2.0"
- }
- ]
- }
- }
- ],
- "choices_links": ""
-}
diff --git a/keystone/content/common/samples/choices.xml b/keystone/content/common/samples/choices.xml
deleted file mode 100644
index 834a1987..00000000
--- a/keystone/content/common/samples/choices.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<choices
- xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <version id="v1.0" status="DEPRECATED">
- <media-types>
- <media-type
- base="application/xml"
- type="application/vnd.openstack.identity+xml;version=1.0" />
- <media-type
- base="application/json"
- type="application/vnd.openstack.identity+json;version=1.0" />
- </media-types>
- <atom:link rel="self" href="http://identity.api.openstack.org/v1.0" />
- </version>
- <version id="v1.1" status="CURRENT">
- <media-types>
- <media-type
- base="application/xml"
- type="application/vnd.openstack.identity+xml;version=1.1" />
- <media-type
- base="application/json"
- type="application/vnd.openstack.identity+json;version=1.1" />
- </media-types>
- <atom:link rel="self" href="http://identity.api.openstack.org/v1.1" />
- </version>
- <version id="v2.0" status="BETA">
- <media-types>
- <media-type
- base="application/xml"
- type="application/vnd.openstack.identity+xml;version=2.0" />
- <media-type
- base="application/json"
- type="application/vnd.openstack.identity+json;version=2.0" />
- </media-types>
- <atom:link rel="self" href="http://identity.api.openstack.org/v2.0" />
- </version>
-</choices>
diff --git a/keystone/content/common/samples/credentials.json b/keystone/content/common/samples/credentials.json
deleted file mode 100644
index 584fc3a1..00000000
--- a/keystone/content/common/samples/credentials.json
+++ /dev/null
@@ -1,11 +0,0 @@
-{
- "credentials": [
- {
- "passwordCredentials": {
- "username": "test_user",
- "password": "mypass"
- }
- }
- ],
- "credentials_links": []
-}
diff --git a/keystone/content/common/samples/credentials.xml b/keystone/content/common/samples/credentials.xml
deleted file mode 100644
index 8efa9f2e..00000000
--- a/keystone/content/common/samples/credentials.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<credentials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <passwordCredentials username="test_user" password="test"/>
-</credentials>
diff --git a/keystone/content/common/samples/credentialswithapikey.json b/keystone/content/common/samples/credentialswithapikey.json
deleted file mode 100644
index 8ab8f2cd..00000000
--- a/keystone/content/common/samples/credentialswithapikey.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "credentials": [
- {
- "passwordCredentials": {
- "username": "test_user",
- "password": "mypass"
- }
- },
- {
- "RAX-KSKEY:apiKeyCredentials": {
- "username": "test_user",
- "apiKey": "aaaaa-bbbbb-ccccc-12345678"
- }
- }
- ],
- "credentials_links": []
-}
diff --git a/keystone/content/common/samples/credentialswithapikey.xml b/keystone/content/common/samples/credentialswithapikey.xml
deleted file mode 100644
index 762016e8..00000000
--- a/keystone/content/common/samples/credentialswithapikey.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<credentials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <passwordCredentials username="test_user" password="test"/>
- <apiKeyCredentials
- xmlns="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
- username="testuser"
- apiKey="aaaaa-bbbbb-ccccc-12345678"/>
-</credentials>
diff --git a/keystone/content/common/samples/credentialswithec2.json b/keystone/content/common/samples/credentialswithec2.json
deleted file mode 100644
index 8da6844e..00000000
--- a/keystone/content/common/samples/credentialswithec2.json
+++ /dev/null
@@ -1,18 +0,0 @@
-{
- "credentials": [
- {
- "passwordCredentials": {
- "username": "test_user",
- "password": "mypass"
- }
- },
- {
- "OS-KSEC2:ec2Credentials": {
- "username": "test_user",
- "secret": "aaaaa",
- "signature": "bbb"
- }
- }
- ],
- "credentials_links": []
-}
diff --git a/keystone/content/common/samples/credentialswithec2.xml b/keystone/content/common/samples/credentialswithec2.xml
deleted file mode 100644
index b6ded2a3..00000000
--- a/keystone/content/common/samples/credentialswithec2.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<credentials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <passwordCredentials username="test_user" password="test"/>
- <ec2Credentials xmlns="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- username="testuser" key="aaaaa" signature="bbbbb"/>
-</credentials>
diff --git a/keystone/content/common/samples/credentialswiths3.json b/keystone/content/common/samples/credentialswiths3.json
deleted file mode 100644
index fb286205..00000000
--- a/keystone/content/common/samples/credentialswiths3.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "credentials":[{
- "passwordCredentials":{
- "username":"test_user",
- "password":"mypass"
- }
- },
- {
- "OS-KSS3:s3Credentials":{
- "username":"test_user",
- "secret":"aaaaa",
- "signature":"bbb"
- }
- }
- ],
- "credentials_links":[]
-}
diff --git a/keystone/content/common/samples/credentialswiths3.xml b/keystone/content/common/samples/credentialswiths3.xml
deleted file mode 100644
index 4c482d8a..00000000
--- a/keystone/content/common/samples/credentialswiths3.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<credentials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <passwordCredentials username="test_user" password="test"/>
- <s3Credentials xmlns="http://docs.openstack.org/identity/api/ext/OS-KSS3/v1.0"
- username="testuser" key="aaaaa" signature="bbbbb"/>
-</credentials>
diff --git a/keystone/content/common/samples/ec2Credentials.json b/keystone/content/common/samples/ec2Credentials.json
deleted file mode 100644
index e72ee28c..00000000
--- a/keystone/content/common/samples/ec2Credentials.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "OS-KSEC2:ec2Credentials": {
- "username": "test_user",
- "secret": "aaaaa",
- "signature": "bbb"
- }
-}
diff --git a/keystone/content/common/samples/ec2Credentials.xml b/keystone/content/common/samples/ec2Credentials.xml
deleted file mode 100644
index e36f231c..00000000
--- a/keystone/content/common/samples/ec2Credentials.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <ec2Credentials
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- username="testuser"
- key="aaaaa"
- signature="bbbbb"/>
-
diff --git a/keystone/content/common/samples/endpoint.json b/keystone/content/common/samples/endpoint.json
deleted file mode 100644
index aad05b62..00000000
--- a/keystone/content/common/samples/endpoint.json
+++ /dev/null
@@ -1,14 +0,0 @@
-{
- "endpoint": {
- "id": 1,
- "tenantId": 1,
- "region": "North",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "adminURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/"
- }
-}
diff --git a/keystone/content/common/samples/endpoint.xml b/keystone/content/common/samples/endpoint.xml
deleted file mode 100644
index cd09b24a..00000000
--- a/keystone/content/common/samples/endpoint.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<endpoint
- id="1"
- tenantId="1"
- type="compute"
- name="Compute"
- region="North"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- adminURL="https://compute.north.internal.com/v1"
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <version
- id="1"
- info="https://compute.north.public.com/v1/"
- list="https://compute.north.public.com/"
- />
-</endpoint> \ No newline at end of file
diff --git a/keystone/content/common/samples/endpointTemplate.json b/keystone/content/common/samples/endpointTemplate.json
deleted file mode 100644
index 4cf6c4d1..00000000
--- a/keystone/content/common/samples/endpointTemplate.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "OS-KSCATALOG:endpointTemplate": {
- "id": 1,
- "region": "North",
- "global": true,
- "name": "nova",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/endpointTemplate.xml b/keystone/content/common/samples/endpointTemplate.xml
deleted file mode 100644
index 37f98091..00000000
--- a/keystone/content/common/samples/endpointTemplate.xml
+++ /dev/null
@@ -1,18 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<endpointTemplate
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0"
- id="1"
- region="North"
- global="true"
- type="compute"
- name="Nova"
- publicURL="https://service-public.com/v1"
- internalURL="https://service-internal.com/v1"
- enabled="true">
- <version
- id="1"
- info="https://compute.north.public.com/v1/"
- list="https://compute.north.public.com/"
- />
-</endpointTemplate> \ No newline at end of file
diff --git a/keystone/content/common/samples/endpointTemplateWithOnlyId.json b/keystone/content/common/samples/endpointTemplateWithOnlyId.json
deleted file mode 100644
index e2fa47f7..00000000
--- a/keystone/content/common/samples/endpointTemplateWithOnlyId.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "OS-KSCATALOG:endpointTemplate": {
- "id": 1
- }
-}
diff --git a/keystone/content/common/samples/endpointTemplateWithOnlyId.xml b/keystone/content/common/samples/endpointTemplateWithOnlyId.xml
deleted file mode 100644
index 6379b3ae..00000000
--- a/keystone/content/common/samples/endpointTemplateWithOnlyId.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<endpointTemplate
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:type="EndpointTemplateWithOnlyId"
- id="1"/>
diff --git a/keystone/content/common/samples/endpointTemplates.json b/keystone/content/common/samples/endpointTemplates.json
deleted file mode 100644
index ab683ae8..00000000
--- a/keystone/content/common/samples/endpointTemplates.json
+++ /dev/null
@@ -1,59 +0,0 @@
-{
- "OS-KSCATALOG:endpointsTemplates": [
- {
- "id": 1,
- "region": "North",
- "global": true,
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/",
- "enabled": true
- },
- {
- "id": 2,
- "region": "South",
- "type": "compute",
- "publicURL": "https://compute.south.public.com/v1",
- "internalURL": "https://compute.south.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.south.public.com/v1/",
- "versionList": "https://compute.south.public.com/",
- "enabled": false
- },
- {
- "id": 3,
- "region": "North",
- "global": true,
- "type": "object-store",
- "publicURL": "https://object-store.north.public.com/v1.0",
- "versionId": "1.0",
- "versionInfo": "https://object-store.north.public.com/v1.0/",
- "versionList": "https://object-store.north.public.com/",
- "enabled": true
- },
- {
- "id": 4,
- "region": "South",
- "type": "object-store",
- "publicURL": "https://object-store.south.public.com/v2",
- "versionId": "2",
- "versionInfo": "https://object-store.south.public.com/v2/",
- "versionList": "https://object-store.south.public.com/",
- "enabled": true
- },
- {
- "id": 5,
- "global": true,
- "type": "OS-DNS:DNS",
- "publicURL": "https://dns.public.com/v3.2",
- "versionId": "1.0",
- "versionInfo": "https://dns.public.com/v1.0/",
- "versionList": "https://dns.public.com/",
- "enabled": true
- }
- ],
- "OS-KSCATALOG:endpointsTemplates_links": []
-}
diff --git a/keystone/content/common/samples/endpointTemplates.xml b/keystone/content/common/samples/endpointTemplates.xml
deleted file mode 100644
index 965be9be..00000000
--- a/keystone/content/common/samples/endpointTemplates.xml
+++ /dev/null
@@ -1,67 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<endpointTemplates xmlns="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0">
- <endpointTemplate
- id="1"
- region="North"
- global="true"
- type="compute"
- name="Compute"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- enabled="true">
- <version
- id="1"
- list="https://compute.north.public.com/"
- info="https://compute.north.public.com/v1"/>
- </endpointTemplate>
- <endpointTemplate
- id="2"
- region="south"
- type="compute"
- name="Compute"
- publicURL="https://service2.public.com/v1"
- internalURL="https://service2.internal.public.com/v1"
- enabled="false">
- <version
- id="1"
- list="https://service1.public.com/"
- info="https://service1.public.com/v1"/>
- </endpointTemplate>
- <endpointTemplate
- id="3"
- region="DFW"
- global="true"
- type="ext1:service1"
- name="Compute"
- publicURL="https://service1.public.com/v1"
- enabled="true">
- <version
- id="1"
- list="https://service1.public.com/"
- info="https://service1.public.com/v1"/>
- </endpointTemplate>
- <endpointTemplate
- id="4"
- region="ORD"
- type="compute"
- name="Compute"
- publicURL="https://service2.public.com/v1"
- enabled="true">
- <version
- id="1"
- list="https://service1.public.com/"
- info="https://service1.public.com/v1"/>
- </endpointTemplate>
- <endpointTemplate
- id="5"
- global="true"
- type="compute"
- name="Compute"
- publicURL="https://service3.public.com/v1">
- <version
- id="1"
- list="https://service1.public.com/"
- info="https://service1.public.com/v1"/>
- </endpointTemplate>
-</endpointTemplates>
diff --git a/keystone/content/common/samples/endpoints.json b/keystone/content/common/samples/endpoints.json
deleted file mode 100644
index e10f05e3..00000000
--- a/keystone/content/common/samples/endpoints.json
+++ /dev/null
@@ -1,65 +0,0 @@
-{
- "endpoints": [
- {
- "id": 1,
- "tenantId": "1",
- "region": "North",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "adminURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/"
- },
- {
- "id": 2,
- "tenantId": "1",
- "region": "South",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "adminURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/"
- },
- {
- "id": 3,
- "tenantId": "1",
- "region": "East",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "adminURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/"
- },
- {
- "id": 4,
- "tenantId": "1",
- "region": "West",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "adminURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/"
- },
- {
- "id": 5,
- "tenantId": "1",
- "region": "Global",
- "type": "compute",
- "publicURL": "https://compute.north.public.com/v1",
- "internalURL": "https://compute.north.internal.com/v1",
- "adminURL": "https://compute.north.internal.com/v1",
- "versionId": "1",
- "versionInfo": "https://compute.north.public.com/v1/",
- "versionList": "https://compute.north.public.com/"
- }
- ],
- "endpoints_links": []
-}
diff --git a/keystone/content/common/samples/endpoints.xml b/keystone/content/common/samples/endpoints.xml
deleted file mode 100644
index b09819a1..00000000
--- a/keystone/content/common/samples/endpoints.xml
+++ /dev/null
@@ -1,76 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<endpoints
- xmlns="http://docs.openstack.org/identity/api/v2.0">
- <endpoint
- id="1"
- tenantId="1"
- type="compute"
- name="Compute"
- region="North"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- adminURL="https://compute.north.internal.com/v1">
- <version
- id="1"
- info="https://compute.north.public.com/v1/"
- list="https://compute.north.public.com/"
- />
- </endpoint>
- <endpoint
- id="2"
- tenantId="2"
- type="compute"
- name="Compute"
- region="South"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- adminURL="https://compute.north.internal.com/v1">
- <version
- id="1"
- info="https://compute.north.public.com/v1/"
- list="https://compute.north.public.com/"
- />
- </endpoint>
- <endpoint
- id="3"
- tenantId="1"
- type="compute"
- name="Compute"
- region="East"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- adminURL="https://compute.north.internal.com/v1"
- tenantId="1"
- />
- <endpoint
- id="4"
- tenantId="1"
- type="compute"
- name="Compute"
- region="West"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- adminURL="https://compute.north.internal.com/v1">
- <version
- id="1"
- info="https://compute.north.public.com/v1/"
- list="https://compute.north.public.com/"
- />
- </endpoint>
- <endpoint
- id="5"
- tenantId="1"
- type="compute"
- name="Compute"
- region="Global"
- publicURL="https://compute.north.public.com/v1"
- internalURL="https://compute.north.internal.com/v1"
- adminURL="https://compute.north.internal.com/v1">
- <version
- id="1"
- info="https://compute.north.public.com/v1/"
- list="https://compute.north.public.com/"
- />
- </endpoint>
-</endpoints>
diff --git a/keystone/content/common/samples/ext-getuser.json b/keystone/content/common/samples/ext-getuser.json
deleted file mode 100644
index f4071ccf..00000000
--- a/keystone/content/common/samples/ext-getuser.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "user": {
- "roles": [
- {
- "tenantId": "1234",
- "id": "Admin"
- }
- ],
- "roles_links": [],
- "id": "1000",
- "username": "jqsmith",
- "email": "john.smith@example.org",
- "enabled": true,
- "RS-META:metadata": {
- "values": {
- "MetaKey1": "MetaValue1",
- "MetaKey2": "MetaValue2"
- }
- }
- }
-}
diff --git a/keystone/content/common/samples/ext-getuser.xml b/keystone/content/common/samples/ext-getuser.xml
deleted file mode 100644
index b155904a..00000000
--- a/keystone/content/common/samples/ext-getuser.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<user xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" email="john.smith@example.org"
- id="u1000" username="jqsmith">
- <roles>
- <role tenantId="1234" id="Admin"/>
- </roles>
- <metadata
- xmlns="http://docs.rackspacecloud.com/identity/api/ext/meta/v2.0">
- <meta key="MetaKey1">MetaValue1</meta>
- <meta key="MetaKey2">MetaValue2</meta>
- </metadata>
-</user>
diff --git a/keystone/content/common/samples/extension.json b/keystone/content/common/samples/extension.json
deleted file mode 100644
index bb66a50c..00000000
--- a/keystone/content/common/samples/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "User Metadata Extension",
- "namespace": "http://docs.rackspacecloud.com/identity/api/ext/meta/v2.0",
- "alias": "RS-META",
- "updated": "2011-01-12T11:22:33-06:00",
- "description": "Allows associating arbritrary metadata with a user.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "http://docs.rackspacecloud.com/identity/api/ext/identity-meta-20111201.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "http://docs.rackspacecloud.com/identity/api/ext/identity-cbs.wadl"
- }
- ]
- }
-}
diff --git a/keystone/content/common/samples/extension.xml b/keystone/content/common/samples/extension.xml
deleted file mode 100644
index 056d7e96..00000000
--- a/keystone/content/common/samples/extension.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="User Metadata Extension"
- namespace="http://docs.rackspacecloud.com/identity/api/ext/meta/v2.0"
- alias="RS-META"
- updated="2011-01-12T11:22:33-06:00">
-
- <description>
- Allows associating arbritrary metadata with a user.
- </description>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="http://docs.rackspacecloud.com/identity/api/ext/identity-meta-20111201.pdf"/>
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="http://docs.rackspacecloud.com/identity/api/ext/identity-meta.wadl"/>
-
-</extension>
-
-
diff --git a/keystone/content/common/samples/extensions.json b/keystone/content/common/samples/extensions.json
deleted file mode 100644
index ca46f941..00000000
--- a/keystone/content/common/samples/extensions.json
+++ /dev/null
@@ -1,44 +0,0 @@
-{
- "extensions": {
- "values": [
- {
- "name": "Reset Password Extension",
- "namespace": "http://docs.rackspacecloud.com/identity/api/ext/rpe/v2.0",
- "alias": "RS-RPE",
- "updated": "2011-01-22T13:25:27-06:00",
- "description": "Adds the capability to reset a user's password. The user is emailed when the password has been reset.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "http://docs.rackspacecloud.com/identity/api/ext/identity-rpe-20111111.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "http://docs.rackspacecloud.com/identity/api/ext/identity-rpe.wadl"
- }
- ]
- },
- {
- "name": "User Metadata Extension",
- "namespace": "http://docs.rackspacecloud.com/identity/api/ext/meta/v2.0",
- "alias": "RS-META",
- "updated": "2011-01-12T11:22:33-06:00",
- "description": "Allows associating arbritrary metadata with a user.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "http://docs.rackspacecloud.com/identity/api/ext/identity-meta-20111201.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "http://docs.rackspacecloud.com/identity/api/ext/identity-meta.wadl"
- }
- ]
- }
- ]},
- "extensions_links": []
-}
diff --git a/keystone/content/common/samples/extensions.xml b/keystone/content/common/samples/extensions.xml
deleted file mode 100644
index c11b06d7..00000000
--- a/keystone/content/common/samples/extensions.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<extensions xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <extension
- name="Reset Password Extension"
- namespace="http://docs.rackspacecloud.com/identity/api/ext/rpe/v1.0"
- alias="RS-RPE"
- updated="2011-01-22T13:25:27-06:00">
-
- <description>
- Adds the capability to reset a user's password. The user is
- emailed when the password has been reset.
- </description>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="http://docs.rackspacecloud.com/identity/api/ext/identity-rpe-20111111.pdf"/>
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="http://docs.rackspacecloud.com/identity/api/ext/identity-rpe.wadl"/>
- </extension>
- <extension
- name="User Metadata Extension"
- namespace="http://docs.rackspacecloud.com/identity/api/ext/meta/v2.0"
- alias="RS-META"
- updated="2011-01-12T11:22:33-06:00">
- <description>
- Allows associating arbritrary metadata with a user.
- </description>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="http://docs.rackspacecloud.com/identity/api/ext/identity-meta-20111201.pdf"/>
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="http://docs.rackspacecloud.com/identity/api/ext/identity-meta.wadl"/>
- </extension>
-</extensions>
diff --git a/keystone/content/common/samples/getuser-1.json b/keystone/content/common/samples/getuser-1.json
deleted file mode 100644
index 741312cc..00000000
--- a/keystone/content/common/samples/getuser-1.json
+++ /dev/null
@@ -1,24 +0,0 @@
-{
- "user": {
- "roles": [
- {
- "tenantId": "1234",
- "id": "Admin"
- },
- {
- "tenantId": "1234",
- "id": "DBUser"
- }
- ],
- "roles_links": [
- {
- "rel": "next",
- "href": "http://identity.api.openstack.org/v2.0/tenants/1234/users/u1000/roles?marker=Super"
- }
- ],
- "id": "u1000",
- "username": "jqsmith",
- "email": "john.smith@example.org",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/getuser-1.xml b/keystone/content/common/samples/getuser-1.xml
deleted file mode 100644
index 531a229f..00000000
--- a/keystone/content/common/samples/getuser-1.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<user xmlns="http://docs.openstack.org/identity/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- enabled="true" email="john.smith@example.org"
- username="jqsmith" id="u1000">
- <roles>
- <role tenantId="1234" id="Admin"/>
- <role tenantId="1234" id="DBUser"/>
- <atom:link
- rel="next"
- href="http://identity.api.openstack.org/v2.0/tenants/1234/users/u1000/groups?marker=Super"/>
- </roles>
-</user>
diff --git a/keystone/content/common/samples/identity_fault.json b/keystone/content/common/samples/identity_fault.json
deleted file mode 100644
index 9968eec2..00000000
--- a/keystone/content/common/samples/identity_fault.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "identityFault": {
- "message": "Fault",
- "details": "Error Details...",
- "code": 500
- }
-}
diff --git a/keystone/content/common/samples/identity_fault.xml b/keystone/content/common/samples/identity_fault.xml
deleted file mode 100644
index 6787af21..00000000
--- a/keystone/content/common/samples/identity_fault.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<identityFault xmlns="http://docs.openstack.org/identity/api/v2.0"
- code="500">
- <message>Fault</message>
- <details>Error Details...</details>
-</identityFault>
diff --git a/keystone/content/common/samples/item_not_found.json b/keystone/content/common/samples/item_not_found.json
deleted file mode 100644
index 8ba8c207..00000000
--- a/keystone/content/common/samples/item_not_found.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "itemNotFound": {
- "message": "Item not found.",
- "details": "Error Details...",
- "code": 404
- }
-}
diff --git a/keystone/content/common/samples/item_not_found.xml b/keystone/content/common/samples/item_not_found.xml
deleted file mode 100644
index 3f78b498..00000000
--- a/keystone/content/common/samples/item_not_found.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<itemNotFound xmlns="http://docs.openstack.org/identity/api/v2.0"
- code="404">
- <message>Item not found.</message>
- <details>Error Details...</details>
-</itemNotFound>
diff --git a/keystone/content/common/samples/norequestbody.txt b/keystone/content/common/samples/norequestbody.txt
deleted file mode 100644
index c6a777d5..00000000
--- a/keystone/content/common/samples/norequestbody.txt
+++ /dev/null
@@ -1 +0,0 @@
-This operation does not require a request body.
diff --git a/keystone/content/common/samples/noresponsebody.txt b/keystone/content/common/samples/noresponsebody.txt
deleted file mode 100644
index 96e583f9..00000000
--- a/keystone/content/common/samples/noresponsebody.txt
+++ /dev/null
@@ -1 +0,0 @@
-This operation does not return a response body.
diff --git a/keystone/content/common/samples/passwordcredentials.json b/keystone/content/common/samples/passwordcredentials.json
deleted file mode 100644
index c57309ba..00000000
--- a/keystone/content/common/samples/passwordcredentials.json
+++ /dev/null
@@ -1,6 +0,0 @@
-{
- "passwordCredentials": {
- "username": "test_user",
- "password": "mypass"
- }
-}
diff --git a/keystone/content/common/samples/passwordcredentials.xml b/keystone/content/common/samples/passwordcredentials.xml
deleted file mode 100644
index 86e4d9fe..00000000
--- a/keystone/content/common/samples/passwordcredentials.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <passwordCredentials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns="http://docs.openstack.org/identity/api/v2.0" username="test_user" password="test"/>
-
diff --git a/keystone/content/common/samples/role.json b/keystone/content/common/samples/role.json
deleted file mode 100644
index a1b8109d..00000000
--- a/keystone/content/common/samples/role.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "role": {
- "id": "123",
- "name": "Guest",
- "description": "Guest Access"
- }
-}
diff --git a/keystone/content/common/samples/role.xml b/keystone/content/common/samples/role.xml
deleted file mode 100644
index dd25cfff..00000000
--- a/keystone/content/common/samples/role.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<role xmlns="http://docs.openstack.org/identity/api/v2.0"
- id="123" name="Admin" description="All Access" />
diff --git a/keystone/content/common/samples/roles.json b/keystone/content/common/samples/roles.json
deleted file mode 100644
index 2504a2b1..00000000
--- a/keystone/content/common/samples/roles.json
+++ /dev/null
@@ -1,10 +0,0 @@
-{
- "roles": [
- {
- "id": "123",
- "name": "compute:admin",
- "description": "Nova Administrator"
- }
- ],
- "roles_links": []
-}
diff --git a/keystone/content/common/samples/roles.xml b/keystone/content/common/samples/roles.xml
deleted file mode 100644
index 30596f92..00000000
--- a/keystone/content/common/samples/roles.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<roles xmlns="http://docs.openstack.org/identity/api/v2.0">
- <role id="123" name="Admin" description="All Access" />
- <role id="234" name="Guest" description="Guest Access" />
-</roles>
diff --git a/keystone/content/common/samples/s3Credentials.json b/keystone/content/common/samples/s3Credentials.json
deleted file mode 100644
index f4b59aa5..00000000
--- a/keystone/content/common/samples/s3Credentials.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "OS-KSS3:s3Credentials":{
- "username":"test_user",
- "secret":"aaaaa",
- "signature":"bbb"
- }
-}
diff --git a/keystone/content/common/samples/s3Credentials.xml b/keystone/content/common/samples/s3Credentials.xml
deleted file mode 100644
index a6941392..00000000
--- a/keystone/content/common/samples/s3Credentials.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <s3Credentials
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSS3/v1.0"
- username="testuser"
- key="aaaaa"
- signature="bbbbb"/>
-
diff --git a/keystone/content/common/samples/samplerequestheader.txt b/keystone/content/common/samples/samplerequestheader.txt
deleted file mode 100644
index 5641d874..00000000
--- a/keystone/content/common/samples/samplerequestheader.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-POST /v2.0/tokens HTTP/1.1
-Host: identity.api.openstack.org
-Content-Type: application/json
-Accept: application/xml \ No newline at end of file
diff --git a/keystone/content/common/samples/sampleresponseheader.txt b/keystone/content/common/samples/sampleresponseheader.txt
deleted file mode 100644
index aee1205a..00000000
--- a/keystone/content/common/samples/sampleresponseheader.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-HTTP/1.1 200 OKAY
-Date: Mon, 12 Nov 2010 15:55:01 GMT
-Content-Length:
-Content-Type: application/xml; charset=UTF-8 \ No newline at end of file
diff --git a/keystone/content/common/samples/service.json b/keystone/content/common/samples/service.json
deleted file mode 100644
index f2a783f2..00000000
--- a/keystone/content/common/samples/service.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "OS-KSADM:service": {
- "id": "123",
- "name": "nova",
- "type": "compute",
- "description": "OpenStack Compute Service"
- }
-}
diff --git a/keystone/content/common/samples/service.xml b/keystone/content/common/samples/service.xml
deleted file mode 100644
index d1c98cec..00000000
--- a/keystone/content/common/samples/service.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<service xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- id="123" name="nova" type="compute" description="OpenStack Compute Service" />
diff --git a/keystone/content/common/samples/services.json b/keystone/content/common/samples/services.json
deleted file mode 100644
index dd8dea4f..00000000
--- a/keystone/content/common/samples/services.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "OS-KSADM:services": [
- {
- "id": "123",
- "name": "nova",
- "type": "compute",
- "description": "OpenStack Compute Service"
- },
- {
- "id": "234",
- "name": "glance",
- "type": "image",
- "description": "OpenStack Image Service"
- }
- ],
- "OS-KSADM:services_links": []
-}
diff --git a/keystone/content/common/samples/services.xml b/keystone/content/common/samples/services.xml
deleted file mode 100644
index 12947c3a..00000000
--- a/keystone/content/common/samples/services.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<services xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0">
- <service id="123" name="nova" type="compute" description="Openstack Compute Service" />
- <service id="234" name="glance" type="image" description="Openstack Image Service" />
-</services> \ No newline at end of file
diff --git a/keystone/content/common/samples/tenant.json b/keystone/content/common/samples/tenant.json
deleted file mode 100644
index 794a61ce..00000000
--- a/keystone/content/common/samples/tenant.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "tenant": {
- "id": "1234",
- "name": "ACME corp",
- "description": "A description ...",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/tenant.xml b/keystone/content/common/samples/tenant.xml
deleted file mode 100644
index ce0137be..00000000
--- a/keystone/content/common/samples/tenant.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenant xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" id="1234" name="ACME Corp">
- <description>A description...</description>
-</tenant>
diff --git a/keystone/content/common/samples/tenantlock.json b/keystone/content/common/samples/tenantlock.json
deleted file mode 100644
index 611e4adb..00000000
--- a/keystone/content/common/samples/tenantlock.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "tenant": {
- "description": "A NEW description..."
- }
-}
diff --git a/keystone/content/common/samples/tenantlock.xml b/keystone/content/common/samples/tenantlock.xml
deleted file mode 100644
index 06a68a83..00000000
--- a/keystone/content/common/samples/tenantlock.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenant xmlns="http://docs.openstack.org/identity/api/v2.0">
- <description>A NEW description...</description>
-</tenant>
diff --git a/keystone/content/common/samples/tenants-1.json b/keystone/content/common/samples/tenants-1.json
deleted file mode 100644
index b3f42349..00000000
--- a/keystone/content/common/samples/tenants-1.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "tenants": [
- {
- "id": "1234",
- "name": "ACME corp",
- "description": "A description ...",
- "enabled": true
- }
- ],
- "tenants_links": [
- {
- "rel": "next",
- "href": "http://identity.api.openstack.org/v2.0/tenants?limit=1&marker=1234"
- }
- ]
-}
diff --git a/keystone/content/common/samples/tenants-1.xml b/keystone/content/common/samples/tenants-1.xml
deleted file mode 100644
index e486649e..00000000
--- a/keystone/content/common/samples/tenants-1.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenants xmlns="http://docs.openstack.org/identity/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <tenant enabled="true" id="1234" name="ACME Corp">
- <description>A description...</description>
- </tenant>
- <atom:link
- rel="next"
- href="http://identity.api.openstack.org/v2.0/tenants?limit=1&amp;marker=1234"/>
-</tenants>
diff --git a/keystone/content/common/samples/tenants-2.json b/keystone/content/common/samples/tenants-2.json
deleted file mode 100644
index c464a446..00000000
--- a/keystone/content/common/samples/tenants-2.json
+++ /dev/null
@@ -1,20 +0,0 @@
-{
- "tenants": [
- {
- "id": "3645",
- "name": "Iron Works",
- "description": "A description ...",
- "enabled": true
- }
- ],
- "tenants_links": [
- {
- "rel": "next",
- "href": "http://identity.api.openstack.org/v2.0/tenants?limit=1&marker=3645"
- },
- {
- "rel": "previous",
- "href": "http://identity.api.openstack.org/v2.0/tenants?limit=1"
- }
- ]
-}
diff --git a/keystone/content/common/samples/tenants-2.xml b/keystone/content/common/samples/tenants-2.xml
deleted file mode 100644
index 7b049c40..00000000
--- a/keystone/content/common/samples/tenants-2.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenants xmlns="http://docs.openstack.org/identity/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <tenant enabled="true" id="3645" name="Iron Works">
- <description>A description...</description>
- </tenant>
- <atom:link
- rel="previous"
- href="http://identity.api.openstack.org/v2.0/tenants?limit=1"/>
- <atom:link
- rel="next"
- href="http://identity.api.openstack.org/v2.0/tenants?limit=1&amp;marker=3645"/>
-</tenants>
diff --git a/keystone/content/common/samples/tenants-3.json b/keystone/content/common/samples/tenants-3.json
deleted file mode 100644
index 5b62bd7e..00000000
--- a/keystone/content/common/samples/tenants-3.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "tenants": [
- {
- "id": "9999",
- "name": "Bigz",
- "description": "A description ...",
- "enabled": true
- }
- ],
- "tenants_links": [
- {
- "rel": "previous",
- "href": "http://identity.api.openstack.org/v2.0/tenants?limit=1&marker=1234"
- }
- ]
-}
diff --git a/keystone/content/common/samples/tenants-3.xml b/keystone/content/common/samples/tenants-3.xml
deleted file mode 100644
index a0edcadb..00000000
--- a/keystone/content/common/samples/tenants-3.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenants xmlns="http://docs.openstack.org/identity/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <tenant enabled="true" id="9999" name="Bigz">
- <description>A description...</description>
- </tenant>
- <atom:link
- rel="previous"
- href="http://identity.api.openstack.org/v2.0/tenants?limit=1&amp;marker=1234"/>
-</tenants>
diff --git a/keystone/content/common/samples/tenants-request.txt b/keystone/content/common/samples/tenants-request.txt
deleted file mode 100644
index 9dbf85e5..00000000
--- a/keystone/content/common/samples/tenants-request.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-GET /v2.0/tenants HTTP/1.1
-Host: identity.api.openstack.org
-Content-Type: application/json
-X-Auth-Token: fa8426a0-8eaf-4d22-8e13-7c1b16a9370c
-Accept: application/json \ No newline at end of file
diff --git a/keystone/content/common/samples/tenants.json b/keystone/content/common/samples/tenants.json
deleted file mode 100644
index a249472f..00000000
--- a/keystone/content/common/samples/tenants.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "tenants": [
- {
- "id": "1234",
- "name": "ACME Corp",
- "description": "A description ...",
- "enabled": true
- },
- {
- "id": "3456",
- "name": "Iron Works",
- "description": "A description ...",
- "enabled": true
- }
- ],
- "tenants_links": []
-}
diff --git a/keystone/content/common/samples/tenants.xml b/keystone/content/common/samples/tenants.xml
deleted file mode 100644
index ac5fa2d9..00000000
--- a/keystone/content/common/samples/tenants.xml
+++ /dev/null
@@ -1,14 +0,0 @@
-HTTP/1.1 200 OK
-Content-Type: application/xml; charset=UTF-8
-Content-Length: 200
-Date: Sun, 1 Jan 2011 9:00:00 GMT
-
-<?xml version="1.0" encoding="UTF-8"?>
-<tenants xmlns="http://docs.openstack.org/identity/api/v2.0">
- <tenant enabled="true" id="1234" name="ACME Corp">
- <description>A description...</description>
- </tenant>
- <tenant enabled="true" id="3645" name="Iron Works">
- <description>A description...</description>
- </tenant>
-</tenants>
diff --git a/keystone/content/common/samples/tenantwithoutid.json b/keystone/content/common/samples/tenantwithoutid.json
deleted file mode 100644
index 63faba9c..00000000
--- a/keystone/content/common/samples/tenantwithoutid.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "tenant": {
- "name": "ACME corp",
- "description": "A description ...",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/tenantwithoutid.xml b/keystone/content/common/samples/tenantwithoutid.xml
deleted file mode 100644
index 3983684b..00000000
--- a/keystone/content/common/samples/tenantwithoutid.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenant xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" name="ACME Corp">
- <description>A description...</description>
-</tenant>
diff --git a/keystone/content/common/samples/updatedtenant.json b/keystone/content/common/samples/updatedtenant.json
deleted file mode 100644
index 2acf53d1..00000000
--- a/keystone/content/common/samples/updatedtenant.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "tenant": {
- "id": "1234",
- "name": "ACME Corp",
- "description": "A NEW description...",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/updatedtenant.xml b/keystone/content/common/samples/updatedtenant.xml
deleted file mode 100644
index 5b36701a..00000000
--- a/keystone/content/common/samples/updatedtenant.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<tenant xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" id="1234" name="ACME Corp">
- <description>A NEW description...</description>
-</tenant>
diff --git a/keystone/content/common/samples/user.json b/keystone/content/common/samples/user.json
deleted file mode 100644
index 75d1508b..00000000
--- a/keystone/content/common/samples/user.json
+++ /dev/null
@@ -1,8 +0,0 @@
-{
- "user": {
- "id": "u1000",
- "username": "jqsmith",
- "email": "john.smith@example.org",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/user.xml b/keystone/content/common/samples/user.xml
deleted file mode 100644
index ccaf7ec4..00000000
--- a/keystone/content/common/samples/user.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<user xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" email="john.smith@example.org"
- username="jqsmith" id="u1000"/>
diff --git a/keystone/content/common/samples/users.json b/keystone/content/common/samples/users.json
deleted file mode 100644
index 3fc104d7..00000000
--- a/keystone/content/common/samples/users.json
+++ /dev/null
@@ -1,17 +0,0 @@
-{
- "users": [
- {
- "id": "u1000",
- "username": "jqsmith",
- "email": "john.smith@example.org",
- "enabled": true
- },
- {
- "id": "u1001",
- "username": "jqsmith",
- "email": "john.smith@example.org",
- "enabled": true
- }
- ],
- "users_links": []
-}
diff --git a/keystone/content/common/samples/users.xml b/keystone/content/common/samples/users.xml
deleted file mode 100644
index 01b321da..00000000
--- a/keystone/content/common/samples/users.xml
+++ /dev/null
@@ -1,9 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<users xmlns="http://docs.openstack.org/identity/api/v2.0">
- <user xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" email="john.smith@example.org"
- username="jqsmith" id="u1000"/>
- <user xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" email="john.smith@example.org"
- username="jqsmith" id="u1001"/>
-</users>
diff --git a/keystone/content/common/samples/userwithenabledonly.json b/keystone/content/common/samples/userwithenabledonly.json
deleted file mode 100644
index fdd74562..00000000
--- a/keystone/content/common/samples/userwithenabledonly.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "user": {
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/userwithenabledonly.xml b/keystone/content/common/samples/userwithenabledonly.xml
deleted file mode 100644
index 0176b9eb..00000000
--- a/keystone/content/common/samples/userwithenabledonly.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<user xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xsi:type="UserWithOnlyEnabled"
- enabled="true"/>
diff --git a/keystone/content/common/samples/userwithoutid.json b/keystone/content/common/samples/userwithoutid.json
deleted file mode 100644
index 8d15f3af..00000000
--- a/keystone/content/common/samples/userwithoutid.json
+++ /dev/null
@@ -1,7 +0,0 @@
-{
- "user": {
- "username": "jqsmith",
- "email": "john.smith@example.org",
- "enabled": true
- }
-}
diff --git a/keystone/content/common/samples/userwithoutid.xml b/keystone/content/common/samples/userwithoutid.xml
deleted file mode 100644
index 3e875beb..00000000
--- a/keystone/content/common/samples/userwithoutid.xml
+++ /dev/null
@@ -1,4 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<user xmlns="http://docs.openstack.org/identity/api/v2.0"
- enabled="true" email="john.smith@example.org"
- username="jqsmith"/>
diff --git a/keystone/content/common/samples/validatetoken.json b/keystone/content/common/samples/validatetoken.json
deleted file mode 100644
index 4a8db881..00000000
--- a/keystone/content/common/samples/validatetoken.json
+++ /dev/null
@@ -1,28 +0,0 @@
-{
- "access": {
- "token": {
- "id": "ab48a9efdfedb23ty3494",
- "expires": "2010-11-01T03:32:15-05:00",
- "tenant": {
- "id": "345",
- "name": "My Project"
- }
- },
- "user": {
- "id": "123",
- "name": "jqsmith",
- "roles": [
- {
- "id": "234",
- "name": "compute:admin"
- },
- {
- "id": "234",
- "name": "object-store:admin",
- "tenantId": "1"
- }
- ],
- "roles_links": []
- }
- }
-}
diff --git a/keystone/content/common/samples/validatetoken.xml b/keystone/content/common/samples/validatetoken.xml
deleted file mode 100644
index 12da9ebb..00000000
--- a/keystone/content/common/samples/validatetoken.xml
+++ /dev/null
@@ -1,12 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<access xmlns="http://docs.openstack.org/identity/api/v2.0">
- <token id="ab48a9efdfedb23ty3494" expires="2010-11-01T03:32:15-05:00">
- <tenant id="456" name="My Project" />
- </token>
- <user id="123" username="jqsmith">
- <roles xmlns="http://docs.openstack.org/identity/api/v2.0">
- <role id="123" name="Admin" tenantId="one"/>
- <role id="234" name="object-store:admin" tenantId="1"/>
- </roles>
- </user>
-</access>
diff --git a/keystone/content/common/samples/version-atom.xml b/keystone/content/common/samples/version-atom.xml
deleted file mode 100644
index 3d78a4a3..00000000
--- a/keystone/content/common/samples/version-atom.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
- <title type="text">About This Version</title>
- <updated>2011-01-21T11:33:21-06:00</updated>
- <id>http://identity.api.openstack.org/v2.0/</id>
- <author><name>OpenStack</name><uri>http://www.openstack.org/</uri></author>
- <link rel="self" href="http://identity.api.openstack.org/v2.0/"/>
- <entry>
- <id>http://identity.api.openstack.org/v2.0/</id>
- <title type="text">Version v2.0</title>
- <updated>2011-01-21T11:33:21-06:00</updated>
- <link rel="self" href="http://identity.api.openstack.org/v2.0/"/>
- <link rel="describedby" type="application/pdf"
- href="http://docs.openstack.org/identity/api/v2.0/identity-latest.pdf"/>
- <link rel="describedby" type="application/vnd.sun.wadl+xml"
- href="http://docs.openstack.org/identity/api/v2.0/application.wadl"/>
- <content type="text">Version v2.0 CURRENT (2011-01-21T11:33:21-06:00)</content>
- </entry>
-</feed>
diff --git a/keystone/content/common/samples/version.json b/keystone/content/common/samples/version.json
deleted file mode 100644
index 4410f93f..00000000
--- a/keystone/content/common/samples/version.json
+++ /dev/null
@@ -1,33 +0,0 @@
-{
- "version": {
- "id": "v2.0",
- "status": "CURRENT",
- "updated": "2011-01-21T11:33:21-06:00",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v2.0/"
- },
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "http://docs.openstack.org/identity/api/v2.0/identity-latest.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "http://docs.openstack.org/identity/api/v2.0/identity.wadl"
- }
- ],
- "media-types": [
- {
- "base": "application/xml",
- "type": "application/vnd.openstack.identity+xml;version=2.0"
- },
- {
- "base": "application/json",
- "type": "application/vnd.openstack.identity+json;version=2.0"
- }
- ]
- }
-}
diff --git a/keystone/content/common/samples/version.xml b/keystone/content/common/samples/version.xml
deleted file mode 100644
index d0f77e42..00000000
--- a/keystone/content/common/samples/version.xml
+++ /dev/null
@@ -1,23 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<version xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- id="v2.0" status="CURRENT" updated="2011-01-21T11:33:21-06:00">
-
- <media-types>
- <media-type base="application/xml"
- type="application/vnd.openstack.identity+xml;version=2.0"/>
- <media-type base="application/json"
- type="application/vnd.openstack.identity+json;version=2.0"/>
- </media-types>
-
- <atom:link rel="self"
- href="http://identity.api.openstack.org/v2.0/"/>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="http://docs.openstack.org/identity/api/v2.0/identity-latest.pdf" />
-
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="http://docs.openstack.org/identity/api/v2.0/identity.wadl" />
-</version>
diff --git a/keystone/content/common/samples/versions-atom.xml b/keystone/content/common/samples/versions-atom.xml
deleted file mode 100644
index 5c864fce..00000000
--- a/keystone/content/common/samples/versions-atom.xml
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
- <title type="text">Available API Versions</title>
- <updated>2010-12-12T18:30:02.25Z</updated>
- <id>http://identity.api.openstack.org/</id>
- <author><name>OpenStack</name><uri>http://www.openstack.org/</uri></author>
- <link rel="self" href="http://identity.api.openstack.org/"/>
- <entry>
- <id>http://identity.api.openstack.org/v2.0/</id>
- <title type="text">Version v2.0</title>
- <updated>2011-05-27T20:22:02.25Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v2.0/"/>
- <content type="text">Version v2.1 CURRENT (2011-05-27T20:22:02.25Z)</content>
- </entry>
- <entry>
- <id>http://identity.api.openstack.org/v1.1/</id>
- <title type="text">Version v1.1</title>
- <updated>2010-12-12T18:30:02.25Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v1.1/"/>
- <content type="text">Version v1.1 CURRENT (2010-12-12T18:30:02.25Z)</content>
- </entry>
- <entry>
- <id>http://identity.api.openstack.org/v1.0/</id>
- <title type="text">Version v1.0</title>
- <updated>2009-10-09T11:30:00Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v1.0/"/>
- <content type="text">Version v1.0 DEPRECATED (2009-10-09T11:30:00Z)</content>
- </entry>
-</feed>
diff --git a/keystone/content/common/samples/versions.json b/keystone/content/common/samples/versions.json
deleted file mode 100644
index e1e590f4..00000000
--- a/keystone/content/common/samples/versions.json
+++ /dev/null
@@ -1,38 +0,0 @@
-{
- "versions": [
- {
- "id": "v1.0",
- "status": "DEPRECATED",
- "updated": "2009-10-09T11:30:00Z",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v1.0/"
- }
- ]
- },
- {
- "id": "v1.1",
- "status": "CURRENT",
- "updated": "2010-12-12T18:30:02.25Z",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v1.1/"
- }
- ]
- },
- {
- "id": "v2.0",
- "status": "BETA",
- "updated": "2011-05-27T20:22:02.25Z",
- "links": [
- {
- "rel": "self",
- "href": "http://identity.api.openstack.org/v2.0/"
- }
- ]
- }
- ],
- "versions_links": []
-}
diff --git a/keystone/content/common/samples/versions.xml b/keystone/content/common/samples/versions.xml
deleted file mode 100644
index caa9801b..00000000
--- a/keystone/content/common/samples/versions.xml
+++ /dev/null
@@ -1,24 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<versions xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
-
- <version id="v1.0" status="DEPRECATED"
- updated="2009-10-09T11:30:00Z">
- <atom:link rel="self"
- href="http://identity.api.openstack.org/v1.0/"/>
- </version>
-
- <version id="v1.1" status="CURRENT"
- updated="2010-12-12T18:30:02.25Z">
- <atom:link rel="self"
- href="http://identity.api.openstack.org/v1.1/"/>
- </version>
-
- <version id="v2.0" status="BETA"
- updated="2011-05-27T20:22:02.25Z">
- <atom:link rel="self"
- href="http://identity.api.openstack.org/v2.0/"/>
- </version>
-
-</versions>
diff --git a/keystone/content/common/style/schema.css b/keystone/content/common/style/schema.css
deleted file mode 100644
index f174ca52..00000000
--- a/keystone/content/common/style/schema.css
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * (C) 2009 Rackspace Hosting, All Rights Reserved.
- */
-body, div, dl, dt, dd, ul, ol, li, h2, h3,
-h4, h5, h6, pre, code, form, fieldset, legend,
-input, button, textarea, p, blockquote, th, td {
- text-align: left;
-}
-
-h1 {
- font-size: 350%;
- margin-bottom: 10px;
-}
-
-#Content {
- border: 1px solid;
- padding: 0px 40px 40px;
- margin-left: 155px;
-}
-
-#SrcContent {
- padding: 0px 40px 40px;
- display: none;
- margin-left: 155px;
-}
-
-#Controller {
- position: fixed;
- width: 145px;
- left: 10px;
- top: 10px;
-}
-
-.Sample {
- display: none;
-}
-
-.EnumValue{
- padding: 10px 0px;
-}
-
-.EnumDoc{
- padding: 10px 10px 10px 0px;
-}
-
-.ExternHref{
- padding-top: 5px;
-}
-
-.ExternDoc{
- padding-right: 10px;
-}
-
-pre {
- overflow: auto;
-}
-
-td {
- padding: 0px 0px 0px 10px;
- width: 50%;
- font-size: 90%;
-}
-
-table {
- width: 100%;
-}
-
-a {
- text-decoration: none;
-}
-
-a:hover {
- text-decoration: underline;
-}
-
-a:link {
- color: #000090;
-}
-
-a:visited {
- color: #000090;
-}
diff --git a/keystone/content/common/style/shjs/sh_acid.css b/keystone/content/common/style/shjs/sh_acid.css
deleted file mode 100644
index a34b786f..00000000
--- a/keystone/content/common/style/shjs/sh_acid.css
+++ /dev/null
@@ -1,151 +0,0 @@
-pre.sh_sourceCode {
- background-color: #eeeeee;
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #bb7977;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #8080c0;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #ff00ff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #ff8000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #800080;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #0080c0;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_symbol {
- color: #ff0080;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_function {
- color: #004466;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_cbracket {
- color: #ff0080;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #bb7977;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #bb7977;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #bb7977;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #0080c0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #ff00ff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #bb7977;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #0080c0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #bb7977;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #a68500;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/style/shjs/sh_darkblue.css b/keystone/content/common/style/shjs/sh_darkblue.css
deleted file mode 100644
index 23fd6dab..00000000
--- a/keystone/content/common/style/shjs/sh_darkblue.css
+++ /dev/null
@@ -1,151 +0,0 @@
-pre.sh_sourceCode {
- background-color: #000040;
- color: #C7C7C7;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #ffff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #60ff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #ffa500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #80a0ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #42cad9;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #ff80ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_symbol {
- color: #d8e91b;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_function {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_cbracket {
- color: #d8e91b;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #ffff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #ffff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #ffff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #26e0e7;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #ffa500;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #ffff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #26e0e7;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #ffff60;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #ffa0a0;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/style/shjs/sh_emacs.css b/keystone/content/common/style/shjs/sh_emacs.css
deleted file mode 100644
index 6e019cbe..00000000
--- a/keystone/content/common/style/shjs/sh_emacs.css
+++ /dev/null
@@ -1,139 +0,0 @@
-pre.sh_sourceCode {
- background-color: #ffffff;
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #9c20ee;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #208920;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #ac2020;
- font-weight: normal;
- font-style: italic;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_function {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #9c20ee;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #9c20ee;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #9c20ee;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #0000ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #9c20ee;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #0000ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #9c20ee;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #bd8d8b;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/style/shjs/sh_night.css b/keystone/content/common/style/shjs/sh_night.css
deleted file mode 100644
index d8d371b4..00000000
--- a/keystone/content/common/style/shjs/sh_night.css
+++ /dev/null
@@ -1,151 +0,0 @@
-pre.sh_sourceCode {
- background-color: #000044;
- color: #dd00ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #f1157c;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #82d66d;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #bfbfbf;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #8ee119;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #00bb00;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_symbol {
- color: #e7ee5c;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_function {
- color: #ff06cd;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_cbracket {
- color: #e7ee5c;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #7aec27;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #82d66d;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #7aec27;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #ffffff;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/style/shjs/sh_pablo.css b/keystone/content/common/style/shjs/sh_pablo.css
deleted file mode 100644
index 173cd7bf..00000000
--- a/keystone/content/common/style/shjs/sh_pablo.css
+++ /dev/null
@@ -1,151 +0,0 @@
-pre.sh_sourceCode {
- background-color: #000000;
- color: #ffffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #c0c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #00c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #0000ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #808080;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #00ff00;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_symbol {
- color: #ff0000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_function {
- color: #ff22b9;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_cbracket {
- color: #ff0000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #c0c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #c0c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #c0c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #0000c0;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #0000ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #c0c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #0000c0;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #c0c000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #00ffff;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/style/shjs/sh_print.css b/keystone/content/common/style/shjs/sh_print.css
deleted file mode 100644
index 1e8c1168..00000000
--- a/keystone/content/common/style/shjs/sh_print.css
+++ /dev/null
@@ -1,145 +0,0 @@
-pre.sh_sourceCode {
- background-color: #ffffff;
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #666666;
- font-weight: normal;
- font-style: italic;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_symbol {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_cbracket {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #000000;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/style/shjs/sh_style.css b/keystone/content/common/style/shjs/sh_style.css
deleted file mode 100644
index 6cd20b47..00000000
--- a/keystone/content/common/style/shjs/sh_style.css
+++ /dev/null
@@ -1,66 +0,0 @@
-pre.sh_sourceCode {
- background-color: white;
- color: black;
- font-style: normal;
- font-weight: normal;
-}
-
-pre.sh_sourceCode .sh_keyword { color: blue; font-weight: bold; } /* language keywords */
-pre.sh_sourceCode .sh_type { color: darkgreen; } /* basic types */
-pre.sh_sourceCode .sh_usertype { color: teal; } /* user defined types */
-pre.sh_sourceCode .sh_string { color: red; font-family: monospace; } /* strings and chars */
-pre.sh_sourceCode .sh_regexp { color: orange; font-family: monospace; } /* regular expressions */
-pre.sh_sourceCode .sh_specialchar { color: pink; font-family: monospace; } /* e.g., \n, \t, \\ */
-pre.sh_sourceCode .sh_comment { color: brown; font-style: italic; } /* comments */
-pre.sh_sourceCode .sh_number { color: purple; } /* literal numbers */
-pre.sh_sourceCode .sh_preproc { color: darkblue; font-weight: bold; } /* e.g., #include, import */
-pre.sh_sourceCode .sh_symbol { color: darkred; } /* e.g., <, >, + */
-pre.sh_sourceCode .sh_function { color: black; font-weight: bold; } /* function calls and declarations */
-pre.sh_sourceCode .sh_cbracket { color: red; } /* block brackets (e.g., {, }) */
-pre.sh_sourceCode .sh_todo { font-weight: bold; background-color: cyan; } /* TODO and FIXME */
-
-/* Predefined variables and functions (for instance glsl) */
-pre.sh_sourceCode .sh_predef_var { color: darkblue; }
-pre.sh_sourceCode .sh_predef_func { color: darkblue; font-weight: bold; }
-
-/* for OOP */
-pre.sh_sourceCode .sh_classname { color: teal; }
-
-/* line numbers (not yet implemented) */
-pre.sh_sourceCode .sh_linenum { color: black; font-family: monospace; }
-
-/* Internet related */
-pre.sh_sourceCode .sh_url { color: blue; text-decoration: underline; font-family: monospace; }
-
-/* for ChangeLog and Log files */
-pre.sh_sourceCode .sh_date { color: blue; font-weight: bold; }
-pre.sh_sourceCode .sh_time, pre.sh_sourceCode .sh_file { color: darkblue; font-weight: bold; }
-pre.sh_sourceCode .sh_ip, pre.sh_sourceCode .sh_name { color: darkgreen; }
-
-/* for Prolog, Perl... */
-pre.sh_sourceCode .sh_variable { color: darkgreen; }
-
-/* for LaTeX */
-pre.sh_sourceCode .sh_italics { color: darkgreen; font-style: italic; }
-pre.sh_sourceCode .sh_bold { color: darkgreen; font-weight: bold; }
-pre.sh_sourceCode .sh_underline { color: darkgreen; text-decoration: underline; }
-pre.sh_sourceCode .sh_fixed { color: green; font-family: monospace; }
-pre.sh_sourceCode .sh_argument { color: darkgreen; }
-pre.sh_sourceCode .sh_optionalargument { color: purple; }
-pre.sh_sourceCode .sh_math { color: orange; }
-pre.sh_sourceCode .sh_bibtex { color: blue; }
-
-/* for diffs */
-pre.sh_sourceCode .sh_oldfile { color: orange; }
-pre.sh_sourceCode .sh_newfile { color: darkgreen; }
-pre.sh_sourceCode .sh_difflines { color: blue; }
-
-/* for css */
-pre.sh_sourceCode .sh_selector { color: purple; }
-pre.sh_sourceCode .sh_property { color: blue; }
-pre.sh_sourceCode .sh_value { color: darkgreen; font-style: italic; }
-
-/* other */
-pre.sh_sourceCode .sh_section { color: black; font-weight: bold; }
-pre.sh_sourceCode .sh_paren { color: red; }
-pre.sh_sourceCode .sh_attribute { color: darkgreen; }
diff --git a/keystone/content/common/style/shjs/sh_whitengrey.css b/keystone/content/common/style/shjs/sh_whitengrey.css
deleted file mode 100644
index 41df0e2c..00000000
--- a/keystone/content/common/style/shjs/sh_whitengrey.css
+++ /dev/null
@@ -1,139 +0,0 @@
-pre.sh_sourceCode {
- background-color: #ffffff;
- color: #696969;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_keyword {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_type {
- color: #696969;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_string {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_regexp {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_specialchar {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_comment {
- color: #1326a2;
- font-weight: normal;
- font-style: italic;
-}
-
-pre.sh_sourceCode .sh_number {
- color: #bb00ff;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_preproc {
- color: #470000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_function {
- color: #000000;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_url {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_date {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_time {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_file {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_ip {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_name {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_variable {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_oldfile {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_newfile {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_difflines {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_selector {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_property {
- color: #696969;
- font-weight: bold;
- font-style: normal;
-}
-
-pre.sh_sourceCode .sh_value {
- color: #008800;
- font-weight: normal;
- font-style: normal;
-}
-
diff --git a/keystone/content/common/xsd/OS-KSADM.xsd b/keystone/content/common/xsd/OS-KSADM.xsd
deleted file mode 100644
index 5dfa08dd..00000000
--- a/keystone/content/common/xsd/OS-KSADM.xsd
+++ /dev/null
@@ -1,108 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSADM="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- >
-
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="api.xsd" />
-
- <!-- Elements -->
- <element name="services" type="OS-KSADM:ServiceList">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of services.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <element name="service" type="OS-KSADM:Service" >
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A service.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <element name="extensibleCredentialsType" type="OS-KSADM:ExtensibleCredentialsType">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An extensible credentials type.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <!-- Complex Types -->
- <complexType name="Service">
- <attribute name="id" type="xsd:string" use="required"/>
- <attribute name="name" type="xsd:string" use="required"/>
- <attribute name="type" type="identity:ExtensibleServiceType" use="required"/>
- <attribute name="description" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="ServiceList">
- <sequence>
- <element name="service" type="OS-KSADM:Service" minOccurs="0" maxOccurs="unbounded"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <simpleType name="PasswordCredentialsType">
- <restriction base="xsd:string">
- <enumeration value="password"/>
- </restriction>
- </simpleType>
-
- <simpleType name="ExtensionCredentialsType">
- <restriction base="xsd:string">
- <pattern value="(\w|-)+-\w+"/>
- </restriction>
- </simpleType>
-
- <simpleType name="ExtensibleCredentialsType">
- <union memberTypes="OS-KSADM:PasswordCredentialsType OS-KSADM:ExtensionCredentialsType"/>
- </simpleType>
-
- <!-- Complex Types -->
- <complexType name="UserWithOnlyEnabled">
- <complexContent>
- <restriction base="identity:User">
- <attribute name="id" type="xsd:string" use="prohibited"/>
- <attribute name="email" type="xsd:string" use="prohibited"/>
- <attribute name="username" type="xsd:string" use="prohibited"/>
- <attribute name="enabled" type="xsd:boolean" use="required"/>
- </restriction>
- </complexContent>
- </complexType>
-</schema> \ No newline at end of file
diff --git a/keystone/content/common/xsd/OS-KSCATALOG.xsd b/keystone/content/common/xsd/OS-KSCATALOG.xsd
deleted file mode 100644
index 86de52d1..00000000
--- a/keystone/content/common/xsd/OS-KSCATALOG.xsd
+++ /dev/null
@@ -1,193 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSCATALOG="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0"
- >
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="api.xsd" />
-
- <element name="endpointTemplates" type="OS-KSCATALOG:EndpointTemplateList">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of Endpoint Templates.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <element name="endpointTemplate" type="OS-KSCATALOG:EndpointTemplate">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An Endpoint Template.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <!-- Complex Types -->
- <complexType name="EndpointTemplate">
- <sequence>
- <element name="version" type="identity:VersionForService" maxOccurs="1" minOccurs="0">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Version details.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="id" type="xsd:string" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An ID uniquely identifying the Endpoint Template.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="type" type="identity:ExtensibleServiceType" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The OpenStack-registered type (e.g. 'compute', 'object-store', etc).
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The commercial service name (e.g. 'My Nova Cloud Servers').
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="region" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The region of Endpoint Template.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="publicURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The public URL to access represented service.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="internalURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The internal version of the public URL.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="adminURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The admin URL.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="global" type="xsd:boolean" default="false" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- If true the Endpoint Template is automatically part of every account.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="enabled" type="xsd:boolean" default="true" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- True if the Endpoint Template is enabled (active).
- A Endpoint Template cannot be added if it's disabled or inactive (false).
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="EndpointTemplateList">
- <sequence>
- <element name="endpointTemplate" type="OS-KSCATALOG:EndpointTemplate" minOccurs="0" maxOccurs="unbounded"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="EndpointTemplateWithOnlyId">
- <complexContent>
- <restriction base="OS-KSCATALOG:EndpointTemplate">
- <attribute name="id" type="xsd:string" use="required"/>
- <attribute name="type" type="identity:ExtensibleServiceType" use="prohibited"/>
- <attribute name="name" type="xsd:string" use="prohibited"/>
- <attribute name="region" type="xsd:string" use="prohibited"/>
- <attribute name="publicURL" type="xsd:anyURI" use="prohibited"/>
- <attribute name="internalURL" type="xsd:anyURI" use="prohibited"/>
- <attribute name="adminURL" type="xsd:anyURI" use="prohibited"/>
- <attribute name="global" type="xsd:boolean" use="prohibited"/>
- <attribute name="enabled" type="xsd:boolean" use="prohibited"/>
- </restriction>
- </complexContent>
- </complexType>
-</schema>
diff --git a/keystone/content/common/xsd/OS-KSEC2-credentials.xsd b/keystone/content/common/xsd/OS-KSEC2-credentials.xsd
deleted file mode 100644
index 4b7da238..00000000
--- a/keystone/content/common/xsd/OS-KSEC2-credentials.xsd
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSEC2="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
->
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="credentials.xsd"/>
-
- <!-- Elements -->
- <element name="ec2Credentials" type="OS-KSEC2:ec2CredentialsType" substitutionGroup="identity:credential"/>
-
- <!-- Complex Types -->
- <complexType name="ec2CredentialsType">
- <complexContent>
- <extension base="identity:CredentialType">
- <attribute name="username" type="xsd:string" use="required" ></attribute>
- <attribute name="key" type="xsd:string" use="required" ></attribute>
- <attribute name="signature" type="xsd:string" use="required" ></attribute>
- </extension>
- </complexContent>
- </complexType>
-</schema>
-
-
diff --git a/keystone/content/common/xsd/OS-KSS3-credentials.xsd b/keystone/content/common/xsd/OS-KSS3-credentials.xsd
deleted file mode 100644
index 8de65bf9..00000000
--- a/keystone/content/common/xsd/OS-KSS3-credentials.xsd
+++ /dev/null
@@ -1,35 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:OS-KSEC2="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
->
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="credentials.xsd"/>
-
- <!-- Elements -->
- <element name="s3Credentials" type="OS-KSEC2:s3CredentialsType" substitutionGroup="identity:credential"/>
-
- <!-- Complex Types -->
- <complexType name="s3CredentialsType">
- <complexContent>
- <extension base="identity:CredentialType">
- <attribute name="username" type="xsd:string" use="required" ></attribute>
- <attribute name="key" type="xsd:string" use="required" ></attribute>
- <attribute name="signature" type="xsd:string" use="required" ></attribute>
- </extension>
- </complexContent>
- </complexType>
-</schema>
-
-
diff --git a/keystone/content/common/xsd/RAX-KSADM-credentials.xsd b/keystone/content/common/xsd/RAX-KSADM-credentials.xsd
deleted file mode 100644
index c1430ac3..00000000
--- a/keystone/content/common/xsd/RAX-KSADM-credentials.xsd
+++ /dev/null
@@ -1,33 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSADM="http://docs.rackspace.com/identity/api/ext/RAX-KSADM/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.rackspace.com/identity/api/ext/RAX-KSADM/v1.0"
- >
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="credentials.xsd"/>
-
- <!-- Elements -->
- <element name="apikeyCredentials" type="RAX-KSADM:apiKeyCredentials" substitutionGroup="identity:credential"/>
-
- <!-- Complex Types -->
- <complexType name="apiKeyCredentials">
- <complexContent>
- <extension base="identity:CredentialType">
- <attribute name="APIKey" type="xsd:string" use="required" ></attribute>
- </extension>
- </complexContent>
- </complexType>
-
-</schema>
-
diff --git a/keystone/content/common/xsd/RAX-KSADM-users.xsd b/keystone/content/common/xsd/RAX-KSADM-users.xsd
deleted file mode 100644
index d6e8026b..00000000
--- a/keystone/content/common/xsd/RAX-KSADM-users.xsd
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSADM="http://docs.rackspace.com/identity/api/ext/RAX-KSADM/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.rackspace.com/identity/api/ext/RAX-KSADM/v1.0"
- >
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="user.xsd"/>
-
- <!-- Elements -->
- <complexType name="UserWithOnlyEnabled">
- <complexContent>
- <restriction base="identity:User">
- <attribute name="id" type="xsd:string" use="prohibited"/>
- <attribute name="username" type="xsd:string" use="prohibited"/>
- <attribute name="email" type="xsd:string" use="prohibited"/>
- <attribute name="enabled" type="xsd:boolean" use="required"/>
- </restriction>
- </complexContent>
- </complexType>
-
- <complexType name="UserWithPassword">
- <complexContent>
- <annotation>
- <xsd:appinfo>
- <xsdxt:samples>
- <xsdxt:sample>
- <xsdxt:code type="application/xml" href="../samples/RAX-KSADM-userWithPassword.xml" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/json" href="../samples/RAX-KSADM-userWithPassword.json" />
- </xsdxt:sample>
- </xsdxt:samples>
- </xsd:appinfo>
- </annotation>
- <extension base="identity:User">
- <attribute name="password" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax" />
- </extension>
- </complexContent>
- </complexType>
-
-</schema>
diff --git a/keystone/content/common/xsd/RAX-KSGRP-groups.xsd b/keystone/content/common/xsd/RAX-KSGRP-groups.xsd
deleted file mode 100644
index 267bacc3..00000000
--- a/keystone/content/common/xsd/RAX-KSGRP-groups.xsd
+++ /dev/null
@@ -1,53 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSGRP="http://docs.rackspace.com/identity/api/ext/RAX-KSGRP/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.rackspace.com/identity/api/ext/RAX-KSGRP/v1.0"
->
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="token.xsd"/>
-
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="api.xsd" />
-
-
- <element name="groups" type="RAX-KSGRP:Groups"/>
-
- <complexType name="Groups">
- <sequence>
- <element name="group" type="RAX-KSGRP:Group" maxOccurs="100"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="Group">
- <sequence>
- <element name="description" type="xsd:string" maxOccurs="1"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="id" type="xsd:string" use="required"/>
- <attribute name="name" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="TenantGroup">
- <complexContent>
- <extension base="RAX-KSGRP:Group">
- <attribute name="tenantId" type="xsd:string" use="required"/>
- </extension>
- </complexContent>
- </complexType>
-</schema>
-
diff --git a/keystone/content/common/xsd/RAX-KSKEY-credentials.xsd b/keystone/content/common/xsd/RAX-KSKEY-credentials.xsd
deleted file mode 100644
index 69f5ce10..00000000
--- a/keystone/content/common/xsd/RAX-KSKEY-credentials.xsd
+++ /dev/null
@@ -1,52 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSKEY="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
->
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="credentials.xsd"/>
-
- <!-- Elements -->
- <element name="apiKeyCredentials" type="RAX-KSKEY:apiKeyCredentials" substitutionGroup="identity:credential"/>
-
- <!-- Complex Types -->
- <complexType name="apiKeyCredentials">
- <complexContent>
- <extension base="identity:CredentialType">
- <attribute name="username" type="xsd:string" use="optional" ></attribute>
- <attribute name="apiKey" type="xsd:string" use="required" ></attribute>
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="apiKeyCredentialsWithOnlyApiKey">
- <complexContent>
- <restriction base="RAX-KSKEY:apiKeyCredentials">
- <attribute name="username" type="xsd:string" use="prohibited"/>
- <attribute name="apiKey" type="xsd:string" use="required" >
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The user's API Key.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- </restriction>
- </complexContent>
- </complexType>
-
-</schema>
diff --git a/keystone/content/common/xsd/RAX-KSQA-secretQA.xsd b/keystone/content/common/xsd/RAX-KSQA-secretQA.xsd
deleted file mode 100644
index cc13a492..00000000
--- a/keystone/content/common/xsd/RAX-KSQA-secretQA.xsd
+++ /dev/null
@@ -1,51 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<schema elementFormDefault="qualified" attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema" xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:RAX-KSQA="http://docs.rackspace.com/identity/api/ext/RAX-KSQA/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0" xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.rackspace.com/identity/api/ext/RAX-KSQA/v1.0">
-
- <!--Import schema we are extending -->
- <import namespace="http://docs.openstack.org/identity/api/v2.0"
- schemaLocation="credentials.xsd" />
-
- <!-- Elements -->
- <element name="secretQA" type="RAX-KSQA:SecretQA"
- substitutionGroup="identity:credential" />
-
- <!-- Complex Types -->
- <complexType name="SecretQA">
- <complexContent>
- <annotation>
- <xsd:documentation xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A Secret Question and Answer. The answer shall serve to prove
- the user's identity as it should only be able to be answered
- by the user who proposed the question.
- </p>
- </xsd:documentation>
- <xsd:appinfo>
- <xsdxt:samples>
- <xsdxt:sample>
- <xsdxt:code type="application/xml" href="../samples/RAX-KSQA-secretQA.xml" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/json" href="../samples/RAX-KSQA-secretQA.json" />
- </xsdxt:sample>
- </xsdxt:samples>
- </xsd:appinfo>
- </annotation>
- <extension base="identity:CredentialType">
- <attribute name="username" type="xsd:string" use="optional" />
- <attribute name="question" type="xsd:string" use="optional" />
- <attribute name="answer" type="xsd:string" use="optional" />
- <anyAttribute namespace="##other" processContents="lax" />
- </extension>
- </complexContent>
- </complexType>
-
-</schema>
diff --git a/keystone/content/common/xsd/api-common.xsd b/keystone/content/common/xsd/api-common.xsd
deleted file mode 100644
index 0625e5be..00000000
--- a/keystone/content/common/xsd/api-common.xsd
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://docs.openstack.org/common/api/v1.0"
->
- <annotation>
- <xsd:appinfo
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <xsdxt:title>Open Stack Common API Schema Types 1.0</xsdxt:title>
- <xsdxt:link rev="index" href="extensions.xsd" />
- <xsdxt:link rev="index" href="limits.xsd" />
- <xsdxt:link rev="index" href="version.xsd" />
- </xsd:appinfo>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- This is the main index XML Schema document
- for Common API Schema Types Version 1.0.
- </p>
- </xsd:documentation>
- </annotation>
- <include schemaLocation="extensions.xsd">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Types related to extensions.
- </p>
- </xsd:documentation>
- </annotation>
- </include>
- <include schemaLocation="version.xsd">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Types related to API version details.
- </p>
- </xsd:documentation>
- </annotation>
- </include>
-</schema>
diff --git a/keystone/content/common/xsd/api.xsd b/keystone/content/common/xsd/api.xsd
deleted file mode 100644
index 5b6140cc..00000000
--- a/keystone/content/common/xsd/api.xsd
+++ /dev/null
@@ -1,22 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
- <include schemaLocation="token.xsd"/>
- <include schemaLocation="tenant.xsd"/>
- <include schemaLocation="fault.xsd"/>
- <include schemaLocation="endpoints.xsd"/>
- <include schemaLocation="roles.xsd"/>
- <include schemaLocation="user.xsd"/>
- <include schemaLocation="credentials.xsd"/>
- <include schemaLocation="services.xsd"/>
-</schema>
diff --git a/keystone/content/common/xsd/atom/atom.xsd b/keystone/content/common/xsd/atom/atom.xsd
deleted file mode 100644
index c515c497..00000000
--- a/keystone/content/common/xsd/atom/atom.xsd
+++ /dev/null
@@ -1,115 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified"
- targetNamespace="http://www.w3.org/2005/Atom"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:atom="http://www.w3.org/2005/Atom"
- xmlns:xml="http://www.w3.org/XML/1998/namespace"
- xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
- <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
-
- <xs:simpleType name="relation">
- <xs:restriction base="xs:string">
- <xs:enumeration value="alternate" />
- <xs:enumeration value="appendix" />
- <xs:enumeration value="archives" />
- <xs:enumeration value="author" />
- <xs:enumeration value="bookmark" />
- <xs:enumeration value="chapter" />
- <xs:enumeration value="contents" />
- <xs:enumeration value="copyright" />
- <xs:enumeration value="current" />
- <xs:enumeration value="describedby" />
- <xs:enumeration value="edit" />
- <xs:enumeration value="edit-media" />
- <xs:enumeration value="first" />
- <xs:enumeration value="glossary" />
- <xs:enumeration value="help" />
- <xs:enumeration value="hub" />
- <xs:enumeration value="icon" />
- <xs:enumeration value="index" />
- <xs:enumeration value="last" />
- <xs:enumeration value="latest-version" />
- <xs:enumeration value="license" />
- <xs:enumeration value="monitor" />
- <xs:enumeration value="monitor-group" />
- <xs:enumeration value="next" />
- <xs:enumeration value="next-arvhice" />
- <xs:enumeration value="nofollow" />
- <xs:enumeration value="payment" />
- <xs:enumeration value="predecessor-version" />
- <xs:enumeration value="prefetch" />
- <xs:enumeration value="prev" />
- <xs:enumeration value="previous" />
- <xs:enumeration value="prev-archive" />
- <xs:enumeration value="replies" />
- <xs:enumeration value="search" />
- <xs:enumeration value="section" />
- <xs:enumeration value="self" />
- <xs:enumeration value="service" />
- <xs:enumeration value="start" />
- <xs:enumeration value="stylesheet" />
- <xs:enumeration value="subsection" />
- <xs:enumeration value="successor-version" />
- <xs:enumeration value="up" />
- <xs:enumeration value="version-history" />
- <xs:enumeration value="via" />
- <xs:enumeration value="working-copy" />
- <xs:enumeration value="working-copy-of" />
- </xs:restriction>
- </xs:simpleType>
-
- <xs:element name="link" type="atom:link" />
-
- <xs:complexType name="link">
- <xs:annotation>
- <xs:documentation>
- <html:p>See section 3.4 of the ATOM RFC <html:a href="http://tools.ietf.org/html/rfc4287">RFC4287</html:a></html:p>
- </xs:documentation>
- </xs:annotation>
-
- <xs:attribute name="rel" use="required" type="atom:relation">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO(Jorge)</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="type" use="optional" type="xs:string">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO(Jorge)</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="href" use="required" type="xs:anyURI">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO(Jorge)</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="hreflang" use="optional" type="xs:NMTOKEN">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO(Jorge)</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="title" use="optional" type="xs:string">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO(Jorge)</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute ref="xml:base" />
- <xs:attribute ref="xml:lang" />
- </xs:complexType>
-</xs:schema>
diff --git a/keystone/content/common/xsd/atom/xml.xsd b/keystone/content/common/xsd/atom/xml.xsd
deleted file mode 100644
index aea7d0db..00000000
--- a/keystone/content/common/xsd/atom/xml.xsd
+++ /dev/null
@@ -1,287 +0,0 @@
-<?xml version='1.0'?>
-<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
-<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace"
- xmlns:xs="http://www.w3.org/2001/XMLSchema"
- xmlns ="http://www.w3.org/1999/xhtml"
- xml:lang="en">
-
- <xs:annotation>
- <xs:documentation>
- <div>
- <h1>About the XML namespace</h1>
-
- <div class="bodytext">
- <p>
- This schema document describes the XML namespace, in a form
- suitable for import by other schema documents.
- </p>
- <p>
- See <a href="http://www.w3.org/XML/1998/namespace.html">
- http://www.w3.org/XML/1998/namespace.html</a> and
- <a href="http://www.w3.org/TR/REC-xml">
- http://www.w3.org/TR/REC-xml</a> for information
- about this namespace.
- </p>
- <p>
- Note that local names in this namespace are intended to be
- defined only by the World Wide Web Consortium or its subgroups.
- The names currently defined in this namespace are listed below.
- They should not be used with conflicting semantics by any Working
- Group, specification, or document instance.
- </p>
- <p>
- See further below in this document for more information about <a
- href="#usage">how to refer to this schema document from your own
- XSD schema documents</a> and about <a href="#nsversioning">the
- namespace-versioning policy governing this schema document</a>.
- </p>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
- <xs:attribute name="lang">
- <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>lang (as an attribute name)</h3>
- <p>
- denotes an attribute whose value
- is a language code for the natural language of the content of
- any element; its value is inherited. This name is reserved
- by virtue of its definition in the XML specification.</p>
-
- </div>
- <div>
- <h4>Notes</h4>
- <p>
- Attempting to install the relevant ISO 2- and 3-letter
- codes as the enumerated possible values is probably never
- going to be a realistic possibility.
- </p>
- <p>
- See BCP 47 at <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">
- http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
- and the IANA language subtag registry at
- <a href="http://www.iana.org/assignments/language-subtag-registry">
- http://www.iana.org/assignments/language-subtag-registry</a>
- for further information.
- </p>
- <p>
- The union allows for the 'un-declaration' of xml:lang with
- the empty string.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:union memberTypes="xs:language">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value=""/>
- </xs:restriction>
- </xs:simpleType>
- </xs:union>
- </xs:simpleType>
- </xs:attribute>
-
- <xs:attribute name="space">
- <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>space (as an attribute name)</h3>
- <p>
- denotes an attribute whose
- value is a keyword indicating what whitespace processing
- discipline is intended for the content of the element; its
- value is inherited. This name is reserved by virtue of its
- definition in the XML specification.</p>
-
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:NCName">
- <xs:enumeration value="default"/>
- <xs:enumeration value="preserve"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
-
- <xs:attribute name="base" type="xs:anyURI"> <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>base (as an attribute name)</h3>
- <p>
- denotes an attribute whose value
- provides a URI to be used as the base for interpreting any
- relative URIs in the scope of the element on which it
- appears; its value is inherited. This name is reserved
- by virtue of its definition in the XML Base specification.</p>
-
- <p>
- See <a
- href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
- for information about this attribute.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="id" type="xs:ID">
- <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>id (as an attribute name)</h3>
- <p>
- denotes an attribute whose value
- should be interpreted as if declared to be of type ID.
- This name is reserved by virtue of its definition in the
- xml:id specification.</p>
-
- <p>
- See <a
- href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
- for information about this attribute.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attributeGroup name="specialAttrs">
- <xs:attribute ref="xml:base"/>
- <xs:attribute ref="xml:lang"/>
- <xs:attribute ref="xml:space"/>
- <xs:attribute ref="xml:id"/>
- </xs:attributeGroup>
-
- <xs:annotation>
- <xs:documentation>
- <div>
-
- <h3>Father (in any context at all)</h3>
-
- <div class="bodytext">
- <p>
- denotes Jon Bosak, the chair of
- the original XML Working Group. This name is reserved by
- the following decision of the W3C XML Plenary and
- XML Coordination groups:
- </p>
- <blockquote>
- <p>
- In appreciation for his vision, leadership and
- dedication the W3C XML Plenary on this 10th day of
- February, 2000, reserves for Jon Bosak in perpetuity
- the XML name "xml:Father".
- </p>
- </blockquote>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
- <xs:annotation>
- <xs:documentation>
- <div xml:id="usage" id="usage">
- <h2><a name="usage">About this schema document</a></h2>
-
- <div class="bodytext">
- <p>
- This schema defines attributes and an attribute group suitable
- for use by schemas wishing to allow <code>xml:base</code>,
- <code>xml:lang</code>, <code>xml:space</code> or
- <code>xml:id</code> attributes on elements they define.
- </p>
- <p>
- To enable this, such a schema must import this schema for
- the XML namespace, e.g. as follows:
- </p>
- <pre>
- &lt;schema . . .>
- . . .
- &lt;import namespace="http://www.w3.org/XML/1998/namespace"
- schemaLocation="http://www.w3.org/2001/xml.xsd"/>
- </pre>
- <p>
- or
- </p>
- <pre>
- &lt;import namespace="http://www.w3.org/XML/1998/namespace"
- schemaLocation="http://www.w3.org/2009/01/xml.xsd"/>
- </pre>
- <p>
- Subsequently, qualified reference to any of the attributes or the
- group defined below will have the desired effect, e.g.
- </p>
- <pre>
- &lt;type . . .>
- . . .
- &lt;attributeGroup ref="xml:specialAttrs"/>
- </pre>
- <p>
- will define a type which will schema-validate an instance element
- with any of those attributes.
- </p>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
- <xs:annotation>
- <xs:documentation>
- <div id="nsversioning" xml:id="nsversioning">
- <h2><a name="nsversioning">Versioning policy for this schema document</a></h2>
- <div class="bodytext">
- <p>
- In keeping with the XML Schema WG's standard versioning
- policy, this schema document will persist at
- <a href="http://www.w3.org/2009/01/xml.xsd">
- http://www.w3.org/2009/01/xml.xsd</a>.
- </p>
- <p>
- At the date of issue it can also be found at
- <a href="http://www.w3.org/2001/xml.xsd">
- http://www.w3.org/2001/xml.xsd</a>.
- </p>
- <p>
- The schema document at that URI may however change in the future,
- in order to remain compatible with the latest version of XML
- Schema itself, or with the XML namespace itself. In other words,
- if the XML Schema or XML namespaces change, the version of this
- document at <a href="http://www.w3.org/2001/xml.xsd">
- http://www.w3.org/2001/xml.xsd
- </a>
- will change accordingly; the version at
- <a href="http://www.w3.org/2009/01/xml.xsd">
- http://www.w3.org/2009/01/xml.xsd
- </a>
- will not change.
- </p>
- <p>
- Previous dated (and unchanging) versions of this schema
- document are at:
- </p>
- <ul>
- <li><a href="http://www.w3.org/2009/01/xml.xsd">
- http://www.w3.org/2009/01/xml.xsd</a></li>
- <li><a href="http://www.w3.org/2007/08/xml.xsd">
- http://www.w3.org/2007/08/xml.xsd</a></li>
- <li><a href="http://www.w3.org/2004/10/xml.xsd">
- http://www.w3.org/2004/10/xml.xsd</a></li>
- <li><a href="http://www.w3.org/2001/03/xml.xsd">
- http://www.w3.org/2001/03/xml.xsd</a></li>
- </ul>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-
-</xs:schema>
-
diff --git a/keystone/content/common/xsd/credentials.xsd b/keystone/content/common/xsd/credentials.xsd
deleted file mode 100644
index 36e59942..00000000
--- a/keystone/content/common/xsd/credentials.xsd
+++ /dev/null
@@ -1,105 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
-
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <!-- Elements -->
- <element name="auth" type="identity:AuthenticationRequest"/>
- <element name="credential" type="identity:CredentialType"/>
- <element name="credentials" type="identity:CredentialListType"/>
- <element name="passwordCredentials" type="identity:PasswordCredentialsRequiredUsername" substitutionGroup="identity:credential"/>
-
- <!-- Complex Types -->
- <complexType name="CredentialType" abstract="true">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Base type for credential in Keystone.
- </p>
- </xsd:documentation>
- </annotation>
- <sequence>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
-
- <complexType name="AuthenticationRequest">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Both the tenantId and tenantName are optional, but should not be specified together. If both attributes are specified, the server SHOULD respond with a 400 Bad Request.
- </p>
- </xsd:documentation>
- </annotation>
- <sequence>
- <choice>
- <element ref="identity:credential" minOccurs="1"/>
- <element name="token" type="identity:TokenForAuthenticationRequest"/>
- </choice>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="tenantId" type="xsd:string" use="optional"/>
- <attribute name="tenantName" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="TokenForAuthenticationRequest">
- <attribute name="id" type="xsd:string" use="required"/>
- </complexType>
-
- <complexType name="PasswordCredentialsBase">
- <complexContent>
- <extension base="identity:CredentialType">
- <attribute name="username" type="xsd:string" use="optional" />
- <attribute name="password" type="xsd:string" use="required" />
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="PasswordCredentialsWithoutUsername">
- <complexContent>
- <restriction base="identity:PasswordCredentialsBase">
- <attribute name="username" type="xsd:string" use="prohibited" />
- <attribute name="password" type="xsd:string" use="required" />
- </restriction>
- </complexContent>
- </complexType>
-
- <complexType name="PasswordCredentialsRequiredUsername">
- <complexContent>
- <restriction base="identity:PasswordCredentialsBase">
- <attribute name="username" type="xsd:string" use="required" />
- <attribute name="password" type="xsd:string" use="required" />
- </restriction>
- </complexContent>
- </complexType>
-
- <complexType name="CredentialListType">
- <sequence>
- <element ref="identity:credential" minOccurs="1" maxOccurs="unbounded"/>
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>
diff --git a/keystone/content/common/xsd/endpoints.xsd b/keystone/content/common/xsd/endpoints.xsd
deleted file mode 100644
index dbb07516..00000000
--- a/keystone/content/common/xsd/endpoints.xsd
+++ /dev/null
@@ -1,161 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
- >
- <include schemaLocation="services.xsd"/>
- <include schemaLocation="token.xsd"/>
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <element name="endpoint" type="identity:Endpoint">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An Endpoint.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element name="endpoints" type="identity:EndpointList">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of Endpoints.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <!-- Complex Types -->
- <complexType name="Endpoint">
- <sequence>
- <element name="version" type="identity:VersionForService" maxOccurs="1" minOccurs="0">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Version details.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="id" type="xsd:string" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An ID uniquely identifying the Endpoint.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="type" type="identity:ExtensibleServiceType" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The OpenStack-registered type (e.g. 'compute', 'object-store', etc).
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The commercial service name (e.g. 'My Nova Cloud Servers').
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="region" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The region of Endpoint Template.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="publicURL" type="xsd:anyURI" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The public URL to access represented service.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="internalURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The internal version of the public URL.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="adminURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The admin URL.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="tenantId" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Tenant id to which the endpoints belong.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="EndpointList">
- <sequence>
- <element name="endpoint" type="identity:Endpoint" minOccurs="0" maxOccurs="unbounded"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>
diff --git a/keystone/content/common/xsd/extensions.xsd b/keystone/content/common/xsd/extensions.xsd
deleted file mode 100644
index 26694c07..00000000
--- a/keystone/content/common/xsd/extensions.xsd
+++ /dev/null
@@ -1,60 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<xsd:schema elementFormDefault="qualified" attributeFormDefault="unqualified"
- targetNamespace="http://docs.openstack.org/common/api/v1.0"
- xmlns:ext="http://docs.openstack.org/common/api/v1.0"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:atom="http://www.w3.org/2005/Atom"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema">
-
- <!-- Import ATOM specific schema definitions -->
- <xsd:import namespace="http://www.w3.org/2005/Atom" schemaLocation="atom/atom.xsd" />
-
- <xsd:element name="extensions" type="ext:Extensions"/>
- <xsd:element name="extension" type="ext:Extension"/>
-
- <xsd:complexType name="Extensions">
- <xsd:sequence>
- <xsd:element name="extension" type="ext:Extension" minOccurs="0" maxOccurs="unbounded" />
- <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </xsd:sequence>
- <xsd:anyAttribute namespace="##other" processContents="lax"/>
- </xsd:complexType>
-
- <xsd:complexType name="Extension">
- <xsd:sequence>
- <xsd:element name="description" type="xsd:string" minOccurs="1" />
- <!--<xsd:element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />-->
- <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required"/>
- <xsd:attribute name="namespace" type="xsd:anyURI" use="required"/>
- <xsd:attribute name="alias" type="ext:Alias" use="required"/>
- <xsd:attribute name="updated" type="xsd:dateTime" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="lax"/>
- <!--TODO(Ziad)resolve asser issue
- <xsd:assert vc:minVersion="1.1" test="atom:link[@rel='describedby']">
- <xsd:annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- There should be at least one atom link
- with a describedby relation.
- </p>
- </xsd:documentation>
- </xsd:annotation>
- </xsd:assert>-->
- </xsd:complexType>
-
- <xsd:simpleType name="Alias">
- <xsd:restriction base="xsd:string">
- <xsd:pattern value="\w+\-\w+" />
- </xsd:restriction>
- </xsd:simpleType>
-
-</xsd:schema> \ No newline at end of file
diff --git a/keystone/content/common/xsd/fault.xsd b/keystone/content/common/xsd/fault.xsd
deleted file mode 100644
index 4776ddaf..00000000
--- a/keystone/content/common/xsd/fault.xsd
+++ /dev/null
@@ -1,138 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
- <!-- Fault Elements -->
- <element name="identityFault" type="identity:IdentityFault"/>
- <element name="serviceUnavailable" type="identity:ServiceUnavailableFault"/>
- <element name="badRequest" type="identity:BadRequestFault"/>
- <element name="unauthorized" type="identity:UnauthorizedFault"/>
- <element name="overLimit" type="identity:OverLimitFault"/>
- <element name="userDisabled" type="identity:UserDisabledFault"/>
- <element name="forbidden" type="identity:ForbiddenFault"/>
- <element name="itemNotFound" type="identity:ItemNotFoundFault"/>
- <element name="tenantConflict" type="identity:TenantConflictFault"/>
-
- <!-- Fault Types -->
- <complexType name="IdentityFault">
- <sequence>
- <element name="message" type="xsd:string">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A human readable message that is appropriate for display
- to the end user.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element name="details" type="xsd:string" minOccurs="0">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The optional &lt;details&gt; element may contain useful
- information for tracking down errors (e.g a stack
- trace). This information may or may not be appropriate
- for display to an end user.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="code" type="xsd:int" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The HTTP status code associated with the current fault.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="ServiceUnavailableFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="BadRequestFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="UnauthorizedFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="UserDisabledFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="ForbiddenFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="ItemNotFoundFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="TenantConflictFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- </extension>
- </complexContent>
- </complexType>
-
- <complexType name="OverLimitFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- <attribute name="retryAt" type="xsd:dateTime" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An optional dateTime denoting when an operation should
- be retried.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- </extension>
- </complexContent>
- </complexType>
-
-</schema>
diff --git a/keystone/content/common/xsd/roles.xsd b/keystone/content/common/xsd/roles.xsd
deleted file mode 100644
index 0ed30143..00000000
--- a/keystone/content/common/xsd/roles.xsd
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
-
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <!-- Elements -->
- <element name="roles" type="identity:RoleList" >
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of roles.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <element name="role" type="identity:Role" >
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A role.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
-
- <!-- Complex Types -->
- <complexType name="Role">
- <attribute name="id" type="xsd:string" use="optional"/>
- <attribute name="name" type="xsd:string" use="required"/>
- <attribute name="description" type="xsd:string" use="optional"/>
- <attribute name="serviceId" type="xsd:string" use="optional"/>
- <attribute name="tenantId" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="RoleList">
- <sequence>
- <element name="role" type="identity:Role" minOccurs="0" maxOccurs="unbounded"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema> \ No newline at end of file
diff --git a/keystone/content/common/xsd/services.xsd b/keystone/content/common/xsd/services.xsd
deleted file mode 100644
index 248e1e93..00000000
--- a/keystone/content/common/xsd/services.xsd
+++ /dev/null
@@ -1,103 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
-
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <!-- Simple Types -->
- <simpleType name="ExtensibleServiceType">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An extensible service type allows all of the
- strings defined in <a href="#type_ServiceType"
- title="See definition of
- ServiceType">ServiceType</a> or an
- alias prefixed status.
- </p>
- </xsd:documentation>
- </annotation>
- <union memberTypes="identity:ServiceType identity:ExtendedService"/>
- </simpleType>
-
- <simpleType name="ServiceType">
- <restriction base="xsd:string">
- <enumeration value="compute">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The type for an OpenStack Compute API 1.1 compatible service.
- </p>
- </xsd:documentation>
- </annotation>
- </enumeration>
- <enumeration value="object-store">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The type for a Swift-compatible service.
- </p>
- </xsd:documentation>
- </annotation>
- </enumeration>
- <enumeration value="image-service">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The type for a Glance-compatible service
- </p>
- </xsd:documentation>
- </annotation>
- </enumeration>
- <enumeration value="identity">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The type for a Keystone-compatible service.
- </p>
- </xsd:documentation>
- </annotation>
- </enumeration>
- </restriction>
- </simpleType>
-
- <simpleType name="ExtendedService">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A non-core service type which must contain an extension prefix.
- </p>
- </xsd:documentation>
- </annotation>
- <restriction base="xsd:string">
- <pattern value="(\w|-)+:\w+"/>
- </restriction>
- </simpleType>
-</schema> \ No newline at end of file
diff --git a/keystone/content/common/xsd/tenant.xsd b/keystone/content/common/xsd/tenant.xsd
deleted file mode 100644
index 8e64bd14..00000000
--- a/keystone/content/common/xsd/tenant.xsd
+++ /dev/null
@@ -1,151 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <!-- Elements -->
- <element name="tenant" type="identity:Tenant">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A container used to group or isolate resources and/or identity
- objects. Depending on the service operator, a tenant may map to a customer,
- account, organization, or project.
- </p>
- </xsd:documentation>
- <xsd:appinfo>
- <xsdxt:samples>
-          <xsdxt:sample>
-            <xsdxt:code type="application/xml" href="../samples/tenant.xml" />
-          </xsdxt:sample>
-          <xsdxt:sample>
-            <xsdxt:code type="application/json" href="../samples/tenant.json" />
-          </xsdxt:sample>
-        </xsdxt:samples>
- </xsd:appinfo>
- </annotation>
- </element>
- <element name="tenants" type="identity:Tenants">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of tenants.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <!-- Complex Types -->
- <complexType name="Tenants">
- <sequence>
- <element name="tenant" type="identity:Tenant" maxOccurs="100"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="Tenant">
- <sequence>
- <element name="description" type="xsd:string" minOccurs="0">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An free text description of the tenant.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="id" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An ID uniquely identifying the tenant. This usually comes from the back-end store.
- This value is guaranteed to be unique and immutable (it will never change).
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="xsd:string" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The name of the tenant. This is guaranteed to be unique, but may change.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="enabled" type="xsd:boolean" use="optional" default="true">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An boolean signifying if a tenant is enabled or not. A disabled tenant
- cannot be authenticated against.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="display-name" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A human-readable, friendly name for use in user interfaces.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute type="xsd:dateTime" name="updated" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A time-stamp identifying the modification time of the
- tenant.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute type="xsd:dateTime" name="created" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A creation time-stamp for the tenant.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>
diff --git a/keystone/content/common/xsd/token.xsd b/keystone/content/common/xsd/token.xsd
deleted file mode 100644
index 5e410716..00000000
--- a/keystone/content/common/xsd/token.xsd
+++ /dev/null
@@ -1,298 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
-
- <include schemaLocation="roles.xsd"/>
- <include schemaLocation="services.xsd"/>
-
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <!-- Elements -->
- <element name="access" type="identity:AuthenticateResponse"/>
-
- <!-- Complex Types -->
- <complexType name="Token">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A token is an arbitrary bit of text that is used to access
- resources. Each token has a scope which describes which
- resources are accessible with it. A token may be
- revoked at anytime and is valid for a finite duration.
- </p>
- <p>
- While Keystone supports token-based authentication in this release,
- the intention is for it to support additional protocols in the
- future. The desire is for it to be an integration service, and not
- a full-fledged identity store and management solution.
- </p>
- </xsd:documentation>
- <xsd:appinfo>
- <xsdxt:samples>
- <xsdxt:sample>
- <xsdxt:code type="application/xml" href="../samples/token.xml" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/json" href="../samples/token.json" />
- </xsdxt:sample>
- </xsdxt:samples>
- </xsd:appinfo>
- </annotation>
- <sequence>
- <element name="tenant" type="identity:TenantForAuthenticateResponse"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="id" type="xsd:string" use="required"/>
- <attribute name="expires" type="xsd:dateTime" use="required"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="AuthenticateResponse">
- <sequence>
- <element name="token" type="identity:Token"/>
- <element name="user" type="identity:UserForAuthenticateResponse"/>
- <element name="serviceCatalog" type="identity:ServiceCatalog" minOccurs="0"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="UserForAuthenticateResponse">
- <sequence>
- <element name="roles" type="identity:RoleList" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="id" type="xsd:string"/>
- <attribute name="name" type="xsd:string"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="TenantForAuthenticateResponse">
- <attribute name="id" type="xsd:string"/>
- <attribute name="name" type="xsd:string"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="ServiceCatalog">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The service catalog lists the services you have access to
- </p>
- <div class="design">
- <p>
- We optimized for future flexibility around the hierarchy. So we
- left the design as a flat list of endpoints with attributes and the
- consumer can categorize as they need.
- This results in potential duplication (such as with the version/@list)
- but we acceopt that normalization cost in order to not force an
- artificial hierarchy (suchas on region, which can be optional).
- </p>
- </div>
- </xsd:documentation>
- <xsd:appinfo>
- <xsdxt:samples>
-          <xsdxt:sample>
-            <xsdxt:code type="application/xml" href="../samples/services.xml" />
-          </xsdxt:sample>
-          <xsdxt:sample>
-            <xsdxt:code type="application/json" href="../samples/services.json" />
-          </xsdxt:sample>
-        </xsdxt:samples>
- </xsd:appinfo>
- </annotation>
- <sequence>
- <element name="service" type="identity:ServiceForCatalog" minOccurs="1" maxOccurs="unbounded">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of services.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="ServiceForCatalog">
- <sequence>
- <element name="endpoint" type="identity:EndpointForService" minOccurs="1" maxOccurs="unbounded">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A list of endpoints.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="type" type="identity:ExtensibleServiceType" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The OpenStack-registered type (e.g. 'compute', 'object-store', etc).
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="name" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The commercial service name (e.g. 'My Nova Cloud Servers').
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <!--EndpointForService-->
- <complexType name="EndpointForService">
- <sequence>
- <element name="version" type="identity:VersionForService" maxOccurs="1" minOccurs="0">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Version details.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <attribute name="region" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- The name of the region where the endpoint
- lives. Example: airport codes; LHR (UK),
- STL (Saint Louis)
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="tenantId" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Tenant id to which the endpoints belong.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="publicURL" type="xsd:anyURI" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Public accessible service URL.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="internalURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A service URL, accessible only locally within that
- cloud (generally over a high bandwidth, low latency,
- free of charge link).
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="adminURL" type="xsd:anyURI" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An Admin URL (used for administration using privileged
- calls). This may expose
- additional functionality not found in the public and
- internal URL.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <!-- VersionForService -->
- <complexType name="VersionForService">
- <attribute name="id" type="xsd:string" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Id of the version.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="info" type="xsd:anyURI" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- URI to get the information specific to this version.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="list" type="xsd:anyURI" use="required">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- URI to get the information about all versions.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>
-
diff --git a/keystone/content/common/xsd/user.xsd b/keystone/content/common/xsd/user.xsd
deleted file mode 100644
index 526b0f84..00000000
--- a/keystone/content/common/xsd/user.xsd
+++ /dev/null
@@ -1,131 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<schema
- elementFormDefault="qualified"
- attributeFormDefault="unqualified"
- xmlns="http://www.w3.org/2001/XMLSchema"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:atom="http://www.w3.org/2005/Atom"
- targetNamespace="http://docs.openstack.org/identity/api/v2.0"
->
-
- <!-- Import ATOM specific schema definitions -->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom"
- schemaLocation="atom/atom.xsd" />
-
- <!-- Elements -->
- <element name="users" type="identity:UserList" >
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/2001/XMLSchema">
- <p>
- A list of Users.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <element name="user" type="identity:User">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/2001/XMLSchema">
- <p>
- A Keystone User.
- </p>
- </xsd:documentation>
- </annotation>
- </element>
-
- <!-- Complex Types -->
- <complexType name="User">
- <attribute name="id" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- An automatically generated, unique, immutable (it will never change) identifier
- for the user. This is generated by the backend this user is stored in.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="username" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A unique, mutable (it can change) user name that may be used by the user
- an identifier when presenting credentials.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="email" type="xsd:string" use="optional"/>
- <attribute name="enabled" type="xsd:boolean" default="true" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A true/false value that determines if the user may authenticate or not.
- If enabled is false, the user will not be able to authenticate.
- How this value is stored or generated is dependent on the backend in use.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="display-name" type="xsd:string" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A human-readable, friendly name for use in user interfaces.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="updated" type="xsd:dateTime" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A time-stamp identifying the modification time of the
- user.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <attribute name="created" type="xsd:dateTime" use="optional">
- <annotation>
- <xsd:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- A creation time-stamp for the user.
- </p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-
- <complexType name="UserList">
- <sequence>
- <element name="user" type="identity:User" minOccurs="0" maxOccurs="unbounded"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>
diff --git a/keystone/content/common/xsd/version.xsd b/keystone/content/common/xsd/version.xsd
deleted file mode 100644
index a65d1ff2..00000000
--- a/keystone/content/common/xsd/version.xsd
+++ /dev/null
@@ -1,357 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-
-<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified"
- targetNamespace="http://docs.openstack.org/common/api/v1.0"
- xmlns:vers="http://docs.openstack.org/common/api/v1.0"
- xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:atom="http://www.w3.org/2005/Atom"
- xmlns:xs="http://www.w3.org/2001/XMLSchema">
-
- <xs:annotation>
- <xs:appinfo
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <xsdxt:title>Version Types</xsdxt:title>
- <xsdxt:link rel="index" href="api-common.xsd" />
- </xs:appinfo>
- <xs:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- This schema file defines all types related to versioning.
- </p>
- </xs:documentation>
- </xs:annotation>
-
- <!-- Import ATOM specific schema definitions -->
- <xs:import namespace="http://www.w3.org/2005/Atom" schemaLocation="atom/atom.xsd" />
-
- <!-- Multiple choices -->
- <xs:element name="choices" type="vers:VersionChoiceList">
- <xs:annotation>
- <xs:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- This element is returned when the version of the
- resource cannot be determined. The element
- provides a list of choices for the resource.
- </p>
- </xs:documentation>
- <xs:appinfo>
- <xsdxt:samples>
- <xsdxt:sample>
- <xsdxt:code type="application/xml" href="../samples/choices.xml" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/json" href="../samples/choices.json" />
- </xsdxt:sample>
- </xsdxt:samples>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
-
- <!-- Versioning -->
- <xs:element name="versions" type="vers:VersionChoiceList">
- <xs:annotation>
- <xs:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Provides a list of supported versions.
- </p>
- </xs:documentation>
- <xs:appinfo>
- <xsdxt:samples>
- <xsdxt:sample>
- <xsdxt:code type="application/xml" href="../samples/versions.xml" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/json" href="../samples/versions.json" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/atom+xml" href="../samples/versions-atom.xml" />
- </xsdxt:sample>
- </xsdxt:samples>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
- <xs:element name="version" type="vers:VersionChoice" vc:minVersion="1.0" vc:maxVersion="1.1">
- <xs:annotation>
- <xs:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- This element provides detailed meta information
- regarding the status of the current API version.
- This is the XSD 1.0 compatible element definition.
- </p>
- </xs:documentation>
- </xs:annotation>
- </xs:element>
-
- <xs:element name="version2" type="vers:VersionChoiceRoot" vc:minVersion="1.1">
- <xs:annotation>
- <xs:documentation
- xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- This element provides detailed meta information
- regarding the status of the current API
- version. The description should include a pointer
- to both a human readable and a machine processable
- description of the API service.
- </p>
- </xs:documentation>
- <xs:appinfo>
- <xsdxt:samples>
- <xsdxt:sample>
- <xsdxt:code type="application/xml" href="../samples/version.xml" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/json" href="../samples/version.json" />
- </xsdxt:sample>
- <xsdxt:sample>
- <xsdxt:code type="application/atom+xml" href="../samples/version-atom.xml" />
- </xsdxt:sample>
- </xsdxt:samples>
- </xs:appinfo>
- </xs:annotation>
- </xs:element>
-
- <!-- Types -->
- <xs:simpleType name="VersionStatus">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- The VersionStatus type describes a service's operational status.
- </html:p>
- </xs:documentation>
- </xs:annotation>
-
- <xs:restriction base="xs:string">
- <xs:enumeration value="ALPHA">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- This is a new service the API. Thi API
- contract may be set, but the implementaiton
- may not be 100% complient with it. Developers
- are encouraged to begin testing aganst an
- ALPHA version to provide feedback.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:enumeration>
- <xs:enumeration value="BETA">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A status of BETA indicates that this
- version is a candidate for the next major
- release and may feature functionality not
- available in the current
- version. Developers are encouraged to test
- and begin the migration processes to a
- BETA version. Note that a BETA version is
- undergoing testing, it has not been
- officially released, and my not be stable.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:enumeration>
- <xs:enumeration value="CURRENT">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- The API version is stable and has been
- tested. Developers are encouraged to
- develop against this API version. The
- current released version of the API will
- always be marked as CURRENT.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:enumeration>
- <xs:enumeration value="DEPRECATED">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A status of DEPRECATED indicates that a
- newer version of the API is
- available. Application developers are
- discouraged from using this version and
- should instead develop against the latest
- current version of the API.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:enumeration>
- </xs:restriction>
- </xs:simpleType>
-
- <xs:complexType name="VersionChoiceList">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A version choice list outlines a collection of
- resources at various versions.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:element name="version" type="vers:VersionChoice" minOccurs="1" maxOccurs="unbounded" />
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </xs:sequence>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- <!--TODO(Ziad)resolve assert issue
- <xs:assert vc:minVersion="1.1" test="every $v in vers:version satisfies $v/atom:link[@rel='self']">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- In version lists, every single version must
- contain at least one self link.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:assert>-->
- </xs:complexType>
-
- <xs:complexType name="VersionChoiceRoot" vc:minVersion="1.1">
- <xs:complexContent>
- <xs:extension base="vers:VersionChoice">
- <!--TODO(Ziad)resolve asser issue
- <xs:assert test="atom:link[@rel='describedby']">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- When used as a root element, a version choice
- must contain at least one describedby link.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:assert>-->
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
-
- <xs:complexType name="VersionChoice">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A version choice contains relevant information
- about an available service that a user can then
- use to target a specific version of the service.
- </html:p>
- </xs:documentation>
- </xs:annotation>
-
- <xs:sequence>
- <xs:element name="media-types" type="vers:MediaTypeList" minOccurs="0" maxOccurs="1" />
- <!--<xs:element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded" />-->
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </xs:sequence>
-
- <xs:attribute name="id" type="xs:string" use="required">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- The ID of a version choice represents the service version's unique
- identifier. This ID is guaranteed to be unique only among the
- service version choices outlined in the VersionChoiceList.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="status" type="vers:VersionStatus" use="required">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A version choice's status describes the current operational state of
- the given service version. The operational status is captured in a
- simple type enumeration called VersionStatus.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="updated" type="xs:dateTime" use="optional">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A version choice's updated attribute describes
- the time when the version was updated. The
- time should be updated anytime
- <html:strong>anything</html:strong> in the
- version has changed: documentation,
- extensions, bug fixes.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- </xs:complexType>
-
- <xs:complexType name="MediaTypeList">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A MediaTypeList outlines a collection of valid media types for a given
- service version.
- </html:p>
- </xs:documentation>
- </xs:annotation>
-
- <xs:sequence>
- <xs:element name="media-type" type="vers:MediaType" minOccurs="1" maxOccurs="unbounded" />
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </xs:sequence>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- </xs:complexType>
-
- <xs:complexType name="MediaType">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A MediaType describes what content types the service version understands.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded" />
- </xs:sequence>
- <xs:attribute name="base" type="xs:string" use="optional" default="">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- The base of a given media type describes the
- simple MIME type that then a more complicated
- media type can be derived from. These types
- are basic and provide no namespace or version
- specific data are are only provided as a
- convenience.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
-
- <xs:attribute name="type" type="xs:string" use="required">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- The type attribute of a MediaType describes
- the MIME specific identifier of the media type
- in question.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- </xs:complexType>
-</xs:schema>
diff --git a/keystone/content/common/xslt/schema.xslt b/keystone/content/common/xslt/schema.xslt
deleted file mode 100644
index 6d602cc7..00000000
--- a/keystone/content/common/xslt/schema.xslt
+++ /dev/null
@@ -1,1342 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<!-- (C) 2009 Rackspace Hosting, All Rights Reserved -->
-
-
-<xslt:stylesheet version="1.0"
- xmlns:xslt="http://www.w3.org/1999/XSL/Transform"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0"
- xmlns="http://www.w3.org/1999/xhtml"
- >
-
- <xslt:output method="html"
- encoding="UTF-8"
- media-type="text/html"
- doctype-public = "-//W3C//DTD HTML 4.01//EN"
- doctype-system = "http://www.w3.org/TR/html4/strict.dtd" />
-
- <!-- Params -->
- <xslt:param name="base">
- <xslt:choose>
- <xslt:when test="/xsd:schema/@xsdxt:base">
- <xslt:value-of select="/xsd:schema/@xsdxt:base"/>
- </xslt:when>
- <xslt:otherwise>
- <xslt:text>..</xslt:text>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:param>
-
- <!-- Global Variables -->
- <xslt:variable name="defaultTitle">XML Schema Documentation</xslt:variable>
- <xslt:variable name="templateType">application/xhtml+xml</xslt:variable>
- <xslt:variable name="schemaNamespace">http://www.w3.org/2001/XMLSchema</xslt:variable>
- <xslt:variable name="schemaDatatypeURI">http://web4.w3.org/TR/2001/REC-xmlschema-2-20010502/#</xslt:variable>
-
- <xslt:variable name="dQuote">"</xslt:variable>
- <xslt:variable name="sQuote">'</xslt:variable>
-
- <!-- The namespace prefixes -->
- <xslt:variable name="targetPrefix">
- <xslt:for-each select="/xsd:schema/namespace::node()">
- <xslt:if test=".=/xsd:schema/@targetNamespace">
- <xslt:value-of select="name(.)"/>
- </xslt:if>
- </xslt:for-each>
- </xslt:variable>
-
- <xslt:variable name="schemaPrefix">
- <xslt:for-each select="/xsd:schema/namespace::node()">
- <xslt:if test="(.=$schemaNamespace) and (string-length(.) > 0)">
- <xslt:value-of select="name(.)"/>
- </xslt:if>
- </xslt:for-each>
- </xslt:variable>
-
- <!-- Anchor prefixes -->
- <xslt:variable name="elementPrefix">element_</xslt:variable>
- <xslt:variable name="attributePrefix">attrib_</xslt:variable>
- <xslt:variable name="attributeGroupPrefix">attgrp_</xslt:variable>
- <xslt:variable name="groupPrefix">grp_</xslt:variable>
- <xslt:variable name="typePrefix">type_</xslt:variable>
-
- <!-- YUI BASE: -->
- <!--
- We only load YUI style sheets here. We bring js stuff
- dynamically. Stylesheet's can't really be brought dynamically.
- They need to be loaded before anything else.
- -->
- <xslt:variable name="YUI_BASE">http://yui.yahooapis.com/2.7.0/build/</xslt:variable>
- <xslt:variable name="YUI_RESET_STYLESHEET">
- <xslt:value-of select="concat($YUI_BASE,'reset/reset-min.css')" />
- </xslt:variable>
- <xslt:variable name="YUI_BASE_STYLESHEET">
- <xslt:value-of select="concat($YUI_BASE,'base/base-min.css')" />
- </xslt:variable>
- <xslt:variable name="YUI_FONTS_STYLESHEET">
- <xslt:value-of select="concat($YUI_BASE,'fonts/fonts-min.css')" />
- </xslt:variable>
- <xslt:variable name="YUI_GRIDS_STYLESHEET">
- <xslt:value-of select="concat($YUI_BASE,'grids/grids-min.css')" />
- </xslt:variable>
-
- <xslt:template name="addStylesheet">
- <xslt:param name="sheet" />
- <xslt:element name="link">
- <xslt:attribute name="rel">stylesheet</xslt:attribute>
- <xslt:attribute name="type">text/css</xslt:attribute>
- <xslt:attribute name="href">
- <xslt:value-of select="$sheet"/>
- </xslt:attribute>
- </xslt:element>
- </xslt:template>
-
- <!-- Templates -->
- <xslt:template name="SchemaHandler" match="xsd:schema">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
- <xslt:call-template name="addStylesheet">
- <xslt:with-param name="sheet" select="$YUI_RESET_STYLESHEET"/>
- </xslt:call-template>
- <xslt:call-template name="addStylesheet">
- <xslt:with-param name="sheet" select="$YUI_BASE_STYLESHEET"/>
- </xslt:call-template>
- <xslt:call-template name="addStylesheet">
- <xslt:with-param name="sheet" select="$YUI_FONTS_STYLESHEET"/>
- </xslt:call-template>
- <xslt:call-template name="addStylesheet">
- <xslt:with-param name="sheet" select="$YUI_GRIDS_STYLESHEET"/>
- </xslt:call-template>
- <xslt:call-template name="addStylesheet">
- <xslt:with-param name="sheet" select="concat($base,'/style/schema.css')"/>
- </xslt:call-template>
-
- <!--
- Add custom links...
- -->
- <xslt:for-each select="//xsdxt:link">
- <xslt:if test="not(@qname)">
- <xslt:element name="link">
- <xslt:if test="@rev">
- <xslt:attribute name="rev"><xslt:value-of select="@rev"/></xslt:attribute>
- </xslt:if>
- <xslt:if test="@rel">
- <xslt:attribute name="rel"><xslt:value-of select="@rel"/></xslt:attribute>
- </xslt:if>
- <xslt:if test="@href">
- <xslt:attribute name="href"><xslt:value-of select="@href"/></xslt:attribute>
- </xslt:if>
- <xslt:if test="@type">
- <xslt:attribute name="type"><xslt:value-of select="@type"/></xslt:attribute>
- </xslt:if>
- </xslt:element>
- </xslt:if>
- </xslt:for-each>
-
- <!--
- Set the title if it's available, default title if not.
- -->
- <xslt:choose>
- <xslt:when test="xsd:annotation/xsd:appinfo/xsdxt:title">
- <title><xslt:value-of select="xsd:annotation/xsd:appinfo/xsdxt:title"/></title>
- </xslt:when>
- <xslt:otherwise>
- <title><xslt:value-of select="$defaultTitle"/></title>
- </xslt:otherwise>
- </xslt:choose>
-
- <!-- Schema scripts -->
- <script type="text/javascript" src="{$base}/js/trc/util.js"> </script>
- <script type="text/javascript" src="{$base}/js/trc/schema/layoutManager.js"> </script>
- <script type="text/javascript" src="{$base}/js/trc/schema/sampleManager.js"> </script>
- <script type="text/javascript" src="{$base}/js/trc/schema/controller.js"> </script>
-
- <xslt:if test="//xsdxt:samples | //xsdxt:code">
- <script type="text/javascript">
- <xslt:for-each select="//xsdxt:samples">
- <xslt:variable name="elmId"><xslt:value-of select="generate-id(.)"/></xslt:variable>
- <xslt:if test="xsdxt:sample">
- <xslt:text>trc.schema.sampleManager.samples["</xslt:text>
- <xslt:value-of select="$elmId"/>
- <xslt:text>"]=[</xslt:text>
- <xslt:for-each select="xsdxt:sample">
- <xslt:call-template name="StringToJavascript">
- <xslt:with-param name="inString" select="generate-id(.)"/>
- </xslt:call-template>
- <xslt:if test="generate-id(../xsdxt:sample[count(../xsdxt:sample)]) !=
- generate-id(.)
- ">
- <xslt:text>,</xslt:text>
- </xslt:if>
- </xslt:for-each>
- <xslt:text>];</xslt:text>
- </xslt:if>
- </xslt:for-each>
- <xslt:if test="//xsdxt:code">
- <xslt:text>trc.schema.sampleManager.codes.push(</xslt:text>
- <xslt:for-each select="//xsdxt:code">
- <xslt:text>{ id : </xslt:text>
- <xslt:value-of select="concat($dQuote,generate-id(.),$dQuote)" />
- <xslt:text>, type : "</xslt:text>
- <xslt:choose>
- <xslt:when test="@type">
- <xslt:value-of select="@type"/>
- </xslt:when>
- <xslt:otherwise>
- <xslt:text>application/xml</xslt:text>
- </xslt:otherwise>
- </xslt:choose>
- <xslt:text>", href : </xslt:text>
- <xslt:choose>
- <xslt:when test="@href">
- <xslt:value-of select="concat($dQuote,@href,$dQuote)"/>
- </xslt:when>
- <xslt:otherwise>
- <xslt:text>null</xslt:text>
- </xslt:otherwise>
- </xslt:choose>
- <xslt:text>}</xslt:text>
- <xslt:text>,</xslt:text>
- </xslt:for-each>
- <xslt:text>null);</xslt:text>
- </xslt:if>
- </script>
- </xslt:if>
-
- <xslt:call-template name="ControllerJSHandler" />
-
- <!--
- Copy any HTML header tags here
- -->
- <xslt:for-each select="//xsdxt:head">
- <xslt:choose>
- <xslt:when test="not(@type)">
- <xslt:copy-of select="./*" />
- </xslt:when>
- <xslt:when test="@type = $templateType">
- <xslt:copy-of select="./*" />
- </xslt:when>
- </xslt:choose>
- </xslt:for-each>
- </head>
- <body>
- <div id="Controller">
- </div>
- <div id="doc">
- <div id="Main">
- <div id="SrcContent">
- <div class="SampleCode">
- <pre id="SrcContentCode">Loading...</pre>
- </div>
- </div>
- <div id="Content">
- <!--
- If there is a title use it as a first heading, otherwise,
- use default title.
- -->
- <xslt:choose>
- <xslt:when test="xsd:annotation/xsd:appinfo/xsdxt:title">
- <h1><xslt:value-of select="xsd:annotation/xsd:appinfo/xsdxt:title"/></h1>
- </xslt:when>
- <xslt:otherwise>
- <h1><xslt:value-of select="$defaultTitle"/></h1>
- </xslt:otherwise>
- </xslt:choose>
-
- <!--
- Schema attributes
- -->
- <table summary="Schema-level attributes">
- <tbody>
- <xslt:for-each select="@*">
- <tr>
- <td><xslt:value-of select="local-name(.)"/></td>
- <td><xslt:value-of select="."/></td>
- </tr>
- </xslt:for-each>
- </tbody>
- </table>
-
- <!--
- Copy schema-level documentation if there's anything to
- copy. This also processes any internal documentation
- annotations: currently just xsdxt:code.
- -->
- <xslt:apply-templates select="xsd:annotation/xsd:documentation/*" mode="Docs"/>
-
- <!--
- Next comes custom header...
- -->
- <div id="Header">
- <xslt:for-each select="//xsdxt:header">
- <xslt:choose>
- <xslt:when test="not(@type)">
- <xslt:copy-of select="./*" />
- </xslt:when>
- <xslt:when test="@type = $templateType">
- <xslt:copy-of select="./*" />
- </xslt:when>
- </xslt:choose>
- </xslt:for-each>
- </div>
-
-
- <!--
- Namespace info, not all borowsers have namespace node
- support. Specifically Firefox currently lacks it.
-
- See:
- https://bugzilla.mozilla.org/show_bug.cgi?id=94270
-
- In this case we ask the user to try a different
- browser: Opera, Safari, or even IE.
- -->
- <h2>Namespaces</h2>
- <xslt:choose>
- <xslt:when test="count(namespace::*) = 0">
- <!--Namespaces are not available...-->
- <div class="Warning">
- <p>
- Your browser does not seem to have support for
- namespace nodes in XPath. If you're a Firefox
- user, please consider voting to get this issue
- resolved:
- <a href="https://bugzilla.mozilla.org/show_bug.cgi?id=94270"
- title="FireFox Bug 94270">
- https://bugzilla.mozilla.org/show_bug.cgi?id=94270
- </a>
- </p>
- </div>
- </xslt:when>
- <xslt:otherwise>
- <table summary="Namespace details">
- <tbody>
- <xslt:for-each select="namespace::*">
- <xslt:sort />
- <tr>
- <td><xslt:value-of select="name(.)"/></td>
- <td><xslt:value-of select="."/></td>
- </tr>
- </xslt:for-each>
- </tbody>
- </table>
- </xslt:otherwise>
- </xslt:choose>
-
- <!--
- Next, call the handlers for the top schema elements.
- -->
- <xslt:if test="xsd:import">
- <xslt:call-template name="ImportHandler" />
- </xslt:if>
- <xslt:if test="xsd:include">
- <xslt:call-template name="IncludeHandler" />
- </xslt:if>
-
- <xslt:if test="xsd:element">
- <xslt:call-template name="ElementHandler" />
- </xslt:if>
-
- <xslt:if test="xsd:complexType">
- <xslt:call-template name="ComplexTypeHandler" />
- </xslt:if>
-
- <xslt:if test="xsd:simpleType">
- <xslt:call-template name="SimpleTypeHandler" />
- </xslt:if>
-
- <!-- Finally, custom footers -->
- <div id="Footer">
- <xslt:for-each select="//xsdxt:footer">
- <xslt:choose>
- <xslt:when test="not(@type)">
- <xslt:copy-of select="./*" />
- </xslt:when>
- <xslt:when test="@type = $templateType">
- <xslt:copy-of select="./*" />
- </xslt:when>
- </xslt:choose>
- </xslt:for-each>
- </div>
- </div>
- </div>
- </div>
- </body>
- </html>
- </xslt:template>
-
- <xslt:template name="ControllerExternJSLinks">
- <xslt:param name="nodes" />
-
- <xslt:text>trc.schema.controller.links['</xslt:text>
- <xslt:value-of select="local-name($nodes[1])"/>
- <xslt:text>']=[</xslt:text>
- <xslt:for-each select="$nodes">
- <xslt:call-template name="ControllerJSLink">
- <xslt:with-param name="href" select="@schemaLocation"/>
- <xslt:with-param name="name">
- <xslt:choose>
- <xslt:when test="@namespace">
- <xslt:value-of select="@namespace" />
- </xslt:when>
- <xslt:otherwise>
- <xslt:value-of select="@schemaLocation" />
- </xslt:otherwise>
- </xslt:choose>
- </xslt:with-param>
- <xslt:with-param name="title">
- <xslt:choose>
- <xslt:when test="@namespace">
- <xslt:value-of select="concat('View schema for namespace ',@namespace)"/>
- </xslt:when>
- <xslt:otherwise>
- <xslt:value-of select="concat('Visit schema ',@schemaLocation)"/>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:with-param>
- </xslt:call-template>
- <xslt:if test="$nodes[count($nodes)]/@schemaLocation !=
- @schemaLocation">
- <xslt:text>,</xslt:text>
- </xslt:if>
- </xslt:for-each>
- <xslt:text>];</xslt:text>
- </xslt:template>
-
- <xslt:template name="ControllerIndexJSLink">
- <xslt:param name="node" select="//xsdxt:link[@rel = 'index']" />
-
- <xslt:text>trc.schema.controller.index = </xslt:text>
- <xslt:call-template name="ControllerJSLink">
- <xslt:with-param name="href">
- <xslt:value-of select="$node/@href"/>
- </xslt:with-param>
- <xslt:with-param name="name">
- <xslt:text>index</xslt:text>
- </xslt:with-param>
- <xslt:with-param name="title">
- <xslt:text>Index Schema Document</xslt:text>
- </xslt:with-param>
- </xslt:call-template>
- <xslt:text>;</xslt:text>
- </xslt:template>
-
- <xslt:template name="ControllerNamedElementJSLink">
- <xslt:param name="nodes" />
- <xslt:param name="anchorPrefix" />
-
- <xslt:text>trc.schema.controller.links['</xslt:text>
- <xslt:value-of select="local-name($nodes[1])"/>
- <xslt:text>']=[</xslt:text>
- <xslt:for-each select="$nodes">
- <xslt:call-template name="ControllerJSLink">
- <xslt:with-param name="href">
- <xslt:text>#</xslt:text>
- <xslt:value-of select="$anchorPrefix" />
- <xslt:value-of select="@name" />
- </xslt:with-param>
- <xslt:with-param name="name">
- <xslt:call-template name="StringToName"/>
- </xslt:with-param>
- <xslt:with-param name="title">
- <xslt:text>See definition of </xslt:text>
- <xslt:call-template name="StringToName"/>
- </xslt:with-param>
- </xslt:call-template>
- <xslt:if test="generate-id($nodes[count($nodes)]) !=
- generate-id(.)">
- <xslt:text>,</xslt:text>
- </xslt:if>
- </xslt:for-each>
- <xslt:text>];</xslt:text>
- </xslt:template>
-
- <xslt:template name="ControllerJSLink">
- <xslt:param name="name" />
- <xslt:param name="href" />
- <xslt:param name="title" />
-
- <xslt:text>{ href : </xslt:text>
- <xslt:call-template name="StringToJavascript">
- <xslt:with-param name="inString">
- <xslt:value-of select="$href"/>
- </xslt:with-param>
- </xslt:call-template>
- <xslt:text>, name : </xslt:text>
- <xslt:call-template name="StringToJavascript">
- <xslt:with-param name="inString">
- <xslt:value-of select="$name"/>
- </xslt:with-param>
- </xslt:call-template>
- <xslt:text>, title : </xslt:text>
- <xslt:call-template name="StringToJavascript">
- <xslt:with-param name="inString">
- <xslt:value-of select="$title"/>
- </xslt:with-param>
- </xslt:call-template>
- <xslt:text>}</xslt:text>
- </xslt:template>
-
- <!--
- Adds javascript for controller data..
- -->
- <xslt:template name="ControllerJSHandler">
- <script type="text/javascript">
- <xslt:if test="xsd:import">
- <xslt:call-template name="ControllerExternJSLinks">
- <xslt:with-param name="nodes" select="xsd:import" />
- </xslt:call-template>
- </xslt:if>
- <xslt:if test="xsd:include">
- <xslt:call-template name="ControllerExternJSLinks">
- <xslt:with-param name="nodes" select="xsd:include" />
- </xslt:call-template>
- </xslt:if>
- <xslt:if test="xsd:element">
- <xslt:call-template name="ControllerNamedElementJSLink">
- <xslt:with-param name="nodes" select="xsd:element"/>
- <xslt:with-param name="anchorPrefix" select="$elementPrefix"/>
- </xslt:call-template>
- </xslt:if>
- <xslt:if test="xsd:attribute">
- <xslt:call-template name="ControllerNamedElementJSLink">
- <xslt:with-param name="nodes" select="xsd:attribute"/>
- <xslt:with-param name="anchorPrefix" select="$attributePrefix"/>
- </xslt:call-template>
- </xslt:if>
- <xslt:if test="xsd:complexType">
- <xslt:call-template name="ControllerNamedElementJSLink">
- <xslt:with-param name="nodes" select="xsd:complexType"/>
- <xslt:with-param name="anchorPrefix" select="$typePrefix"/>
- </xslt:call-template>
- </xslt:if>
- <xslt:if test="xsd:simpleType">
- <xslt:call-template name="ControllerNamedElementJSLink">
- <xslt:with-param name="nodes" select="xsd:simpleType"/>
- <xslt:with-param name="anchorPrefix" select="$typePrefix"/>
- </xslt:call-template>
- </xslt:if>
- <xslt:if test="//xsdxt:link[@rel = 'index']">
- <xslt:call-template name="ControllerIndexJSLink" />
- </xslt:if>
- </script>
- </xslt:template>
-
- <xslt:template name="ImportHandler">
- <h2>Imports</h2>
- <table summary="A list of imported XML Schema" class="ImportTable">
- <tbody>
- <xslt:for-each select="xsd:import">
- <tr>
- <td>
- <xslt:value-of select="@namespace"/>
- </td>
- <td>
- <div class="Extern">
- <div class="ExternHref">
- <xslt:element name="a">
- <xslt:attribute name="href"><xslt:value-of select="@schemaLocation"/></xslt:attribute>
- <xslt:attribute name="title">Visit <xslt:value-of select="@schemaLocation"/></xslt:attribute>
- <xslt:value-of select="@schemaLocation"/>
- </xslt:element>
- </div>
- <div class="ExternDoc">
- <xslt:apply-templates select="xsd:annotation/xsd:documentation/*" mode="Docs"/>
- </div>
- </div>
- </td>
- </tr>
- </xslt:for-each>
- </tbody>
- </table>
- </xslt:template>
-
- <xslt:template name="IncludeHandler">
- <h2>Includes</h2>
- <table summary="A list of included XML Schema">
- <tbody>
- <xslt:for-each select="xsd:include">
- <tr>
- <td>
- <div class="Extern">
- <div class="ExternHref">
- <xslt:element name="a">
- <xslt:attribute name="href"><xslt:value-of select="@schemaLocation"/></xslt:attribute>
- <xslt:attribute name="title">Visit <xslt:value-of select="@schemaLocation"/></xslt:attribute>
- <xslt:value-of select="@schemaLocation"/>
- </xslt:element>
- </div>
- <div class="ExternDoc">
- <xslt:apply-templates select="xsd:annotation/xsd:documentation/*" mode="Docs"/>
- </div>
- </div>
- </td>
- </tr>
- </xslt:for-each>
- </tbody>
- </table>
- </xslt:template>
-
- <xslt:template name="ElementHandler">
- <h2>Elements</h2>
- <xslt:for-each select="xsd:element">
- <xslt:call-template name="NamedElement">
- <xslt:with-param name="anchorPrefix" select="$elementPrefix" />
- </xslt:call-template>
- <xslt:if test="xsd:annotation/xsd:appinfo/xsdxt:samples">
- <xslt:apply-templates select="xsd:annotation/xsd:appinfo/xsdxt:samples" mode="Docs" />
- </xslt:if>
- </xslt:for-each>
- </xslt:template>
-
- <xslt:template name="SampleHandler" match="xsdxt:samples" mode="Docs">
- <xslt:variable name="sampleID" select="generate-id(.)"/>
- <xslt:if test="xsdxt:description">
- <xslt:apply-templates select="xsdxt:description/*" mode="Docs" />
- </xslt:if>
- <form action="">
- <div class="SampleControl">
- <xslt:element name="select">
- <xslt:attribute name="onchange">
- <xslt:text>trc.schema.sampleManager.showSample(</xslt:text>
- <xslt:call-template name="StringToJavascript">
- <xslt:with-param name="inString" select="$sampleID"/>
- </xslt:call-template>
- <xslt:text>);</xslt:text>
- </xslt:attribute>
- <xslt:attribute name="id">
- <xslt:value-of select="$sampleID"/>
- </xslt:attribute>
- <xslt:for-each select="xsdxt:sample">
- <xslt:element name="option">
- <xslt:attribute name="value">
- <xslt:value-of select="generate-id(.)"/>
- </xslt:attribute>
- <xslt:choose>
- <xslt:when test="@title">
- <xslt:value-of select="@title"/>
- </xslt:when>
- <xslt:otherwise>
- <xslt:value-of select="./xsdxt:code/@type"/>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:element>
- </xslt:for-each>
- </xslt:element>
- </div>
- </form>
- <xslt:for-each select="xsdxt:sample">
- <xslt:element name="div">
- <xslt:attribute name="id"><xslt:value-of select="generate-id(.)"/></xslt:attribute>
- <xslt:attribute name="class">Sample</xslt:attribute>
- <div class="SampleDesc">
- <xslt:apply-templates select="xsdxt:description/*" mode="Docs"/>
- </div>
- <xslt:apply-templates select="xsdxt:code" mode="Docs"/>
- </xslt:element>
- </xslt:for-each>
- </xslt:template>
-
- <!--
- Documentation templates, copy everything but process the
- xsdxt:code tag.
- -->
- <xslt:template match="xsdxt:code" mode="Docs">
- <div class="SampleCode">
- <xslt:element name="pre">
- <xslt:attribute name="id">
- <xslt:value-of select="generate-id(.)"/>
- </xslt:attribute>
- <xslt:choose>
- <xslt:when test="@href">
- <xslt:text>Loading...</xslt:text>
- </xslt:when>
- <xslt:otherwise>
- <xslt:value-of select="."/>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:element>
- </div>
- </xslt:template>
-
- <xslt:template match="*" mode="Docs">
- <xslt:copy-of select="." />
- </xslt:template>
-
- <xslt:template name="ComplexTypeHandler">
- <h2>Complex Types</h2>
- <xslt:for-each select="xsd:complexType">
- <xslt:call-template name="NamedElement">
- <xslt:with-param name="anchorPrefix" select="$typePrefix" />
- </xslt:call-template>
- <xslt:apply-templates />
- </xslt:for-each>
- </xslt:template>
-
- <xslt:template name="SimpleTypeHandler">
- <h2>Simple Types</h2>
- <xslt:for-each select="xsd:simpleType">
- <xslt:call-template name="NamedElement">
- <xslt:with-param name="anchorPrefix" select="$typePrefix" />
- </xslt:call-template>
- <xslt:apply-templates />
- </xslt:for-each>
- </xslt:template>
-
- <xslt:template name="NamedElementLink">
- <xslt:param name="anchorPrefix" />
- <xslt:call-template name="Anchor">
- <xslt:with-param name="href">
- <xslt:text>#</xslt:text>
- <xslt:value-of select="$anchorPrefix"/>
- <xslt:value-of select="@name"/>
- </xslt:with-param>
- <xslt:with-param name="content">
- <xslt:call-template name="StringToName" />
- </xslt:with-param>
- </xslt:call-template>
- </xslt:template>
-
- <xslt:template name="NamedElement">
- <xslt:param name="anchorPrefix" />
- <xslt:element name="a">
- <xslt:attribute name="id"><xslt:value-of select="$anchorPrefix"/><xslt:value-of select="@name"/></xslt:attribute>
- <!--
- Placing a comment here causes the anchor tag to be closed
- correctly in IE 8.
- -->
- <xslt:comment>
- <xslt:value-of select="@name"/>
- </xslt:comment>
- </xslt:element>
- <h3>
- <xslt:call-template name="StringToName" />
- </h3>
-
- <xslt:choose>
- <!-- look for extensions and restrictions in type names -->
- <xslt:when test="$anchorPrefix = $typePrefix">
- <xslt:if test=".//xsd:extension">
- <div class="NameAddl">
- <xslt:text> extends: </xslt:text>
- <xslt:for-each select=".//xsd:extension">
- <xslt:apply-templates select="@base" mode="QNameToLink" />
- <xslt:if test=".//xsd:extension[count(.//xsd:extension)]/@base != @base">
- <xslt:text>,</xslt:text>
- </xslt:if>
- </xslt:for-each>
- </div>
- </xslt:if>
- <xslt:if test=".//xsd:restriction">
- <div class="NameAddl">
- <xslt:text> restricts: </xslt:text>
- <xslt:for-each select=".//xsd:restriction">
- <xslt:apply-templates select="@base" mode="QNameToLink" />
- <xslt:if test=".//xsd:restriction[count(.//xsd:restriction)]/@base != @base">
- <xslt:text>,</xslt:text>
- </xslt:if>
- </xslt:for-each>
- </div>
- </xslt:if>
- </xslt:when>
- </xslt:choose>
-
- <xslt:call-template name="AttribsAndDocs" />
-
- </xslt:template>
-
- <!-- Display all attributes besides @name -->
- <xslt:template name="Attribs">
- <xslt:param name="isSubItem" select="false()"/>
- <xslt:if test="(count(@*) > 1) or ((count(@*) = 1) and not(@name))">
- <xslt:element name="div">
- <xslt:attribute name="class">
- <xslt:choose>
- <xslt:when test="$isSubItem = true()">
- <xslt:text>SubAttributes</xslt:text>
- </xslt:when>
- <xslt:otherwise>
- <xslt:text>Attributes</xslt:text>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:attribute>
- <table summary="Attributes">
- <tbody>
- <xslt:for-each select="@*">
- <xslt:sort select="local-name(.)"/>
- <xslt:if test="local-name(.) != 'name'">
- <tr>
- <td><xslt:value-of select="local-name(.)"/></td>
- <td><xslt:call-template name="QNameToLink"/></td>
- </tr>
- </xslt:if>
- </xslt:for-each>
- </tbody>
- </table>
- </xslt:element>
- </xslt:if>
- </xslt:template>
-
- <xslt:template name="Docs">
- <xslt:param name="isSubItem" select="false()"/>
- <!--
- Copy element-level documentation
- -->
- <xslt:if test="xsd:annotation/xsd:documentation">
- <xslt:element name="div">
- <xslt:attribute name="class">
- <xslt:choose>
- <xslt:when test="$isSubItem = true()">
- <xslt:text>SubDocumentation</xslt:text>
- </xslt:when>
- <xslt:otherwise>
- <xslt:text>Documentation</xslt:text>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:attribute>
- <xslt:apply-templates select="xsd:annotation/xsd:documentation/*" mode="Docs"/>
- </xslt:element>
- </xslt:if>
- </xslt:template>
-
- <xslt:template name="AttribsAndDocs">
- <xslt:param name="isSubItem" select="false()"/>
- <xslt:call-template name="Attribs">
- <xslt:with-param name="isSubItem" select="$isSubItem"/>
- </xslt:call-template>
- <xslt:call-template name="Docs">
- <xslt:with-param name="isSubItem" select="$isSubItem"/>
- </xslt:call-template>
- </xslt:template>
-
- <!--
- Convert a qname to a link.
- -->
- <xslt:template name="QNameToLink" match="@*" mode="QNameToLink">
- <xslt:param name="qname" select="normalize-space(.)"/>
- <xslt:choose>
- <xslt:when test="contains($qname,':')">
- <xslt:variable name="prefix" select="substring-before($qname,':')"/>
- <xslt:variable name="localName" select="substring-after($qname,':')"/>
- <xslt:choose>
- <xslt:when test="//xsdxt:link[(@qname = $qname) and (@rel = 'schema')]">
- <xslt:call-template name="Anchor">
- <xslt:with-param name="href" select="//xsdxt:link[(@qname = $qname) and (@rel = 'schema')]/@href"/>
- <xslt:with-param name="title" select="concat('See ',$localName)"/>
- </xslt:call-template>
- </xslt:when>
- <xslt:when test="$prefix = $targetPrefix">
- <xslt:call-template name="Anchor">
- <xslt:with-param name="href"><xslt:call-template name="QNameToLocalAnchor"/></xslt:with-param>
- <xslt:with-param name="title" select="concat('See ',$localName)"/>
- </xslt:call-template>
- </xslt:when>
- <xslt:when test="$prefix = $schemaPrefix">
- <xslt:call-template name="Anchor">
- <xslt:with-param name="href"><xslt:call-template name="QNameToXSDAnchor"/></xslt:with-param>
- <xslt:with-param name="title" select="concat('See ',$localName)"/>
- </xslt:call-template>
- </xslt:when>
- <xslt:otherwise>
- <xslt:call-template name="Anchor">
- <xslt:with-param name="href"><xslt:call-template name="QNameToForeignAnchor"/></xslt:with-param>
- <xslt:with-param name="title" select="concat('See ',$localName)"/>
- </xslt:call-template>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:when>
- <xslt:otherwise>
- <xslt:value-of select="."/>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:template>
-
- <!-- Write an anchor if it's defined for the current node -->
- <xslt:template name="Anchor">
- <xslt:param name="href" /> <!-- if empty don't make an anchor -->
- <xslt:param name="title">
- <xslt:if test="@name">
- <xslt:value-of select="concat('See ',@name)"/>
- </xslt:if>
- </xslt:param>
- <xslt:param name="content" select="."/>
- <xslt:choose>
- <xslt:when test="string-length($href) != 0">
- <xslt:element name="a">
- <xslt:attribute name="href"><xslt:value-of select="$href"/></xslt:attribute>
- <xslt:attribute name="title"><xslt:value-of select="$title"/></xslt:attribute>
- <xslt:value-of select="$content"/>
- </xslt:element>
- </xslt:when>
- <xslt:otherwise><xslt:value-of select="."/></xslt:otherwise>
- </xslt:choose>
- </xslt:template>
-
- <!--
- Given a quname attribute pointing to a forign XSD type return a
- link if a single import statement exists with a schemaLocation
- attribute
- -->
- <xslt:template name="QNameToForeignAnchor">
- <xslt:param name="qname" select="normalize-space(.)"/>
- <xslt:param name="localName" select="substring-after($qname, ':')"/>
- <xslt:param name="prefix" select="substring-before($qname, ':')"/>
- <xslt:if test="namespace-uri(..) = $schemaNamespace">
- <xslt:variable name="namespace">
- <xslt:for-each select="/xsd:schema/namespace::node()">
- <xslt:if test="name(.)=$prefix">
- <xslt:value-of select="."/>
- </xslt:if>
- </xslt:for-each>
- </xslt:variable>
- <xslt:if test="(string-length($namespace) > 0) and
- (count(/xsd:schema/xsd:import[@namespace = $namespace]) = 1) and
- /xsd:schema/xsd:import[@namespace = $namespace]/@schemaLocation
- ">
- <xslt:value-of select="/xsd:schema/xsd:import[@namespace = $namespace]/@schemaLocation"/>
- </xslt:if>
- </xslt:if>
- </xslt:template>
-
- <!--
- Given a qname attribute pointing to an XSD type, returns an anchor
- to the XSD definition. This only works for type references.
- -->
- <xslt:template name="QNameToXSDAnchor">
- <xslt:param name="qname" select="normalize-space(.)"/>
- <xslt:param name="localName" select="substring-after($qname, ':')"/>
- <xslt:if test="namespace-uri(..) = $schemaNamespace">
- <xslt:if test="(local-name(.) = 'type') or (local-name(.) = 'base')">
- <xslt:value-of select="concat($schemaDatatypeURI,$localName)" />
- </xslt:if>
- </xslt:if>
- </xslt:template>
-
- <!--
- Given a qname attribute, returns an anchor target for that qname,
- or an empty string if an anchor cannot be generated for whatever
- reason.
- -->
- <xslt:template name="QNameToLocalAnchor">
- <xslt:param name="qname" select="normalize-space(.)"/>
- <xslt:param name="localName" select="substring-after($qname, ':')"/>
- <xslt:if test="namespace-uri(..) = $schemaNamespace">
- <xslt:choose>
- <xslt:when test="(local-name(.) = 'type') or
- (local-name(.) = 'base') or
- (local-name(.) = 'itemType')"><xslt:call-template name="LocalTypeAnchor"><xslt:with-param name="localName" select="$localName"/>
- </xslt:call-template></xslt:when>
- <xslt:when test="local-name(.) = 'ref'"><xslt:call-template name="LocalRefAnchor"><xslt:with-param name="localName" select="$localName"/>
- </xslt:call-template></xslt:when>
- </xslt:choose>
- </xslt:if>
- </xslt:template>
-
- <xslt:template name="LocalRefAnchor">
- <xslt:param name="localName" />
- <xslt:choose>
- <!-- Element Reference -->
- <xslt:when test="local-name(..) = 'element'">
- <xslt:call-template name="LocalRefAnchorBuilder">
- <xslt:with-param name="localName" select="$localName"/>
- <xslt:with-param name="search" select="/xsd:schema/xsd:element[@name= $localName]"/>
- <xslt:with-param name="refPrefix" select="$elementPrefix"/>
- </xslt:call-template>
- </xslt:when>
- <!-- Attribute Reference -->
- <xslt:when test="local-name(..) = 'attribute'">
- <xslt:call-template name="LocalRefAnchorBuilder">
- <xslt:with-param name="localName" select="$localName"/>
- <xslt:with-param name="search" select="/xsd:schema/xsd:attribute[@name= $localName]"/>
- <xslt:with-param name="refPrefix" select="$attributePrefix"/>
- </xslt:call-template>
- </xslt:when>
- <!-- Attribute Group Reference -->
- <xslt:when test="local-name(..) = 'attributeGroup'">
- <xslt:call-template name="LocalRefAnchorBuilder">
- <xslt:with-param name="localName" select="$localName"/>
- <xslt:with-param name="search" select="/xsd:schema/xsd:attributeGroup[@name= $localName]"/>
- <xslt:with-param name="refPrefix" select="$attributeGroupPrefix"/>
- </xslt:call-template>
- </xslt:when>
- <!-- Group Reference -->
- <xslt:when test="local-name(..) = 'group'">
- <xslt:call-template name="LocalRefAnchorBuilder">
- <xslt:with-param name="localName" select="$localName"/>
- <xslt:with-param name="search" select="/xsd:schema/xsd:group[@name= $localName]"/>
- <xslt:with-param name="refPrefix" select="$groupPrefix"/>
- </xslt:call-template>
- </xslt:when>
- </xslt:choose>
- </xslt:template>
-
- <xslt:template name="LocalRefAnchorBuilder">
- <xslt:param name="localName" />
- <xslt:param name="search" />
- <xslt:param name="refPrefix" />
- <xslt:choose>
- <xslt:when test="$search">
- <xslt:value-of select="concat('#',$refPrefix,$localName)"/>
- </xslt:when>
- <!--
- If we have a single incude then we assume it's
- included...
- -->
- <xslt:when test="count(/xsd:schema/xsd:include) = 1"><xslt:value-of
- select="concat(/xsd:schema/xsd:include/@schemaLocation,'#',$refPrefix,$localName)"/></xslt:when>
- </xslt:choose>
- </xslt:template>
-
- <!--
- Given a local name as a pram, returns a local "type" anchor or an
- empty string if one cannot be generated.
- -->
- <xslt:template name="LocalTypeAnchor">
- <xslt:param name="localName" />
- <xslt:choose>
- <!-- Search the types -->
- <xslt:when
- test="/xsd:schema/xsd:complexType[@name = $localName] or
- /xsd:schema/xsd:simpleType[@name = $localName]"
- ><xslt:value-of select="concat('#',$typePrefix,$localName)"/></xslt:when>
- <!--
- If we haven't hit yet see if we have an include.
- Currently this only works with a single include.
- -->
- <xslt:when
- test="count(/xsd:schema/xsd:include) = 1"><xslt:value-of
- select="concat(/xsd:schema/xsd:include/@schemaLocation,'#',$typePrefix,$localName)"/></xslt:when>
- <!-- Can't tell so send an empty string... -->
- <xslt:otherwise />
- </xslt:choose>
- </xslt:template>
-
- <!-- Internal sequences -->
- <xslt:template match="xsd:sequence">
- <div class="Sequence">
- <span class="h4">Sequence</span>
- <xslt:call-template name="AttribsAndDocs" />
- <xslt:apply-templates />
- </div>
- </xslt:template>
-
- <xslt:template name="SubItem">
- <xslt:param name="name" />
- <div class="SubItem">
- <div class="SubItemProps">
- <div class="SubName">
- <xslt:value-of select="$name"/>
- </div>
- <xslt:call-template name="Attribs">
- <xslt:with-param name="isSubItem" select="true()"/>
- </xslt:call-template>
- </div>
- <xslt:call-template name="Docs">
- <xslt:with-param name="isSubItem" select="true()"/>
- </xslt:call-template>
- </div>
- </xslt:template>
-
- <xslt:template match="xsd:element">
- <xslt:call-template name="SubItem">
- <xslt:with-param name="name">
- <xslt:choose>
- <xslt:when test="@name">
- <xslt:call-template name="StringToElementName">
- <xslt:with-param name="inString" select="@name"/>
- </xslt:call-template>
- </xslt:when>
- <xslt:when test="@ref">
- <xslt:variable name="elementName" select="substring-after(@ref,':')"/>
- <xslt:call-template name="StringToElementName">
- <xslt:with-param name="inString" select="$elementName"/>
- </xslt:call-template>
- </xslt:when>
- </xslt:choose>
- </xslt:with-param>
- </xslt:call-template>
- </xslt:template>
-
- <xslt:template match="xsd:any">
- <xslt:call-template name="SubItem">
- <xslt:with-param name="name">
- <xslt:text>&lt;?&gt; (Any Element)</xslt:text>
- </xslt:with-param>
- </xslt:call-template>
- </xslt:template>
-
- <xslt:template match="xsd:anyAttribute">
- <xslt:call-template name="SubItem">
- <xslt:with-param name="name">
- <xslt:text>@? (Any Attribute)</xslt:text>
- </xslt:with-param>
- </xslt:call-template>
- </xslt:template>
-
- <xslt:template match="xsd:restriction">
- <div class="SubName">
- <xslt:text>restriction</xslt:text>
- </div>
- <table summary="Restriction Props and Attributes">
- <tbody>
- <xslt:for-each select="@*">
- <xslt:sort select="local-name(.)"/>
- <xslt:if test="local-name(.) != 'name'">
- <tr>
- <td><xslt:value-of select="local-name(.)"/></td>
- <td><xslt:call-template name="QNameToLink"/></td>
- </tr>
- </xslt:if>
- </xslt:for-each>
-
- <!-- simple restrictions -->
- <xslt:for-each select="xsd:minExclusive | xsd:minInclusive |
- xsd:maxExclusive | xsd:maxInclusive |
- xsd:totalDigits | xsd:fractionDigits |
- xsd:length | xsd:minLength |
- xsd:maxLength | xsd:minLength |
- xsd:whitespace | xsd:pattern
- ">
- <tr>
- <td><xslt:value-of select="local-name(.)"/></td>
- <xslt:call-template name="DisplaySimpleRestriction"/>
- </tr>
- </xslt:for-each>
-
- <xslt:if test="xsd:enumeration">
- <tr>
- <td>enum values</td>
- <xslt:call-template name="DisplayEnumeration">
- <xslt:with-param name="enum" select="xsd:enumeration[1]"/>
- </xslt:call-template>
- </tr>
- <xslt:for-each select="xsd:enumeration">
- <xslt:if test="@value != ../xsd:enumeration[1]/@value">
- <tr>
- <td></td>
- <xslt:call-template name="DisplayEnumeration"/>
- </tr>
- </xslt:if>
- </xslt:for-each>
- </xslt:if>
- </tbody>
- </table>
-
- <!--
- Copy restriction docs documentation...
- -->
- <xslt:if test="xsd:annotation/xsd:documentation">
- <xslt:apply-templates select="xsd:annotation/xsd:documentation/*" mode="Docs"/>
- </xslt:if>
-
- <!--
- Apply templates for unhandled children
- -->
- <xslt:apply-templates select="xsd:simpleType | xsd:group |
- xsd:all | xsd:choice |
- xsd:sequence | xsd:attribute |
- xsd:attributeGroup | xsd:anyAttribute" />
- </xslt:template>
-
- <!--
- Displays an enumeration in a table...
- -->
- <xslt:template name="DisplayEnumeration">
- <xslt:param name="enum" select="." />
- <td>
- <div class="Enum">
- <div class="EnumValue">
- <xslt:value-of select="$enum/@value"/>
- <xslt:if test="$enum/@id">
- <xslt:text> (id = </xslt:text>
- <xslt:value-of select="$enum/@id"/>
- <xslt:text>)</xslt:text>
- </xslt:if>
- </div>
- <xslt:if test="$enum/xsd:annotation/xsd:documentation">
- <div class="EnumDoc">
- <xslt:apply-templates select="$enum/xsd:annotation/xsd:documentation/*" mode="Docs"/>
- </div>
- </xslt:if>
- </div>
- </td>
- </xslt:template>
-
- <!--
- A Simple restriction in a table fragment.
- -->
- <xslt:template name="DisplaySimpleRestriction">
- <xslt:param name="restriction" select="." />
- <td>
- <xslt:value-of select="$restriction/@value"/>
- <xslt:if test="$restriction/@id">
- <xslt:text> (id = </xslt:text>
- <xslt:value-of select="$restriction/@id"/>
- <xslt:text>)</xslt:text>
- </xslt:if>
- <xslt:if test="$restriction/@fixed = 'true'">
- <xslt:text> (fixed)</xslt:text>
- </xslt:if>
- </td>
- <xslt:if test="$restriction/xsd:annotation/xsd:documentation">
- <td>
- <xslt:apply-templates select="$restriction/xsd:annotation/xsd:documentation/*" mode="Docs"/>
- </td>
- </xslt:if>
- </xslt:template>
-
- <!-- Catch all for the missed elements -->
- <xslt:template match="xsd:*">
- <xslt:if test="local-name(.) != 'annotation'">
- <div class="SubElementName">
- <xslt:value-of select="local-name(.)"/>
- </div>
- <xslt:call-template name="AttribsAndDocs" />
- <div class="SubElementContent">
- <xslt:apply-templates />
- </div>
- </xslt:if>
- </xslt:template>
-
- <xslt:template match="xsd:attribute">
- <xslt:call-template name="SubItem">
- <xslt:with-param name="name">
- <xslt:choose>
- <xslt:when test="@name">
- <xslt:call-template name="StringToAttributeName">
- <xslt:with-param name="inString" select="@name"/>
- </xslt:call-template>
- </xslt:when>
- <xslt:when test="@ref">
- <xslt:variable name="attribName" select="substring-after(@ref,':')"/>
- <xslt:call-template name="StringToAttributeName">
- <xslt:with-param name="inString" select="$attribName"/>
- </xslt:call-template>
- </xslt:when>
- </xslt:choose>
- </xslt:with-param>
- </xslt:call-template>
- </xslt:template>
-
- <!-- ignore other text -->
- <xslt:template match="text()" />
-
- <!-- Convert a string to a name -->
- <xslt:template name="StringToName">
- <xslt:param name="inString" select="@name" />
- <xslt:param name="inNode" select="." />
-
- <xslt:choose>
- <!-- element names handled with StringToElementName -->
- <xslt:when test="(local-name($inNode) = 'element') and
- (namespace-uri($inNode) = $schemaNamespace)
- ">
- <xslt:call-template name="StringToElementName">
- <xslt:with-param name="inString" select="$inString"/>
- </xslt:call-template>
- </xslt:when>
-
- <!-- attribute names handled with StringToAttributeName -->
- <xslt:when test="(local-name($inNode) = 'attribute') and
- (namespace-uri($inNode) = $schemaNamespace)
- ">
- <xslt:call-template name="StringToAttributeName">
- <xslt:with-param name="inString" select="$inString"/>
- </xslt:call-template>
- </xslt:when>
-
- <xslt:otherwise>
- <xslt:value-of select="@name"/>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:template>
-
- <!-- Convert a string to an element name -->
- <xslt:template name="StringToElementName">
- <xslt:param name="inString" />
- <xslt:text>&lt;</xslt:text>
- <xslt:value-of select="$inString" />
- <xslt:text>&gt;</xslt:text>
- </xslt:template>
-
- <!-- Convert a string to an attribute name -->
- <xslt:template name="StringToAttributeName">
- <xslt:param name="inString" />
- <xslt:text>@</xslt:text>
- <xslt:value-of select="$inString" />
- </xslt:template>
-
- <!--
- Convert a string parameter to an escapted Javascript string in
- quotes.
- -->
- <xslt:template name="StringToJavascript">
- <xslt:param name="inString" />
- <!-- quote the string -->
- <xslt:variable name="quotedString"
- select="concat($dQuote,translate($inString,$dQuote,$sQuote),$dQuote)"/>
- <!-- replace linefeeds with \n -->
- <xslt:variable name="lfString">
- <xslt:call-template name="ReplaceText">
- <xslt:with-param name="inString" select="$quotedString"/>
- <xslt:with-param name="searchString" select="'&#x0a;'"/>
- <xslt:with-param name="replaceString" select="'\n'"/>
- </xslt:call-template>
- </xslt:variable>
- <!-- replace tabs with 5 spaces -->
- <xslt:variable name="tabString">
- <xslt:call-template name="ReplaceText">
- <xslt:with-param name="inString" select="$lfString"/>
- <xslt:with-param name="searchString" select="'&#x09;'"/>
- <xslt:with-param name="replaceString" select="' '"/>
- </xslt:call-template>
- </xslt:variable>
- <!-- remove carrige returns -->
- <xslt:variable name="crString" select="translate($tabString,'&#x0d;','')"/>
- <!-- replace < with unicode sequence -->
- <xslt:variable name="ltString">
- <xslt:call-template name="ReplaceText">
- <xslt:with-param name="inString" select="$crString"/>
- <xslt:with-param name="searchString" select="'&#x3c;'"/>
- <xslt:with-param name="replaceString" select="'\u003c'"/>
- </xslt:call-template>
- </xslt:variable>
- <!-- replace > with unicode sequence -->
- <xslt:variable name="gtString">
- <xslt:call-template name="ReplaceText">
- <xslt:with-param name="inString" select="$ltString"/>
- <xslt:with-param name="searchString" select="'&#x3e;'"/>
- <xslt:with-param name="replaceString" select="'\u003e'"/>
- </xslt:call-template>
- </xslt:variable>
- <xslt:value-of select="$gtString"/>
- </xslt:template>
-
- <!--
- Simple search and replace
- -->
- <xslt:template name="ReplaceText">
- <xslt:param name="inString" />
- <xslt:param name="searchString"/>
- <xslt:param name="replaceString"/>
-
- <xslt:choose>
- <xslt:when test="$searchString and
- contains($inString, $searchString)">
- <xslt:value-of select="substring-before($inString, $searchString)"/>
- <xslt:value-of select="$replaceString"/>
- <xslt:call-template name="ReplaceText">
- <xslt:with-param name="inString" select="substring-after($inString, $searchString)"/>
- <xslt:with-param name="searchString" select="$searchString"/>
- <xslt:with-param name="replaceString" select="$replaceString"/>
- </xslt:call-template>
- </xslt:when>
- <xslt:otherwise>
- <xslt:value-of select="$inString"/>
- </xslt:otherwise>
- </xslt:choose>
- </xslt:template>
-</xslt:stylesheet>
diff --git a/keystone/content/multiple_choice.json.tpl b/keystone/content/multiple_choice.json.tpl
deleted file mode 100644
index 578502ac..00000000
--- a/keystone/content/multiple_choice.json.tpl
+++ /dev/null
@@ -1,26 +0,0 @@
-{
- "choices": [
- {
- "id": "v{{API_VERSION}}",
- "status": "{{API_VERSION_STATUS}}",
- "links": [
- {
- "rel": "self",
- "href": "{{PROTOCOL}}://{{HOST}}:{{PORT}}/v{{API_VERSION}}{{RESOURCE_PATH}}"
- }
- ],
- "media-types": {
- "values": [
- {
- "base": "application/xml",
- "type": "application/vnd.openstack.identity+xml;version={{API_VERSION}}"
- },
- {
- "base": "application/json",
- "type": "application/vnd.openstack.identity+json;version={{API_VERSION}}"
- }
- ]
- }
- }
- ]
-} \ No newline at end of file
diff --git a/keystone/content/multiple_choice.xml.tpl b/keystone/content/multiple_choice.xml.tpl
deleted file mode 100644
index 9f3b88a4..00000000
--- a/keystone/content/multiple_choice.xml.tpl
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<choices
- xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
- <version id="v{{API_VERSION}}" status="{{API_VERSION_STATUS}}">
- <media-types>
- <media-type
- base="application/xml"
- type="application/vnd.openstack.identity+xml;version={{API_VERSION}}" />
- <media-type
- base="application/json"
- type="application/vnd.openstack.identity+json;version={{API_VERSION}}" />
- </media-types>
- <atom:link rel="self" href="{{PROTOCOL}}://{{HOST}}:{{PORT}}/v{{API_VERSION}}{{RESOURCE_PATH}}" />
- </version>
-</choices> \ No newline at end of file
diff --git a/keystone/content/service/OS-KSEC2-service-devguide.pdf b/keystone/content/service/OS-KSEC2-service-devguide.pdf
deleted file mode 100644
index 7ebf1078..00000000
--- a/keystone/content/service/OS-KSEC2-service-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/service/RAX-KSGRP-service-devguide.pdf b/keystone/content/service/RAX-KSGRP-service-devguide.pdf
deleted file mode 100644
index add0cb28..00000000
--- a/keystone/content/service/RAX-KSGRP-service-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/service/RAX-KSKEY-service-devguide.pdf b/keystone/content/service/RAX-KSKEY-service-devguide.pdf
deleted file mode 100644
index 289ceb48..00000000
--- a/keystone/content/service/RAX-KSKEY-service-devguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/service/extensions.json b/keystone/content/service/extensions.json
deleted file mode 100644
index 7a514fd7..00000000
--- a/keystone/content/service/extensions.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "extensions": {
- "values": []
- }
-}
diff --git a/keystone/content/service/extensions.xml b/keystone/content/service/extensions.xml
deleted file mode 100644
index d63c1b96..00000000
--- a/keystone/content/service/extensions.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<extensions xmlns="http://docs.openstack.org/common/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
-</extensions>
diff --git a/keystone/content/service/identity.wadl b/keystone/content/service/identity.wadl
deleted file mode 100644
index d91a7030..00000000
--- a/keystone/content/service/identity.wadl
+++ /dev/null
@@ -1,182 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!-- (C) 2011 OpenStack LLC., All Rights Reserved -->
-<!--*******************************************************-->
-<!-- Import Common XML Entities -->
-<!-- -->
-<!-- You can resolve the entites with xmllint -->
-<!-- -->
-<!-- xmllint -noent identity.wadl -->
-<!--*******************************************************-->
-<!DOCTYPE application [
- <!ENTITY % common SYSTEM "../common/common.ent">
- %common;
-]>
-
-<application xmlns="http://wadl.dev.java.net/2009/02"
- xmlns:identity="http://docs.openstack.org/identity/api/v2.0"
- xmlns:capi="http://docs.openstack.org/common/api/v1.0"
- xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
- xmlns:xsd="http://www.w3.org/2001/XMLSchema"
- xmlns:html="http://www.w3.org/1999/xhtml"
- xmlns:wadl="http://wadl.dev.java.net/2009/02"
- xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 ../common/xsd/api.xsd
- http://docs.openstack.org/common/api/v1.0 ../common/xsd/api-common.xsd
- http://wadl.dev.java.net/2009/02 http://www.w3.org/Submission/wadl/wadl.xsd
- ">
-
- <grammars>
- <include href="../common/xsd/api.xsd"/>
- <include href="../common/xsd/api-common.xsd"/>
- </grammars>
-
- <!--*******************************************************-->
- <!-- All Resources -->
- <!--*******************************************************-->
-
- <!-- We should use SSL in production -->
- <resources base="http://localhost:5000">
- <resource id="version" type="#VersionDetails" path="v2.0/">
- <resource id="extensions" type="#ExtensionList" path="extensions">
- <resource id="extension" path="{alias}">
- <param name="alias" style="template" type="xsd:string"/>
- <method href="#getExtension"/>
- </resource>
- </resource>
- <resource id="tokens" path="tokens">
- <method href="#authenticate"/>
- </resource>
- <resource id="tenants" path="tenants">
- <method href="#listTenants"/>
- </resource>
- </resource>
- </resources>
-
- <!--***************************************************-->
- <!-- Resource Types -->
- <!--*******************************************************-->
-
- <resource_type id="VersionDetails">
- <method href="#getVersionInfo"/>
- </resource_type>
- <resource_type id="ExtensionList">
- <doc xml:lang="EN" title="Extension List">
- <p xmlns="http://www.w3.org/1999/xhtml">
- A list of supported extensions.
- </p>
- </doc>
- <method href="#listExtensions"/>
- </resource_type>
-
- <!--*******************************************************-->
- <!-- All Methods -->
- <!--*******************************************************-->
-
- <!-- Version -->
-
- <method name="GET" id="getVersionInfo">
- <doc xml:lang="EN" title="Version Details">
- <p xmlns="http://www.w3.org/1999/xhtml">
- Returns detailed information about this specific version of the API.
- </p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:version">
- <param name="location" style="plain" type="xsd:anyURI" required="true" path="/capi:version/atom:link[@rel='self']/@href">
- <link resource_type="#VersionDetails" rel="self"/>
- </param>
- </representation>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Extensions -->
-
- <method name="GET" id="listExtensions">
- <doc xml:lang="EN" title="List Extensions">
- <p xmlns="http://www.w3.org/1999/xhtml">List all available extensions.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:extensions">
- <param name="next" style="plain" type="xsd:anyURI" path="/capi:extensions/atom:link[@rel='next']/@href">
- <link resource_type="#ExtensionList" rel="next"/>
- </param>
- <param name="previous" style="plain" type="xsd:anyURI" path="/capi:extensions/atom:link[@rel='previous']/@href">
- <link resource_type="#ExtensionList" rel="previous"/>
- </param>
- </representation>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
- <method name="GET" id="getExtension">
- <doc xml:lang="EN" title="Get Server Details">
- <p xmlns="http://www.w3.org/1999/xhtml">Get details about a specific extension.</p>
- </doc>
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:extension"/>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Token Operations -->
- <method name="POST" id="authenticate">
- <wadl:doc xml:lang="EN" title="Authenticate"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Client authentication is provided via a ReST interface using the POST method,
- with v2.0/tokens supplied as the path. A payload of credentials must be included
- in the body. See <a href="xsd/credentials.xsd">supported credentials</a>
- </p>
- <p>
- Each ReST request against the Keystone system requires the inclusion of a
- specific authorization token HTTP x-header, defined as X-Auth-Token. Clients obtain
- this token, along with the URL to other service APIs, by first authenticating against the
- Keystone Service and supplying valid credentials.
- </p>
- <p>
- The Keystone Service is a ReSTful web service. It is the entry point to all service APIs.
- To access the Keystone Service, you must know URL of the Keystone service.
- </p>
- </wadl:doc>
- <request>
- <representation mediaType="application/xml" element="identity:auth"/>
- <representation mediaType="application/json"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:access"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:userDisabled"/>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-
- <!-- Tenant Operations -->
-
- <method name="GET" id="listTenants">
- <wadl:doc title="List Tenants" xml:lang="EN"
- xmlns="http://www.w3.org/1999/xhtml">
- <p>
- Returns a list of tenants.
- </p>
- </wadl:doc>
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:tenants"/>
- <representation mediaType="application/json"/>
- </response>
- &commonFaults;
- &getFaults;
- </method>
-</application>
diff --git a/keystone/content/service/identitydevguide.pdf b/keystone/content/service/identitydevguide.pdf
deleted file mode 100644
index 5229e5d4..00000000
--- a/keystone/content/service/identitydevguide.pdf
+++ /dev/null
Binary files differ
diff --git a/keystone/content/service/version.atom.tpl b/keystone/content/service/version.atom.tpl
deleted file mode 100644
index e39250d5..00000000
--- a/keystone/content/service/version.atom.tpl
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<feed xmlns="http://www.w3.org/2005/Atom">
- <title type="text">Available API Versions</title>
- <updated>2010-12-22T00:00:00.00Z</updated>
- <id>http://identity.api.openstack.org/</id>
- <author><name>OpenStack</name><uri>http://www.openstack.org/</uri></author>
- <link rel="self" href="http://identity.api.openstack.org/"/>
- <entry>
- <id>http://identity.api.openstack.org/v2.0/</id>
- <title type="text">Version v2.0</title>
- <updated>2011-09-30T00:00:00.00Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v2.0/"/>
- <content type="text">Version v2.0 BETA (2011-09-30T00:00:00.00Z)</content>
- </entry>
- <entry>
- <id>http://identity.api.openstack.org/v1.1/</id>
- <title type="text">Version v1.1</title>
- <updated>2011-01-21T11:33:21-06:00</updated>
- <link rel="self" href="http://identity.api.openstack.org/v1.1/"/>
- <content type="text">Version v1.1 CURRENT (2011-01-21T11:33:21-06:00)</content>
- </entry>
- <entry>
- <id>http://identity.api.openstack.org/v1.0/</id>
- <title type="text">Version v1.0</title>
- <updated>2009-10-09T11:30:00Z</updated>
- <link rel="self" href="http://identity.api.openstack.org/v1.0/"/>
- <content type="text">Version v1.0 DEPRECATED (2009-10-09T11:30:00Z)</content>
- </entry>
-</feed>
diff --git a/keystone/content/service/version.json.tpl b/keystone/content/service/version.json.tpl
deleted file mode 100644
index 0eb824bf..00000000
--- a/keystone/content/service/version.json.tpl
+++ /dev/null
@@ -1,32 +0,0 @@
-{
- "versions": {
- "values": [{
- "id": "v{{API_VERSION}}",
- "status": "{{API_VERSION_STATUS}}",
- "updated": "{{API_VERSION_DATE}}",
- "links": [{
- "rel": "self",
- "href": "http://{{HOST}}:{{PORT}}/v2.0/"
- }, {
- "rel": "describedby",
- "type": "text/html",
- "href": "http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/content/"
- }, {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/identity-dev-guide-{{API_VERSION}}.pdf"
- }, {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "http://{{HOST}}:{{PORT}}/v2.0/identity.wadl"
- }],
- "media-types": [{
- "base": "application/xml",
- "type": "application/vnd.openstack.identity-v2.0+xml"
- }, {
- "base": "application/json",
- "type": "application/vnd.openstack.identity-v2.0+json"
- }]
- }]
- }
-} \ No newline at end of file
diff --git a/keystone/content/service/version.xml.tpl b/keystone/content/service/version.xml.tpl
deleted file mode 100644
index 30a46489..00000000
--- a/keystone/content/service/version.xml.tpl
+++ /dev/null
@@ -1,29 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<versions xmlns="http://docs.openstack.org/common/api/v2.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
-
- <version id="v{{API_VERSION}}" status="{{API_VERSION_STATUS}}" updated="{{API_VERSION_DATE}}">
-
- <media-types>
- <media-type base="application/xml"
- type="application/vnd.openstack.identity-v{{API_VERSION}}+xml"/>
- <media-type base="application/json"
- type="application/vnd.openstack.identity-v{{API_VERSION}}+json"/>
- </media-types>
-
- <atom:link rel="self"
- href="http://{{HOST}}:{{PORT}}/v{{API_VERSION}}/"/>
-
- <atom:link rel="describedby"
- type="text/html"
- href="http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/content/" />
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="http://docs.openstack.org/api/openstack-identity-service/{{API_VERSION}}/identity-dev-guide-{{API_VERSION}}.pdf" />
-
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="http://{{HOST}}:{{PORT}}/v2.0/identity.wadl" />
- </version>
-</versions> \ No newline at end of file
diff --git a/keystone/contrib/admin_crud/__init__.py b/keystone/contrib/admin_crud/__init__.py
new file mode 100644
index 00000000..eb8c4f17
--- /dev/null
+++ b/keystone/contrib/admin_crud/__init__.py
@@ -0,0 +1 @@
+from keystone.contrib.admin_crud.core import *
diff --git a/keystone/contrib/admin_crud/core.py b/keystone/contrib/admin_crud/core.py
new file mode 100644
index 00000000..15a597ed
--- /dev/null
+++ b/keystone/contrib/admin_crud/core.py
@@ -0,0 +1,150 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from keystone import catalog
+from keystone import identity
+from keystone.common import wsgi
+
+
+class CrudExtension(wsgi.ExtensionRouter):
+ """Previously known as the OS-KSADM extension.
+
+ Provides a bunch of CRUD operations for internal data types.
+
+ """
+
+ def add_routes(self, mapper):
+ tenant_controller = identity.TenantController()
+ user_controller = identity.UserController()
+ role_controller = identity.RoleController()
+ service_controller = catalog.ServiceController()
+
+ # Tenant Operations
+ mapper.connect('/tenants', controller=tenant_controller,
+ action='create_tenant',
+ conditions=dict(method=['POST']))
+ mapper.connect('/tenants/{tenant_id}',
+ controller=tenant_controller,
+ action='update_tenant',
+ conditions=dict(method=['PUT', 'POST']))
+ mapper.connect('/tenants/{tenant_id}',
+ controller=tenant_controller,
+ action='delete_tenant',
+ conditions=dict(method=['DELETE']))
+ mapper.connect('/tenants/{tenant_id}/users',
+ controller=user_controller,
+ action='get_tenant_users',
+ conditions=dict(method=['GET']))
+
+ # User Operations
+ mapper.connect('/users',
+ controller=user_controller,
+ action='get_users',
+ conditions=dict(method=['GET']))
+ mapper.connect('/users',
+ controller=user_controller,
+ action='create_user',
+ conditions=dict(method=['POST']))
+ # NOTE(termie): not in diablo
+ mapper.connect('/users/{user_id}',
+ controller=user_controller,
+ action='update_user',
+ conditions=dict(method=['PUT']))
+ mapper.connect('/users/{user_id}',
+ controller=user_controller,
+ action='delete_user',
+ conditions=dict(method=['DELETE']))
+
+ # COMPAT(diablo): the copy with no OS-KSADM is from diablo
+ mapper.connect('/users/{user_id}/password',
+ controller=user_controller,
+ action='set_user_password',
+ conditions=dict(method=['PUT']))
+ mapper.connect('/users/{user_id}/OS-KSADM/password',
+ controller=user_controller,
+ action='set_user_password',
+ conditions=dict(method=['PUT']))
+
+ # COMPAT(diablo): the copy with no OS-KSADM is from diablo
+ mapper.connect('/users/{user_id}/tenant',
+ controller=user_controller,
+ action='update_user_tenant',
+ conditions=dict(method=['PUT']))
+ mapper.connect('/users/{user_id}/OS-KSADM/tenant',
+ controller=user_controller,
+ action='update_user_tenant',
+ conditions=dict(method=['PUT']))
+
+ # COMPAT(diablo): the copy with no OS-KSADM is from diablo
+ mapper.connect('/users/{user_id}/enabled',
+ controller=user_controller,
+ action='set_user_enabled',
+ conditions=dict(method=['PUT']))
+ mapper.connect('/users/{user_id}/OS-KSADM/enabled',
+ controller=user_controller,
+ action='set_user_enabled',
+ conditions=dict(method=['PUT']))
+
+ # User Roles
+ mapper.connect('/users/{user_id}/roles/OS-KSADM/{role_id}',
+ controller=role_controller, action='add_role_to_user',
+ conditions=dict(method=['PUT']))
+ mapper.connect('/users/{user_id}/roles/OS-KSADM/{role_id}',
+ controller=role_controller, action='delete_role_from_user',
+ conditions=dict(method=['DELETE']))
+
+ # COMPAT(diablo): User Roles
+ mapper.connect('/users/{user_id}/roleRefs',
+ controller=role_controller, action='get_role_refs',
+ conditions=dict(method=['GET']))
+ mapper.connect('/users/{user_id}/roleRefs',
+ controller=role_controller, action='create_role_ref',
+ conditions=dict(method=['POST']))
+ mapper.connect('/users/{user_id}/roleRefs/{role_ref_id}',
+ controller=role_controller, action='delete_role_ref',
+ conditions=dict(method=['DELETE']))
+
+ # User-Tenant Roles
+ mapper.connect(
+ '/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}',
+ controller=role_controller, action='add_role_to_user',
+ conditions=dict(method=['PUT']))
+ mapper.connect(
+ '/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}',
+ controller=role_controller, action='remove_role_from_user',
+ conditions=dict(method=['DELETE']))
+
+ # Service Operations
+ mapper.connect('/OS-KSADM/services',
+ controller=service_controller,
+ action='get_services',
+ conditions=dict(method=['GET']))
+ mapper.connect('/OS-KSADM/services',
+ controller=service_controller,
+ action='create_service',
+ conditions=dict(method=['POST']))
+ mapper.connect('/OS-KSADM/services/{service_id}',
+ controller=service_controller,
+ action='delete_service',
+ conditions=dict(method=['DELETE']))
+ mapper.connect('/OS-KSADM/services/{service_id}',
+ controller=service_controller,
+ action='get_service',
+ conditions=dict(method=['GET']))
+
+ # Role Operations
+ mapper.connect('/OS-KSADM/roles',
+ controller=role_controller,
+ action='create_role',
+ conditions=dict(method=['POST']))
+ mapper.connect('/OS-KSADM/roles',
+ controller=role_controller,
+ action='get_roles',
+ conditions=dict(method=['GET']))
+ mapper.connect('/OS-KSADM/roles/{role_id}',
+ controller=role_controller,
+ action='get_role',
+ conditions=dict(method=['GET']))
+ mapper.connect('/OS-KSADM/roles/{role_id}',
+ controller=role_controller,
+ action='delete_role',
+ conditions=dict(method=['DELETE']))
diff --git a/keystone/contrib/ec2/__init__.py b/keystone/contrib/ec2/__init__.py
new file mode 100644
index 00000000..6c85c66d
--- /dev/null
+++ b/keystone/contrib/ec2/__init__.py
@@ -0,0 +1 @@
+from keystone.contrib.ec2.core import *
diff --git a/keystone/contrib/extensions/admin/osec2/__init__.py b/keystone/contrib/ec2/backends/__init__.py
index e69de29b..e69de29b 100644
--- a/keystone/contrib/extensions/admin/osec2/__init__.py
+++ b/keystone/contrib/ec2/backends/__init__.py
diff --git a/keystone/contrib/ec2/backends/kvs.py b/keystone/contrib/ec2/backends/kvs.py
new file mode 100644
index 00000000..6aa2fe81
--- /dev/null
+++ b/keystone/contrib/ec2/backends/kvs.py
@@ -0,0 +1,31 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from keystone.common import kvs
+
+
+class Ec2(kvs.Base):
+ # Public interface
+ def get_credential(self, credential_id):
+ credential_ref = self.db.get('credential-%s' % credential_id)
+ return credential_ref
+
+ def list_credentials(self, user_id):
+ credential_ids = self.db.get('credential_list', [])
+ rv = [self.get_credential(x) for x in credential_ids]
+ return [x for x in rv if x['user_id'] == user_id]
+
+ # CRUD
+ def create_credential(self, credential_id, credential):
+ self.db.set('credential-%s' % credential_id, credential)
+ credential_list = set(self.db.get('credential_list', []))
+ credential_list.add(credential_id)
+ self.db.set('credential_list', list(credential_list))
+ return credential
+
+ def delete_credential(self, credential_id):
+ old_credential = self.db.get('credential-%s' % credential_id)
+ self.db.delete('credential-%s' % credential_id)
+ credential_list = set(self.db.get('credential_list', []))
+ credential_list.remove(credential_id)
+ self.db.set('credential_list', list(credential_list))
+ return None
diff --git a/keystone/contrib/ec2/backends/sql.py b/keystone/contrib/ec2/backends/sql.py
new file mode 100644
index 00000000..3105660e
--- /dev/null
+++ b/keystone/contrib/ec2/backends/sql.py
@@ -0,0 +1,52 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from keystone.common import sql
+from keystone.common.sql import migration
+
+
+class Ec2Credential(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'ec2_credential'
+ access = sql.Column(sql.String(64), primary_key=True)
+ secret = sql.Column(sql.String(64))
+ user_id = sql.Column(sql.String(64))
+ tenant_id = sql.Column(sql.String(64))
+
+ @classmethod
+ def from_dict(cls, user_dict):
+ return cls(**user_dict)
+
+ def to_dict(self):
+ return dict(self.iteritems())
+
+
+class Ec2(sql.Base):
+ def get_credential(self, credential_id):
+ session = self.get_session()
+ credential_ref = session.query(Ec2Credential)\
+ .filter_by(access=credential_id).first()
+ if not credential_ref:
+ return
+ return credential_ref.to_dict()
+
+ def list_credentials(self, user_id):
+ session = self.get_session()
+ credential_refs = session.query(Ec2Credential)\
+ .filter_by(user_id=user_id)
+ return [x.to_dict() for x in credential_refs]
+
+ # CRUD
+ def create_credential(self, credential_id, credential):
+ session = self.get_session()
+ with session.begin():
+ credential_ref = Ec2Credential.from_dict(credential)
+ session.add(credential_ref)
+ session.flush()
+ return credential_ref.to_dict()
+
+ def delete_credential(self, credential_id):
+ session = self.get_session()
+ credential_ref = session.query(Ec2Credential)\
+ .filter_by(access=credential_id).first()
+ with session.begin():
+ session.delete(credential_ref)
+ session.flush()
diff --git a/keystone/contrib/ec2/core.py b/keystone/contrib/ec2/core.py
new file mode 100644
index 00000000..08a286cc
--- /dev/null
+++ b/keystone/contrib/ec2/core.py
@@ -0,0 +1,288 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Main entry point into the EC2 Credentials service.
+
+This service allows the creation of access/secret credentials used for
+the ec2 interop layer of OpenStack.
+
+A user can create as many access/secret pairs, each of which map to a
+specific tenant. This is required because OpenStack supports a user
+belonging to multiple tenants, whereas the signatures created on ec2-style
+requests don't allow specification of which tenant the user wishs to act
+upon.
+
+To complete the cycle, we provide a method that OpenStack services can
+use to validate a signature and get a corresponding openstack token. This
+token allows method calls to other services within the context the
+access/secret was created. As an example, nova requests keystone to validate
+the signature of a request, receives a token, and then makes a request to
+glance to list images needed to perform the requested task.
+
+"""
+
+import uuid
+
+import webob.exc
+
+from keystone import catalog
+from keystone import config
+from keystone import exception
+from keystone import identity
+from keystone import policy
+from keystone import service
+from keystone import token
+from keystone.common import manager
+from keystone.common import utils
+from keystone.common import wsgi
+
+
+CONF = config.CONF
+
+
+class Manager(manager.Manager):
+ """Default pivot point for the EC2 Credentials backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.ec2.driver)
+
+
+class Ec2Extension(wsgi.ExtensionRouter):
+ def add_routes(self, mapper):
+ ec2_controller = Ec2Controller()
+ # validation
+ mapper.connect('/ec2tokens',
+ controller=ec2_controller,
+ action='authenticate',
+ conditions=dict(method=['POST']))
+
+ # crud
+ mapper.connect('/users/{user_id}/credentials/OS-EC2',
+ controller=ec2_controller,
+ action='create_credential',
+ conditions=dict(method=['POST']))
+ mapper.connect('/users/{user_id}/credentials/OS-EC2',
+ controller=ec2_controller,
+ action='get_credentials',
+ conditions=dict(method=['GET']))
+ mapper.connect('/users/{user_id}/credentials/OS-EC2/{credential_id}',
+ controller=ec2_controller,
+ action='get_credential',
+ conditions=dict(method=['GET']))
+ mapper.connect('/users/{user_id}/credentials/OS-EC2/{credential_id}',
+ controller=ec2_controller,
+ action='delete_credential',
+ conditions=dict(method=['DELETE']))
+
+
+class Ec2Controller(wsgi.Application):
+ def __init__(self):
+ self.catalog_api = catalog.Manager()
+ self.identity_api = identity.Manager()
+ self.token_api = token.Manager()
+ self.policy_api = policy.Manager()
+ self.ec2_api = Manager()
+ super(Ec2Controller, self).__init__()
+
+ def check_signature(self, creds_ref, credentials):
+ signer = utils.Ec2Signer(creds_ref['secret'])
+ signature = signer.generate(credentials)
+ if signature == credentials['signature']:
+ return
+ # NOTE(vish): Some libraries don't use the port when signing
+ # requests, so try again without port.
+ elif ':' in credentials['signature']:
+ hostname, _port = credentials['host'].split(':')
+ credentials['host'] = hostname
+ signature = signer.generate(credentials)
+ if signature != credentials.signature:
+ # TODO(termie): proper exception
+ msg = 'Invalid signature'
+ raise webob.exc.HTTPUnauthorized(explanation=msg)
+ else:
+ msg = 'Signature not supplied'
+ raise webob.exc.HTTPUnauthorized(explanation=msg)
+
+ def authenticate(self, context, credentials=None,
+ ec2Credentials=None):
+ """Validate a signed EC2 request and provide a token.
+
+ Other services (such as Nova) use this **admin** call to determine
+ if a request they signed received is from a valid user.
+
+ If it is a valid signature, an openstack token that maps
+ to the user/tenant is returned to the caller, along with
+ all the other details returned from a normal token validation
+ call.
+
+ The returned token is useful for making calls to other
+ OpenStack services within the context of the request.
+
+ :param context: standard context
+ :param credentials: dict of ec2 signature
+ :param ec2Credentials: DEPRECATED dict of ec2 signature
+ :returns: token: openstack token equivalent to access key along
+ with the corresponding service catalog and roles
+ """
+
+ # FIXME(ja): validate that a service token was used!
+
+ # NOTE(termie): backwards compat hack
+ if not credentials and ec2Credentials:
+ credentials = ec2Credentials
+
+ creds_ref = self.ec2_api.get_credential(context,
+ credentials['access'])
+ if not creds_ref:
+ msg = 'Access key not found'
+ raise webob.exc.HTTPUnauthorized(explanation=msg)
+
+ self.check_signature(creds_ref, credentials)
+
+ # TODO(termie): don't create new tokens every time
+ # TODO(termie): this is copied from TokenController.authenticate
+ token_id = uuid.uuid4().hex
+ tenant_ref = self.identity_api.get_tenant(
+ context=context,
+ tenant_id=creds_ref['tenant_id'])
+ user_ref = self.identity_api.get_user(
+ context=context,
+ user_id=creds_ref['user_id'])
+ metadata_ref = self.identity_api.get_metadata(
+ context=context,
+ user_id=user_ref['id'],
+ tenant_id=tenant_ref['id'])
+ catalog_ref = self.catalog_api.get_catalog(
+ context=context,
+ user_id=user_ref['id'],
+ tenant_id=tenant_ref['id'],
+ metadata=metadata_ref)
+
+ token_ref = self.token_api.create_token(
+ context, token_id, dict(id=token_id,
+ user=user_ref,
+ tenant=tenant_ref,
+ metadata=metadata_ref))
+
+ # TODO(termie): optimize this call at some point and put it into the
+ # the return for metadata
+ # fill out the roles in the metadata
+ roles_ref = []
+ for role_id in metadata_ref.get('roles', []):
+ roles_ref.append(self.identity_api.get_role(context, role_id))
+
+ # TODO(termie): make this a util function or something
+ # TODO(termie): i don't think the ec2 middleware currently expects a
+ # full return, but it contains a note saying that it
+ # would be better to expect a full return
+ token_controller = service.TokenController()
+ return token_controller._format_authenticate(
+ token_ref, roles_ref, catalog_ref)
+
+ def create_credential(self, context, user_id, tenant_id):
+ """Create a secret/access pair for use with ec2 style auth.
+
+ Generates a new set of credentials that map the the user/tenant
+ pair.
+
+ :param context: standard context
+ :param user_id: id of user
+ :param tenant_id: id of tenant
+ :returns: credential: dict of ec2 credential
+ """
+ if not self._is_admin(context):
+ self._assert_identity(context, user_id)
+ cred_ref = {'user_id': user_id,
+ 'tenant_id': tenant_id,
+ 'access': uuid.uuid4().hex,
+ 'secret': uuid.uuid4().hex}
+ self.ec2_api.create_credential(context, cred_ref['access'], cred_ref)
+ return {'credential': cred_ref}
+
+ def get_credentials(self, context, user_id):
+ """List all credentials for a user.
+
+ :param context: standard context
+ :param user_id: id of user
+ :returns: credentials: list of ec2 credential dicts
+ """
+ if not self._is_admin(context):
+ self._assert_identity(context, user_id)
+ return {'credentials': self.ec2_api.list_credentials(context, user_id)}
+
+ def get_credential(self, context, user_id, credential_id):
+ """Retreive a user's access/secret pair by the access key.
+
+ Grab the full access/secret pair for a given access key.
+
+ :param context: standard context
+ :param user_id: id of user
+ :param credential_id: access key for credentials
+ :returns: credential: dict of ec2 credential
+ """
+ if not self._is_admin(context):
+ self._assert_identity(context, user_id)
+ return {'credential': self.ec2_api.get_credential(context,
+ credential_id)}
+
+ def delete_credential(self, context, user_id, credential_id):
+ """Delete a user's access/secret pair.
+
+ Used to revoke a user's access/secret pair
+
+ :param context: standard context
+ :param user_id: id of user
+ :param credential_id: access key for credentials
+ :returns: bool: success
+ """
+ if not self._is_admin(context):
+ self._assert_identity(context, user_id)
+ self._assert_owner(context, user_id, credential_id)
+ return self.ec2_api.delete_credential(context, credential_id)
+
+ def _assert_identity(self, context, user_id):
+ """Check that the provided token belongs to the user.
+
+ :param context: standard context
+ :param user_id: id of user
+ :raises webob.exc.HTTPForbidden: when token is invalid
+
+ """
+ try:
+ token_ref = self.token_api.get_token(context=context,
+ token_id=context['token_id'])
+ except exception.TokenNotFound:
+ raise exception.Unauthorized()
+ token_user_id = token_ref['user'].get('id')
+ if not token_user_id == user_id:
+ raise webob.exc.HTTPForbidden()
+
+ def _is_admin(self, context):
+ """Wrap admin assertion error return statement.
+
+ :param context: standard context
+ :returns: bool: success
+
+ """
+ try:
+ self.assert_admin(context)
+ return True
+ except AssertionError:
+ return False
+
+ def _assert_owner(self, context, user_id, credential_id):
+ """Ensure the provided user owns the credential.
+
+ :param context: standard context
+ :param user_id: expected credential owner
+ :param credential_id: id of credential object
+ :raises webob.exc.HTTPForbidden: on failure
+
+ """
+ cred_ref = self.ec2_api.get_credential(context, credential_id)
+ if not user_id == cred_ref['user_id']:
+ raise webob.exc.HTTPForbidden()
diff --git a/keystone/contrib/extensions/__init__.py b/keystone/contrib/extensions/__init__.py
deleted file mode 100644
index 6d4247ba..00000000
--- a/keystone/contrib/extensions/__init__.py
+++ /dev/null
@@ -1,52 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 logging
-
-from keystone import config
-from keystone import utils
-
-CONF = config.CONF
-EXTENSION_PREFIX = 'keystone.contrib.extensions.'
-DEFAULT_EXTENSIONS = ['osksadm', 'oskscatalog']
-CONFIG_EXTENSION_PROPERTY = 'extensions'
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class BaseExtensionConfigurer(object):
- def configure_extensions(self, extension_type, mapper):
- extensions = CONF[CONFIG_EXTENSION_PROPERTY] or \
- DEFAULT_EXTENSIONS
- extensions = [extension.strip() for extension in extensions]
- for supported_extension in extensions:
- self.extension_handlers = []
- supported_extension = "%s%s.%s" % (
- EXTENSION_PREFIX, extension_type, supported_extension.strip())
- try:
- extension_module = utils.import_module(supported_extension)
- if hasattr(extension_module, 'ExtensionHandler'):
- extension_class = extension_module.ExtensionHandler()
- extension_class.map_extension_methods(mapper)
- self.extension_handlers.append(extension_class)
- except Exception as err:
- logger.exception("Could not load extension for %s:%s %s" %
- (extension_type, supported_extension, err))
-
- def get_extension_handlers(self):
- return self.extension_handlers
diff --git a/keystone/contrib/extensions/admin/__init__.py b/keystone/contrib/extensions/admin/__init__.py
deleted file mode 100644
index 7db667ef..00000000
--- a/keystone/contrib/extensions/admin/__init__.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 ast
-import logging
-from keystone import utils
-from keystone.contrib.extensions import BaseExtensionConfigurer
-ADMIN_CONFIGURER = None
-EXTENSION_ADMIN_PREFIX = 'admin'
-
-
-class AdminExtensionConfigurer(BaseExtensionConfigurer):
- def configure(self, mapper):
- self.configure_extensions(EXTENSION_ADMIN_PREFIX, mapper)
-
-
-def get_extension_configurer():
- global ADMIN_CONFIGURER
- if not ADMIN_CONFIGURER:
- ADMIN_CONFIGURER = AdminExtensionConfigurer()
- return ADMIN_CONFIGURER
diff --git a/keystone/contrib/extensions/admin/extension.py b/keystone/contrib/extensions/admin/extension.py
deleted file mode 100644
index d2ae1525..00000000
--- a/keystone/contrib/extensions/admin/extension.py
+++ /dev/null
@@ -1,20 +0,0 @@
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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
-
-
-class BaseExtensionHandler(object):
- def map_extension_methods(self, mapper):
- raise NotImplementedError
diff --git a/keystone/contrib/extensions/admin/hpidm/__init__.py b/keystone/contrib/extensions/admin/hpidm/__init__.py
deleted file mode 100644
index 451a662a..00000000
--- a/keystone/contrib/extensions/admin/hpidm/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.contrib.extensions.admin.extension import BaseExtensionHandler
-from keystone.controllers.token import TokenController
-
-
-class ExtensionHandler(BaseExtensionHandler):
- def map_extension_methods(self, mapper):
- pass
diff --git a/keystone/contrib/extensions/admin/hpidm/extension.json b/keystone/contrib/extensions/admin/hpidm/extension.json
deleted file mode 100644
index 5804de07..00000000
--- a/keystone/contrib/extensions/admin/hpidm/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "HP Token Validation Extension",
- "namespace": "http://docs.openstack.org/identity/api/ext/HP-IDM/v1.0",
- "alias": "HP-IDM",
- "updated": "2011-12-06T19:00:00-00:00",
- "description": "Validate token with the optional serviceId parameter so that only the roles associated with the given service IDs are returned. See https://bugs.launchpad.net/keystone/+bug/890411 for more details.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/HP-IDM-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://raw.github.com/openstack/keystone/master/keystone/content/admin/HP-IDM-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/hpidm/extension.xml b/keystone/contrib/extensions/admin/hpidm/extension.xml
deleted file mode 100644
index 0482faac..00000000
--- a/keystone/contrib/extensions/admin/hpidm/extension.xml
+++ /dev/null
@@ -1,21 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <extension
- xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="HP Token Validation Extension"
- namespace="http://docs.openstack.org/identity/api/ext/HP-IDM/v1.0"
- alias="HP-IDM"
- updated="2011-12-25T17:00:00-00:00">
-
- <description>
- Validate token with the optional serviceId parameter so that only the roles associated with the given service IDs are returned. See https://bugs.launchpad.net/keystone/+bug/890411 for more details.
- </description>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/HP-IDM-admin-devguide.pdf"/>
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/HP-IDM-admin.wadl"/>
- </extension>
-
diff --git a/keystone/contrib/extensions/admin/osec2/extension.json b/keystone/contrib/extensions/admin/osec2/extension.json
deleted file mode 100644
index 195091b5..00000000
--- a/keystone/contrib/extensions/admin/osec2/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "OpenStack EC2 authentication Extension",
- "namespace": "http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0",
- "alias": "OS-KSEC2",
- "updated": "2011-08-25T09:50:00-00:00",
- "description": "Adds the capability to support EC2 style authentication.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSEC2-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://raw.github.com/openstack/keystone/master/keystone/content/admin/OS-KSEC2-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/osec2/extension.xml b/keystone/contrib/extensions/admin/osec2/extension.xml
deleted file mode 100644
index ea243792..00000000
--- a/keystone/contrib/extensions/admin/osec2/extension.xml
+++ /dev/null
@@ -1,19 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <extension
- name="OpenStack EC2 authentication Extension"
- namespace="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- alias="OS-KSEC2"
- updated="2011-08-25T09:50:00-00:00">
-
- <description>
- Adds the capability to support EC2 style authentication.
- </description>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSEC2-admin-devguide.pdf"/>
- <atom:link rel="describedby"
- type="application/vnd.sun.wadl+xml"
- href="https://raw.github.com/openstack/keystone/master/keystone/content/admin/OS-KSEC2-admin.wadl"/>
- </extension>
-
diff --git a/keystone/contrib/extensions/admin/osksadm/__init__.py b/keystone/contrib/extensions/admin/osksadm/__init__.py
deleted file mode 100644
index c660a7aa..00000000
--- a/keystone/contrib/extensions/admin/osksadm/__init__.py
+++ /dev/null
@@ -1,149 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.contrib.extensions.admin.extension import BaseExtensionHandler
-from keystone.controllers.services import ServicesController
-from keystone.controllers.roles import RolesController
-from keystone.controllers.user import UserController
-from keystone.controllers.tenant import TenantController
-from keystone.controllers.credentials import CredentialsController
-
-
-class ExtensionHandler(BaseExtensionHandler):
- def map_extension_methods(self, mapper):
- tenant_controller = TenantController()
- roles_controller = RolesController()
- user_controller = UserController()
- credentials_controller = CredentialsController()
-
- # Tenant Operations
- mapper.connect("/tenants", controller=tenant_controller,
- action="create_tenant",
- conditions=dict(method=["POST"]))
- mapper.connect("/tenants/{tenant_id}",
- controller=tenant_controller,
- action="update_tenant", conditions=dict(method=["POST"]))
- mapper.connect("/tenants/{tenant_id}",
- controller=tenant_controller,
- action="delete_tenant", conditions=dict(method=["DELETE"]))
- mapper.connect("/tenants/{tenant_id}/users",
- controller=user_controller,
- action="get_tenant_users",
- conditions=dict(method=["GET"]))
-
- #Add/Delete Tenant specific role.
- mapper.connect(
- "/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}",
- controller=roles_controller, action="add_role_to_user",
- conditions=dict(method=["PUT"]))
- mapper.connect(
- "/tenants/{tenant_id}/users/{user_id}/roles/OS-KSADM/{role_id}",
- controller=roles_controller, action="delete_role_from_user",
- conditions=dict(method=["DELETE"]))
- # User Operations
- mapper.connect("/users",
- controller=user_controller,
- action="get_users",
- conditions=dict(method=["GET"]))
- mapper.connect("/users",
- controller=user_controller,
- action="create_user",
- conditions=dict(method=["POST"]))
- mapper.connect("/users/{user_id}",
- controller=user_controller,
- action="update_user",
- conditions=dict(method=["POST"]))
- mapper.connect("/users/{user_id}",
- controller=user_controller,
- action="delete_user",
- conditions=dict(method=["DELETE"]))
- #API doesn't have any of the shorthand updates as of now.
- mapper.connect("/users/{user_id}/OS-KSADM/password",
- controller=user_controller,
- action="set_user_password",
- conditions=dict(method=["PUT"]))
- mapper.connect("/users/{user_id}/OS-KSADM/tenant",
- controller=user_controller,
- action="update_user_tenant",
- conditions=dict(method=["PUT"]))
- # Test this, test failed
- mapper.connect("/users/{user_id}/OS-KSADM/enabled",
- controller=user_controller,
- action="set_user_enabled",
- conditions=dict(method=["PUT"]))
- #User Roles
- #Add/Delete Global role.
- mapper.connect("/users/{user_id}/roles/OS-KSADM/{role_id}",
- controller=roles_controller, action="add_role_to_user",
- conditions=dict(method=["PUT"]))
- mapper.connect("/users/{user_id}/roles/OS-KSADM/{role_id}",
- controller=roles_controller, action="delete_role_from_user",
- conditions=dict(method=["DELETE"]))
-
- # Services Operations
- services_controller = ServicesController()
- mapper.connect("/OS-KSADM/services",
- controller=services_controller,
- action="get_services",
- conditions=dict(method=["GET"]))
- mapper.connect("/OS-KSADM/services",
- controller=services_controller,
- action="create_service",
- conditions=dict(method=["POST"]))
- mapper.connect("/OS-KSADM/services/{service_id}",
- controller=services_controller,
- action="delete_service",
- conditions=dict(method=["DELETE"]))
- mapper.connect("/OS-KSADM/services/{service_id}",
- controller=services_controller,
- action="get_service",
- conditions=dict(method=["GET"]))
- #Roles Operations
- mapper.connect("/OS-KSADM/roles", controller=roles_controller,
- action="create_role", conditions=dict(method=["POST"]))
- mapper.connect("/OS-KSADM/roles", controller=roles_controller,
- action="get_roles", conditions=dict(method=["GET"]))
- mapper.connect("/OS-KSADM/roles/{role_id}",
- controller=roles_controller, action="get_role",
- conditions=dict(method=["GET"]))
- mapper.connect("/OS-KSADM/roles/{role_id}",
- controller=roles_controller, action="delete_role",
- conditions=dict(method=["DELETE"]))
-
- #Credentials Operations
- mapper.connect("/users/{user_id}/OS-KSADM/credentials",
- controller=credentials_controller, action="get_credentials",
- conditions=dict(method=["GET"]))
- mapper.connect("/users/{user_id}/OS-KSADM/credentials",
- controller=credentials_controller, action="add_credential",
- conditions=dict(method=["POST"]))
- mapper.connect("/users/{user_id}/OS-KSADM/"\
- "credentials/passwordCredentials",
- controller=credentials_controller,
- action="get_password_credential",
- conditions=dict(method=["GET"]))
- mapper.connect("/users/{user_id}/OS-KSADM/credentials"\
- "/passwordCredentials",
- controller=credentials_controller,
- action="update_password_credential",
- conditions=dict(method=["POST"]))
- mapper.connect("/users/{user_id}/"\
- "OS-KSADM/credentials/passwordCredentials",
- controller=credentials_controller,
- action="delete_password_credential",
- conditions=dict(method=["DELETE"]))
diff --git a/keystone/contrib/extensions/admin/osksadm/extension.json b/keystone/contrib/extensions/admin/osksadm/extension.json
deleted file mode 100644
index 2c644f97..00000000
--- a/keystone/contrib/extensions/admin/osksadm/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "Openstack Keystone Admin",
- "namespace": "http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0",
- "alias": "OS-KSADM",
- "updated": "2011-08-19T13:25:27-06:00",
- "description": "Openstack extensions to Keystone v2.0 API enabling Admin Operations.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSADM-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSADM-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/osksadm/extension.xml b/keystone/contrib/extensions/admin/osksadm/extension.xml
deleted file mode 100644
index b3c0a7a6..00000000
--- a/keystone/contrib/extensions/admin/osksadm/extension.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Openstack Keystone Admin" namespace="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- alias="OS-KSADM"
- updated="2011-08-14T13:25:27-06:00">
- <description>
- Openstack extensions to Keystone v2.0
- API enabling Admin Operations.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSADM-admin-devguide.pdf"/>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSADM-admin.wadl"/>
-</extension>
diff --git a/keystone/contrib/extensions/admin/oskscatalog/__init__.py b/keystone/contrib/extensions/admin/oskscatalog/__init__.py
deleted file mode 100644
index 38f5cf65..00000000
--- a/keystone/contrib/extensions/admin/oskscatalog/__init__.py
+++ /dev/null
@@ -1,63 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.contrib.extensions.admin.extension import BaseExtensionHandler
-from keystone.controllers.endpointtemplates import EndpointTemplatesController
-
-
-class ExtensionHandler(BaseExtensionHandler):
- def map_extension_methods(self, mapper):
- #EndpointTemplates Calls
- endpoint_templates_controller = EndpointTemplatesController()
- mapper.connect("/OS-KSCATALOG/endpointTemplates",
- controller=endpoint_templates_controller,
- action="get_endpoint_templates",
- conditions=dict(method=["GET"]))
- mapper.connect("/OS-KSCATALOG/endpointTemplates",
- controller=endpoint_templates_controller,
- action="add_endpoint_template",
- conditions=dict(method=["POST"]))
- mapper.connect(
- "/OS-KSCATALOG/endpointTemplates/{endpoint_template_id}",
- controller=endpoint_templates_controller,
- action="get_endpoint_template",
- conditions=dict(method=["GET"]))
- mapper.connect(
- "/OS-KSCATALOG/endpointTemplates/{endpoint_template_id}",
- controller=endpoint_templates_controller,
- action="modify_endpoint_template",
- conditions=dict(method=["PUT"]))
- mapper.connect(
- "/OS-KSCATALOG/endpointTemplates/{endpoint_template_id}",
- controller=endpoint_templates_controller,
- action="delete_endpoint_template",
- conditions=dict(method=["DELETE"]))
- #Endpoint Calls
- mapper.connect("/tenants/{tenant_id}/OS-KSCATALOG/endpoints",
- controller=endpoint_templates_controller,
- action="get_endpoints_for_tenant",
- conditions=dict(method=["GET"]))
- mapper.connect("/tenants/{tenant_id}/OS-KSCATALOG/endpoints",
- controller=endpoint_templates_controller,
- action="add_endpoint_to_tenant",
- conditions=dict(method=["POST"]))
- mapper.connect(
- "/tenants/{tenant_id}/OS-KSCATALOG/endpoints/{endpoint_id}",
- controller=endpoint_templates_controller,
- action="remove_endpoint_from_tenant",
- conditions=dict(method=["DELETE"]))
diff --git a/keystone/contrib/extensions/admin/oskscatalog/extension.json b/keystone/contrib/extensions/admin/oskscatalog/extension.json
deleted file mode 100644
index c84c0e59..00000000
--- a/keystone/contrib/extensions/admin/oskscatalog/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "Openstack Keystone Catalog",
- "namespace": "http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0",
- "alias": "OS-KSCATALOG",
- "updated": "2011-07-13T13:25:27-06:00",
- "description": "Openstack extensions to Keystone v2.0 API enabling Admin Operations to support Catalog.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSCATALOG-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSCATALOG-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/oskscatalog/extension.xml b/keystone/contrib/extensions/admin/oskscatalog/extension.xml
deleted file mode 100644
index 8664c77f..00000000
--- a/keystone/contrib/extensions/admin/oskscatalog/extension.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Openstack Keystone Catalog" namespace="http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0"
- alias="OS-KSCATALOG"
- updated="2011-08-14T13:25:27-06:00">
- <description>
- Openstack extensions to Keystone v2.0 API enabling Admin Operations
- to support Catalog.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSCATALOG-admin-devguide.pdf"/>
- <atom:link rel="describedby" type="application/vnd.sun.wadl+xml"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSCATALOG-admin.wadl"/>
-</extension>
diff --git a/keystone/contrib/extensions/admin/osksvalidate/__init__.py b/keystone/contrib/extensions/admin/osksvalidate/__init__.py
deleted file mode 100644
index 36a50bd7..00000000
--- a/keystone/contrib/extensions/admin/osksvalidate/__init__.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.contrib.extensions.admin.extension import BaseExtensionHandler
-from keystone.contrib.extensions.admin.osksvalidate import handler
-
-
-class ExtensionHandler(BaseExtensionHandler):
- def map_extension_methods(self, mapper):
- extension_controller = handler.SecureValidationController()
-
- # Token Operations
- mapper.connect("/OS-KSVALIDATE/token/validate",
- controller=extension_controller,
- action="handle_validate_request",
- conditions=dict(method=["GET"]))
-
- mapper.connect("/OS-KSVALIDATE/token/endpoints",
- controller=extension_controller,
- action="handle_endpoints_request",
- conditions=dict(method=["GET"]))
- # TODO(zns): make this handle all routes by using the mapper
diff --git a/keystone/contrib/extensions/admin/osksvalidate/extension.json b/keystone/contrib/extensions/admin/osksvalidate/extension.json
deleted file mode 100644
index b1f0c65b..00000000
--- a/keystone/contrib/extensions/admin/osksvalidate/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "Openstack Keystone Admin",
- "namespace": "http://docs.openstack.org/identity/api/ext/OS-KSVALIDATE/v1.0",
- "alias": "OS-KSVALIDATE",
- "updated": "2012-01-12T12:17:00-06:00",
- "description": "Openstack extensions to Keystone v2.0 API for Secure Token Validation.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSVALIDATE-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSVALIDATE-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/osksvalidate/extension.xml b/keystone/contrib/extensions/admin/osksvalidate/extension.xml
deleted file mode 100644
index 6643484a..00000000
--- a/keystone/contrib/extensions/admin/osksvalidate/extension.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Openstack Keystone Admin" namespace="http://docs.openstack.org/identity/api/ext/OS-KSVALIDATE/v1.0"
- alias="OS-KSVALIDATE"
- updated="2012-01-12T12:17:00-06:00">
- <description>
- Openstack extensions to Keystone v2.0
- API for Secure Token Validation.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSVALIDATE-admin-devguide.pdf"/>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/OS-KSVALIDATE-admin.wadl"/>
-</extension>
diff --git a/keystone/contrib/extensions/admin/osksvalidate/handler.py b/keystone/contrib/extensions/admin/osksvalidate/handler.py
deleted file mode 100644
index 4ce7e7c5..00000000
--- a/keystone/contrib/extensions/admin/osksvalidate/handler.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Router & Controller for handling Secure Token Validation
-
-"""
-import logging
-
-from keystone.common import wsgi
-from keystone.controllers.token import TokenController
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class SecureValidationController(wsgi.Controller):
- """Controller for Tenant related operations"""
-
- # pylint: disable=W0231
- def __init__(self):
- self.token_controller = TokenController()
-
- logger.info("Initializing Secure Token Validation extension")
-
- def handle_validate_request(self, req):
- token_id = req.headers.get("X-Subject-Token")
- return self.token_controller.validate_token(req=req, token_id=token_id)
-
- def handle_endpoints_request(self, req):
- token_id = req.headers.get("X-Subject-Token")
- return self.token_controller.endpoints(req=req, token_id=token_id)
diff --git a/keystone/contrib/extensions/admin/raxgrp/extension.json b/keystone/contrib/extensions/admin/raxgrp/extension.json
deleted file mode 100644
index 31744b3d..00000000
--- a/keystone/contrib/extensions/admin/raxgrp/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "Rackspace Keystone Group Extensions",
- "namespace": "http://docs.rackspace.com/identity/api/ext/RAX-KSGROUP/v1.0",
- "alias": "RAX-KSGRP",
- "updated": "2011-08-14T13:25:27-06:00",
- "description": "Rackspace extensions to Keystone v2.0 API enabling groups.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSGRP-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSGRP-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/raxgrp/extension.xml b/keystone/contrib/extensions/admin/raxgrp/extension.xml
deleted file mode 100644
index 22f77faa..00000000
--- a/keystone/contrib/extensions/admin/raxgrp/extension.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Rackspace Keystone Group Extensions" namespace="http://docs.rackspace.com/identity/api/ext/RAX-KSGROUP/v1.0"
- alias="RAX-KSGRP"
- updated="2011-08-14T13:25:27-06:00">
- <description>
- Rackspace extensions to Keystone v2.0 API
- enabling groups.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSGRP-admin-devguide.pdf"/>
- <atom:link rel="describedby" type="application/vnd.sun.wadl+xml"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSGRP-admin.wadl"/>
-</extension>
diff --git a/keystone/contrib/extensions/admin/raxkey/extension.json b/keystone/contrib/extensions/admin/raxkey/extension.json
deleted file mode 100644
index 301ad6a2..00000000
--- a/keystone/contrib/extensions/admin/raxkey/extension.json
+++ /dev/null
@@ -1,21 +0,0 @@
-{
- "extension": {
- "name": "Rackspace API Key Authentication",
- "namespace": "http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0",
- "alias": "RAX-KSKEY",
- "updated": "2011-07-13T13:25:27-06:00",
- "description": "Rackspace extensions to Keystone v2.0 API enabling API Key authentication.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSKEY-admin-devguide.pdf"
- },
- {
- "rel": "describedby",
- "type": "application/vnd.sun.wadl+xml",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSKEY-admin.wadl"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/admin/raxkey/extension.xml b/keystone/contrib/extensions/admin/raxkey/extension.xml
deleted file mode 100644
index 175d7302..00000000
--- a/keystone/contrib/extensions/admin/raxkey/extension.xml
+++ /dev/null
@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Rackspace API Key authentication" namespace="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
- alias="RAX-KSKEY-admin"
- updated="2011-08-14T13:25:27-06:00">
- <description>
- Rackspace extensions to Keystone v2.0 API
- enabling API Key authentication.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSKEY-admin-devguide.pdf"/>
- <atom:link rel="describedby" type="application/vnd.sun.wadl+xml"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/admin/RAX-KSKEY-admin.wadl"/>
-</extension>
diff --git a/keystone/contrib/extensions/admin/raxkey/frontend.py b/keystone/contrib/extensions/admin/raxkey/frontend.py
deleted file mode 100644
index 4f3f0796..00000000
--- a/keystone/contrib/extensions/admin/raxkey/frontend.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-"""
-RACKSPACE API KEY EXTENSION
-
-This WSGI component
-- detects calls with extensions in them.
-- processes the necessary components
-"""
-
-import json
-import logging
-from lxml import etree
-import os
-from webob.exc import Request, Response
-
-from keystone import utils
-
-EXTENSION_ALIAS = "RAX-KSKEY-admin"
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class FrontEndFilter(object):
- """API Key Middleware that handles authentication with API Key"""
-
- def __init__(self, app, conf):
- """ Common initialization code """
- logger.info(_("Starting the %s extension" %
- EXTENSION_ALIAS))
- self.conf = conf
- self.app = app
-
- def __call__(self, env, start_response):
- """ Handle incoming request. Transform. And send downstream. """
- request = Request(env)
- if request.path == "/extensions":
- if env['KEYSTONE_API_VERSION'] == '2.0':
- request = Request(env)
- response = request.get_response(self.app)
- if response.status_int == 200:
- if response.content_type == 'application/json':
- #load json for this extension from file
- thisextension = open(os.path.join(
- os.path.dirname(__file__),
- "extension.json")).read()
- thisextensionjson = json.loads(thisextension)
-
- #load json in response
- body = json.loads(response.body)
- extensionsarray = body["extensions"]["values"]
-
- #add this extension and return the response
- extensionsarray.append(thisextensionjson)
- newresp = Response(
- content_type='application/json',
- body=json.dumps(body))
- return newresp(env, start_response)
- elif response.content_type == 'application/xml':
- #load xml for this extension from file
- thisextensionxml = etree.parse(os.path.join(
- os.path.dirname(__file__),
- "extension.xml")).getroot()
- #load xml being returned in response
- body = etree.fromstring(response.body)
-
- #add this extension and return the response
- body.append(thisextensionxml)
- newresp = Response(
- content_type='application/xml',
- body=etree.tostring(body))
- return newresp(env, start_response)
-
- # return the response
- return response(env, start_response)
-
- #default action, bypass
- return self.app(env, start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def ext_filter(app):
- """Closure to return"""
- return FrontEndFilter(app, conf)
- return ext_filter
diff --git a/keystone/contrib/extensions/extensions.json b/keystone/contrib/extensions/extensions.json
deleted file mode 100644
index 7a514fd7..00000000
--- a/keystone/contrib/extensions/extensions.json
+++ /dev/null
@@ -1,5 +0,0 @@
-{
- "extensions": {
- "values": []
- }
-}
diff --git a/keystone/contrib/extensions/extensions.xml b/keystone/contrib/extensions/extensions.xml
deleted file mode 100644
index ed5ee9c6..00000000
--- a/keystone/contrib/extensions/extensions.xml
+++ /dev/null
@@ -1,5 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-
-<extensions xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom">
-</extensions>
diff --git a/keystone/contrib/extensions/service/__init__.py b/keystone/contrib/extensions/service/__init__.py
deleted file mode 100644
index e0eeb867..00000000
--- a/keystone/contrib/extensions/service/__init__.py
+++ /dev/null
@@ -1 +0,0 @@
-EXTENSION_SERVICE_PREFIX = 'service'
diff --git a/keystone/contrib/extensions/service/osec2/extension.json b/keystone/contrib/extensions/service/osec2/extension.json
deleted file mode 100644
index a2d28717..00000000
--- a/keystone/contrib/extensions/service/osec2/extension.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "extension": {
- "name": "OpenStack EC2 authentication Extension",
- "namespace": "http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0",
- "alias": "OS-KSEC2",
- "updated": "2011-08-25T09:50:00-00:00",
- "description": "Adds the capability to support EC2 style authentication.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/service/OS-KSEC2-service-devguide.pdf"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/service/osec2/extension.xml b/keystone/contrib/extensions/service/osec2/extension.xml
deleted file mode 100644
index 0f8307f2..00000000
--- a/keystone/contrib/extensions/service/osec2/extension.xml
+++ /dev/null
@@ -1,16 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
- <extension
- name="OpenStack EC2 authentication Extension"
- namespace="http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- alias="OS-KSEC2-service"
- updated="2011-08-25T09:50:00-00:00">
-
- <description>
- Adds the capability to support EC2 style authentication.
- </description>
-
- <atom:link rel="describedby"
- type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/service/OS-KSEC2-service-devguide.pdf"/>
- </extension>
-
diff --git a/keystone/contrib/extensions/service/osec2/frontend.py b/keystone/contrib/extensions/service/osec2/frontend.py
deleted file mode 100644
index b2741b89..00000000
--- a/keystone/contrib/extensions/service/osec2/frontend.py
+++ /dev/null
@@ -1,105 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-"""
-RACKSPACE API KEY EXTENSION
-
-This WSGI component
-- detects calls with extensions in them.
-- processes the necessary components
-"""
-
-import json
-import os
-import logging
-from lxml import etree
-from webob.exc import Request, Response
-
-from keystone import utils
-
-EXTENSION_ALIAS = "OS-EC2"
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class FrontEndFilter(object):
- """API Key Middleware that handles authentication with API Key"""
-
- def __init__(self, app, conf):
- """ Common initialization code """
- logger.info(_("Starting the %s extension" %
- EXTENSION_ALIAS))
- self.conf = conf
- self.app = app
-
- def __call__(self, env, start_response):
- """ Handle incoming request. Transform. And send downstream. """
- request = Request(env)
- if request.path == "/extensions":
- if env['KEYSTONE_API_VERSION'] == '2.0':
- request = Request(env)
- response = request.get_response(self.app)
- if response.status_int == 200:
- if response.content_type == 'application/json':
- #load json for this extension from file
- thisextension = open(os.path.join(
- os.path.dirname(__file__),
- "extension.json")).read()
- thisextensionjson = json.loads(thisextension)
-
- #load json in response
- body = json.loads(response.body)
- extensionsarray = body["extensions"]["values"]
-
- #add this extension and return the response
- extensionsarray.append(thisextensionjson)
- newresp = Response(
- content_type='application/json',
- body=json.dumps(body))
- return newresp(env, start_response)
- elif response.content_type == 'application/xml':
- #load xml for this extension from file
- thisextensionxml = etree.parse(os.path.join(
- os.path.dirname(__file__),
- "extension.xml")).getroot()
- #load xml being returned in response
- body = etree.fromstring(response.body)
-
- #add this extension and return the response
- body.append(thisextensionxml)
- newresp = Response(
- content_type='application/xml',
- body=etree.tostring(body))
- return newresp(env, start_response)
-
- # return the response
- return response(env, start_response)
-
- #default action, bypass
- return self.app(env, start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def ext_filter(app):
- """Closure to return"""
- return FrontEndFilter(app, conf)
- return ext_filter
diff --git a/keystone/contrib/extensions/service/raxgrp/api.py b/keystone/contrib/extensions/service/raxgrp/api.py
deleted file mode 100755
index 1882a13f..00000000
--- a/keystone/contrib/extensions/service/raxgrp/api.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-from keystone.backends.api import BaseUserAPI
-
-
-#Base APIs
-class RAXEXTBaseUserAPI(BaseUserAPI):
-
- def get_by_group(self, user_id, group_id):
- raise NotImplementedError
-
- def tenant_group(self, values):
- raise NotImplementedError
-
- def tenant_group_delete(self, id, group_id):
- raise NotImplementedError
-
- def get_groups(self, id):
- raise NotImplementedError
-
- def users_tenant_group_get_page(self, group_id, marker, limit):
- raise NotImplementedError
-
- def users_tenant_group_get_page_markers(self, group_id, marker, limit):
- raise NotImplementedError
-
- def get_group_by_tenant(self, id):
- raise NotImplementedError
-
- def delete_tenant_user(self, id, tenant_id):
- raise NotImplementedError
-
- def users_get_by_tenant(self, user_id, tenant_id):
- raise NotImplementedError
-
- def user_role_add(self, values):
- raise NotImplementedError
-
- def user_get_update(self, id):
- raise NotImplementedError
-
- def users_get_page(self, marker, limit):
- raise NotImplementedError
-
- def users_get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def users_get_by_tenant_get_page(self, tenant_id, role_id, marker, limit):
- raise NotImplementedError
-
- def users_get_by_tenant_get_page_markers(self, tenant_id,
- role_id, marker, limit):
- raise NotImplementedError
-
- def check_password(self, user, password):
- raise NotImplementedError
-
-
-class RAXEXTBaseTenantGroupAPI(object):
- def create(self, values):
- raise NotImplementedError
-
- def is_empty(self, id):
- raise NotImplementedError
-
- def get(self, id, tenant):
- raise NotImplementedError
-
- def get_page(self, tenant_id, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, tenant_id, marker, limit):
- raise NotImplementedError
-
- def update(self, id, tenant_id, values):
- raise NotImplementedError
-
- def delete(self, id, tenant_id):
- raise NotImplementedError
-
-
-class RAXEXTBaseGroupAPI(object):
- def get(self, id):
- raise NotImplementedError
-
- def get_users(self, id):
- raise NotImplementedError
-
- def get_all(self):
- raise NotImplementedError
-
- def get_page(self, marker, limit):
- raise NotImplementedError
-
- def get_page_markers(self, marker, limit):
- raise NotImplementedError
-
- def delete(self, id):
- raise NotImplementedError
-
- def get_by_user_get_page(self, user_id, marker, limit):
- raise NotImplementedError
-
- def get_by_user_get_page_markers(self, user_id, marker, limit):
- raise NotImplementedError
-
-
-#API
-#TODO(Yogi) Refactor all API to separate classes specific to models.
-GROUP = RAXEXTBaseGroupAPI()
-TENANT_GROUP = RAXEXTBaseTenantGroupAPI()
-USER = RAXEXTBaseUserAPI()
-
-
-# Function to dynamically set module references.
-def set_value(variable_name, value):
- if variable_name == 'group':
- global GROUP
- GROUP = value
- elif variable_name == 'tenant_group':
- global TENANT_GROUP
- TENANT_GROUP = value
- elif variable_name == 'user':
- global USER
- USER = value
diff --git a/keystone/contrib/extensions/service/raxgrp/extension.json b/keystone/contrib/extensions/service/raxgrp/extension.json
deleted file mode 100644
index e2c889dd..00000000
--- a/keystone/contrib/extensions/service/raxgrp/extension.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "extension": {
- "name": "Rackspace Keystone Group Extensions",
- "namespace": "http://docs.rackspace.com/identity/api/ext/RAX-KSGROUP/v1.0",
- "alias": "RAX-KSGRP",
- "updated": "2011-08-14T13:25:27-06:00",
- "description": "Rackspace extensions to Keystone v2.0 API enabling groups.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/service/RAX-KSGRP-service-devguide.pdf"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/service/raxgrp/extension.xml b/keystone/contrib/extensions/service/raxgrp/extension.xml
deleted file mode 100644
index f05855ac..00000000
--- a/keystone/contrib/extensions/service/raxgrp/extension.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Rackspace Keystone Group Extensions" namespace="http://docs.rackspace.com/identity/api/ext/RAX-KSGROUP/v1.0"
- alias="RAX-KSGRP"
- updated="2011-08-14T13:25:27-06:00">
- <description>
- Rackspace extensions to Keystone v2.0 API
- enabling groups.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="http://docs.rackspacecloud.com/identity/api/ext/RAX-KSGRP-service-devguide.pdf"/>
-</extension>
diff --git a/keystone/contrib/extensions/service/raxkey/__init__.py b/keystone/contrib/extensions/service/raxkey/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/contrib/extensions/service/raxkey/__init__.py
+++ /dev/null
diff --git a/keystone/contrib/extensions/service/raxkey/extension.json b/keystone/contrib/extensions/service/raxkey/extension.json
deleted file mode 100644
index ad72420e..00000000
--- a/keystone/contrib/extensions/service/raxkey/extension.json
+++ /dev/null
@@ -1,16 +0,0 @@
-{
- "extension": {
- "name": "Rackspace API Key Authentication",
- "namespace": "http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0",
- "alias": "RAX-KSKEY",
- "updated": "2011-08-14T13:25:27-06:00",
- "description": "Rackspace extensions to Keystone v2.0 API enabling API Key authentication.",
- "links": [
- {
- "rel": "describedby",
- "type": "application/pdf",
- "href": "https://github.com/openstack/keystone/raw/master/keystone/content/service/RAX-KSKEY-service-devguide.pdf"
- }
- ]
- }
-}
diff --git a/keystone/contrib/extensions/service/raxkey/extension.xml b/keystone/contrib/extensions/service/raxkey/extension.xml
deleted file mode 100644
index 981cb2bc..00000000
--- a/keystone/contrib/extensions/service/raxkey/extension.xml
+++ /dev/null
@@ -1,13 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<extension xmlns="http://docs.openstack.org/common/api/v1.0"
- xmlns:atom="http://www.w3.org/2005/Atom"
- name="Rackspace API Key authentication" namespace="http://docs.rackspace.com/identity/api/ext/RAX-KSKEY/v1.0"
- alias="RAX-KSKEY"
- updated="2011-08-14T13:25:27-06:00">
- <description>
- Rackspace extensions to Keystone v2.0 API
- enabling API Key authentication.
- </description>
- <atom:link rel="describedby" type="application/pdf"
- href="https://github.com/openstack/keystone/raw/master/keystone/content/service/RAX-KSKEY-service-devguide.pdf"/>
-</extension>
diff --git a/keystone/contrib/extensions/service/raxkey/frontend.py b/keystone/contrib/extensions/service/raxkey/frontend.py
deleted file mode 100644
index 1a050013..00000000
--- a/keystone/contrib/extensions/service/raxkey/frontend.py
+++ /dev/null
@@ -1,62 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-"""
-RACKSPACE API KEY EXTENSION
-
-Deprecated middleware. We still have it here to not break compatiblity with
-configuration files that add it to the pipeline.
-"""
-import logging
-
-from keystone import utils
-
-EXTENSION_ALIAS = "RAX-KEY"
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class FrontEndFilter(object):
- """API Key Middleware that handles authentication with API Key"""
-
- def __init__(self, app, conf):
- """ Common initialization code """
- logger.warn(_("WARNING: Starting the %s extension which "
- "is deprecated" %
- EXTENSION_ALIAS))
- self.conf = conf
- self.app = app
-
- def __call__(self, env, start_response):
- logger.warn("%s middleware is deprecated and will be removed in "
- "Essex+1 (Fall fo 2012). Remove it from your "
- "configuration files." % EXTENSION_ALIAS)
- #Kept for backward compatibility with existing configuration files.
- #Does nothing now.
- return self.app(env, start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def ext_filter(app):
- """Closure to return"""
- return FrontEndFilter(app, conf)
- return ext_filter
diff --git a/keystone/contrib/s3/__init__.py b/keystone/contrib/s3/__init__.py
new file mode 100644
index 00000000..22149596
--- /dev/null
+++ b/keystone/contrib/s3/__init__.py
@@ -0,0 +1 @@
+from keystone.contrib.s3.core import *
diff --git a/keystone/contrib/s3/core.py b/keystone/contrib/s3/core.py
new file mode 100644
index 00000000..d69fade4
--- /dev/null
+++ b/keystone/contrib/s3/core.py
@@ -0,0 +1,37 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Main entry point into the S3 Credentials service.
+
+TODO-DOCS
+"""
+
+import base64
+import hmac
+
+from hashlib import sha1
+
+from keystone import config
+from keystone.common import wsgi
+from keystone.contrib import ec2
+
+CONF = config.CONF
+
+
+class S3Extension(wsgi.ExtensionRouter):
+ def add_routes(self, mapper):
+ controller = S3Controller()
+ # validation
+ mapper.connect('/s3tokens',
+ controller=controller,
+ action='authenticate',
+ conditions=dict(method=['POST']))
+
+
+class S3Controller(ec2.Ec2Controller):
+ def check_signature(self, creds_ref, credentials):
+ msg = base64.urlsafe_b64decode(str(credentials['token']))
+ key = str(creds_ref['secret'])
+ signed = base64.encodestring(hmac.new(key, msg, sha1).digest()).strip()
+
+ if credentials['signature'] != signed:
+ raise Exception('Not Authorized')
diff --git a/keystone/controllers/__init__.py b/keystone/controllers/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/controllers/__init__.py
+++ /dev/null
diff --git a/keystone/controllers/base_controller.py b/keystone/controllers/base_controller.py
deleted file mode 100644
index 5b87e860..00000000
--- a/keystone/controllers/base_controller.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# Copyright (c) 2011 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.
-
-"""
-Base Class Controller
-
-"""
-import functools
-import logging
-
-from keystone import utils
-from keystone.common import wsgi
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class BaseController(wsgi.Controller):
- """Base Controller class for Keystone"""
-
- @staticmethod
- def get_url(req):
- return '%s://%s:%s%s' % (
- req.environ['wsgi.url_scheme'],
- req.environ.get("SERVER_NAME"),
- req.environ.get("SERVER_PORT"),
- req.environ['PATH_INFO'])
-
- def get_marker_limit_and_url(self, req):
- marker = req.GET["marker"] if "marker" in req.GET else None
- limit = req.GET["limit"] if "limit" in req.GET else 10
- url = self.get_url(req)
- return (marker, limit, url)
diff --git a/keystone/controllers/credentials.py b/keystone/controllers/credentials.py
deleted file mode 100644
index b7d4022b..00000000
--- a/keystone/controllers/credentials.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Credentials Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.logic import service
-from keystone.logic.types.credential import PasswordCredentials
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class CredentialsController(BaseController):
- """Controller for Credentials related operations"""
- def __init__(self):
- self.identity_service = service.IdentityService()
-
- @utils.wrap_error
- def get_credentials(self, req, user_id):
- marker, limit, url = self.get_marker_limit_and_url(req)
- credentials = self.identity_service.get_credentials(
- utils.get_auth_token(req), user_id, marker, limit, url)
- return utils.send_result(200, req, credentials)
-
- @utils.wrap_error
- def get_password_credential(self, req, user_id):
- credentials = self.identity_service.get_password_credentials(
- utils.get_auth_token(req), user_id)
- return utils.send_result(200, req, credentials)
-
- @utils.wrap_error
- def delete_password_credential(self, req, user_id):
- self.identity_service.delete_password_credentials(
- utils.get_auth_token(req), user_id)
- return utils.send_result(204, None)
-
- @utils.wrap_error
- def add_credential(self, req, user_id):
- credential = utils.get_normalized_request_content(
- PasswordCredentials, req)
- credential = self.identity_service.create_password_credentials(
- utils.get_auth_token(req), user_id, credential)
- return utils.send_result(201, req, credential)
-
- @utils.wrap_error
- def update_password_credential(self, req, user_id):
- credential = utils.get_normalized_request_content(
- PasswordCredentials, req)
- credential = self.identity_service.update_password_credentials(
- utils.get_auth_token(req), user_id, credential)
- return utils.send_result(200, req, credential)
diff --git a/keystone/controllers/endpointtemplates.py b/keystone/controllers/endpointtemplates.py
deleted file mode 100644
index 4113d4d8..00000000
--- a/keystone/controllers/endpointtemplates.py
+++ /dev/null
@@ -1,99 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-EndpointTemplates Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.logic import service
-from keystone.logic.types.endpoint import EndpointTemplate
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class EndpointTemplatesController(BaseController):
- """Controller for EndpointTemplates related operations"""
-
- def __init__(self):
- self.identity_service = service.IdentityService()
-
- @utils.wrap_error
- def get_endpoint_templates(self, req):
- marker, limit, url = self.get_marker_limit_and_url(req)
- service_id = req.GET["serviceId"] if "serviceId" in req.GET else None
- if service_id:
- endpoint_templates = self.identity_service.\
- get_endpoint_templates_by_service(
- utils.get_auth_token(req), service_id, marker, limit, url)
- else:
- endpoint_templates = self.identity_service.get_endpoint_templates(
- utils.get_auth_token(req), marker, limit, url)
- return utils.send_result(200, req, endpoint_templates)
-
- @utils.wrap_error
- def add_endpoint_template(self, req):
- endpoint_template = utils.get_normalized_request_content(
- EndpointTemplate, req)
- return utils.send_result(201, req,
- self.identity_service.add_endpoint_template(
- utils.get_auth_token(req), endpoint_template))
-
- @utils.wrap_error
- def modify_endpoint_template(self, req, endpoint_template_id):
- endpoint_template = utils.\
- get_normalized_request_content(EndpointTemplate, req)
- return utils.send_result(201, req,
- self.identity_service.modify_endpoint_template(\
- utils.get_auth_token(req),
- endpoint_template_id, endpoint_template))
-
- @utils.wrap_error
- def delete_endpoint_template(self, req, endpoint_template_id):
- rval = self.identity_service.delete_endpoint_template(
- utils.get_auth_token(req), endpoint_template_id)
- return utils.send_result(204, req, rval)
-
- @utils.wrap_error
- def get_endpoint_template(self, req, endpoint_template_id):
- endpoint_template = self.identity_service.get_endpoint_template(
- utils.get_auth_token(req), endpoint_template_id)
- return utils.send_result(200, req, endpoint_template)
-
- @utils.wrap_error
- def get_endpoints_for_tenant(self, req, tenant_id):
- marker, limit, url = self.get_marker_limit_and_url(req)
- endpoints = self.identity_service.get_tenant_endpoints(
- utils.get_auth_token(req), marker, limit, url, tenant_id)
- return utils.send_result(200, req, endpoints)
-
- @utils.wrap_error
- def add_endpoint_to_tenant(self, req, tenant_id):
- endpoint = utils.get_normalized_request_content(EndpointTemplate, req)
- return utils.send_result(201, req,
- self.identity_service.create_endpoint_for_tenant(
- utils.get_auth_token(req), tenant_id, endpoint))
-
- @utils.wrap_error
- def remove_endpoint_from_tenant(self, req, tenant_id, endpoint_id):
- rval = self.identity_service.delete_endpoint(utils.get_auth_token(req),
- endpoint_id)
- return utils.send_result(204, req, rval)
diff --git a/keystone/controllers/extensions.py b/keystone/controllers/extensions.py
deleted file mode 100644
index 171710f6..00000000
--- a/keystone/controllers/extensions.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Extensions Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.logic.extension_reader import ExtensionsReader
-from keystone.contrib.extensions.admin import EXTENSION_ADMIN_PREFIX
-from keystone.contrib.extensions.service import EXTENSION_SERVICE_PREFIX
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class ExtensionsController(BaseController):
- """Controller for extensions related methods"""
-
- def __init__(self, is_service_operation=None):
- super(ExtensionsController, self).__init__()
- if is_service_operation:
- self.extension_prefix = EXTENSION_SERVICE_PREFIX
- else:
- self.extension_prefix = EXTENSION_ADMIN_PREFIX
- self.extension_reader = ExtensionsReader(self.extension_prefix)
-
- @utils.wrap_error
- def get_extensions_info(self, req):
- return utils.send_result(200, req,
- self.extension_reader.get_extensions())
diff --git a/keystone/controllers/roles.py b/keystone/controllers/roles.py
deleted file mode 100644
index 0cc516f7..00000000
--- a/keystone/controllers/roles.py
+++ /dev/null
@@ -1,101 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Roles Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.models import Role
-from keystone.logic import service
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class RolesController(BaseController):
- """Controller for Role related operations"""
-
- def __init__(self):
- self.identity_service = service.IdentityService()
-
- # Not exposed yet.
- @utils.wrap_error
- def create_role(self, req):
- role = utils.get_normalized_request_content(Role, req)
- return utils.send_result(201, req,
- self.identity_service.create_role(utils.get_auth_token(req), role))
-
- @utils.wrap_error
- def delete_role(self, req, role_id):
- rval = self.identity_service.delete_role(
- utils.get_auth_token(req), role_id)
- return utils.send_result(204, req, rval)
-
- @utils.wrap_error
- def get_roles(self, req):
- role_name = req.GET["name"] if "name" in req.GET else None
- if role_name:
- return self.__get_roles_by_name(req, role_name)
- else:
- return self.__get_all_roles(req)
-
- def __get_roles_by_name(self, req, role_name):
- tenant = self.identity_service.get_role_by_name(
- utils.get_auth_token(req), role_name)
- return utils.send_result(200, req, tenant)
-
- def __get_all_roles(self, req):
- service_id = req.GET["serviceId"] if "serviceId" in req.GET else None
- marker, limit, url = self.get_marker_limit_and_url(req)
- if service_id:
- roles = self.identity_service.get_roles_by_service(
- utils.get_auth_token(req), marker, limit, url,
- service_id)
- return utils.send_result(200, req, roles)
- else:
- roles = self.identity_service.get_roles(
- utils.get_auth_token(req), marker, limit, url)
- return utils.send_result(200, req, roles)
-
- @utils.wrap_error
- def get_role(self, req, role_id):
- role = self.identity_service.get_role(utils.get_auth_token(req),
- role_id)
- return utils.send_result(200, req, role)
-
- @utils.wrap_error
- def add_role_to_user(self, req, user_id, role_id, tenant_id=None):
- self.identity_service.add_role_to_user(utils.get_auth_token(req),
- user_id, role_id, tenant_id)
- return utils.send_result(201, None)
-
- @utils.wrap_error
- def delete_role_from_user(self, req, user_id, role_id, tenant_id=None):
- self.identity_service.remove_role_from_user(utils.get_auth_token(req),
- user_id, role_id, tenant_id)
- return utils.send_result(204, req, None)
-
- @utils.wrap_error
- def get_user_roles(self, req, user_id, tenant_id=None):
- marker, limit, url = self.get_marker_limit_and_url(req)
- roles = self.identity_service.get_user_roles(
- utils.get_auth_token(req), marker, limit, url, user_id, tenant_id)
- return utils.send_result(200, req, roles)
diff --git a/keystone/controllers/services.py b/keystone/controllers/services.py
deleted file mode 100755
index 9d1c0f4f..00000000
--- a/keystone/controllers/services.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Services Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.models import Service
-from keystone.logic import service
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class ServicesController(BaseController):
- """Controller for Service related operations"""
-
- def __init__(self):
- self.identity_service = service.IdentityService()
-
- @utils.wrap_error
- def create_service(self, req):
- service = utils.get_normalized_request_content(Service, req)
- return utils.send_result(201, req,
- self.identity_service.create_service(utils.get_auth_token(req),
- service))
-
- @utils.wrap_error
- def get_services(self, req):
- service_name = req.GET["name"] if "name" in req.GET else None
- if service_name:
- tenant = self.identity_service.get_service_by_name(
- utils.get_auth_token(req), service_name)
- return utils.send_result(200, req, tenant)
- else:
- marker, limit, url = self.get_marker_limit_and_url(req)
- services = self.identity_service.get_services(
- utils.get_auth_token(req), marker, limit, url)
- return utils.send_result(200, req, services)
-
- @utils.wrap_error
- def get_service(self, req, service_id):
- service = self.identity_service.get_service(
- utils.get_auth_token(req), service_id)
- return utils.send_result(200, req, service)
-
- @utils.wrap_error
- def delete_service(self, req, service_id):
- rval = self.identity_service.delete_service(utils.get_auth_token(req),
- service_id)
- return utils.send_result(204, req, rval)
diff --git a/keystone/controllers/staticfiles.py b/keystone/controllers/staticfiles.py
deleted file mode 100644
index f6c79186..00000000
--- a/keystone/controllers/staticfiles.py
+++ /dev/null
@@ -1,89 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Static Files Controller
-
-Serves static files like PDF, WADL, etc...
-"""
-import logging
-import os
-from webob import Response
-
-from keystone import utils
-from keystone.common import template
-from keystone.controllers.base_controller import BaseController
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class StaticFilesController(BaseController):
- """Controller for contract documents"""
- @staticmethod
- @utils.wrap_error
- def get_pdf_contract(req, pdf, root="content/"):
- resp = Response()
- filepath = root + pdf
- return template.static_file(resp, req, filepath,
- root=utils.get_app_root(), mimetype="application/pdf")
-
- @staticmethod
- @utils.wrap_error
- def get_wadl_contract(req, wadl, root):
- resp = Response()
- return template.static_file(resp, req, root + wadl,
- root=utils.get_app_root(), mimetype="application/vnd.sun.wadl+xml")
-
- @staticmethod
- @utils.wrap_error
- def get_xsd_contract(req, xsd, root="content/"):
- resp = Response()
- return template.static_file(resp, req, root + "xsd/" + xsd,
- root=utils.get_app_root(), mimetype="application/xml")
-
- @staticmethod
- @utils.wrap_error
- def get_xsd_atom_contract(req, xsd, root="content/"):
- resp = Response()
- return template.static_file(resp, req, root + "xsd/atom/" + xsd,
- root=utils.get_app_root(), mimetype="application/xml")
-
- @staticmethod
- @utils.wrap_error
- def get_static_file(req, path, file, mimetype=None, root="content/"):
- resp = Response()
-
- if mimetype is None:
- if utils.is_xml_response(req):
- mimetype = "application/xml"
- elif utils.is_json_response(req):
- mimetype = "application/json"
- else:
- logger.debug("Unhandled mime type: %s" % req.content_type)
-
- basename, extension = os.path.splitext(file)
- resp_file = "%s%s%s" % (root, path, file)
- if extension is None or extension == '':
- if mimetype == "application/xml":
- resp_file = "%s.xml" % resp_file
- elif mimetype == "application/json":
- resp_file = "%s.json" % resp_file
-
- logger.debug("Returning contents from file '%s'" % resp_file)
- return template.static_file(resp, req, resp_file,
- root=utils.get_app_root(), mimetype=mimetype)
diff --git a/keystone/controllers/tenant.py b/keystone/controllers/tenant.py
deleted file mode 100644
index 562998c7..00000000
--- a/keystone/controllers/tenant.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Tenant Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.logic import service
-from keystone.models import Tenant
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class TenantController(BaseController):
- """Controller for Tenant related operations"""
-
- def __init__(self, is_service_operation=None):
- self.identity_service = service.IdentityService()
- self.is_service_operation = is_service_operation
- logger.debug("Initializing: 'Service API' mode=%s" %
- self.is_service_operation)
-
- @utils.wrap_error
- def create_tenant(self, req):
- tenant = utils.get_normalized_request_content(Tenant, req)
- return utils.send_result(201, req,
- self.identity_service.create_tenant(utils.get_auth_token(req),
- tenant))
-
- @utils.wrap_error
- def get_tenants(self, req):
- tenant_name = req.GET["name"] if "name" in req.GET else None
- if tenant_name:
- tenant = self.identity_service.get_tenant_by_name(
- utils.get_auth_token(req),
- tenant_name)
- return utils.send_result(200, req, tenant)
- else:
- marker, limit, url = self.get_marker_limit_and_url(req)
- tenants = self.identity_service.get_tenants(
- utils.get_auth_token(req), marker, limit, url,
- self.is_service_operation)
- return utils.send_result(200, req, tenants)
-
- @utils.wrap_error
- def get_tenant(self, req, tenant_id):
- tenant = self.identity_service.get_tenant(utils.get_auth_token(req),
- tenant_id)
- return utils.send_result(200, req, tenant)
-
- @utils.wrap_error
- def update_tenant(self, req, tenant_id):
- tenant = utils.get_normalized_request_content(Tenant, req)
- rval = self.identity_service.update_tenant(utils.get_auth_token(req),
- tenant_id, tenant)
- return utils.send_result(200, req, rval)
-
- @utils.wrap_error
- def delete_tenant(self, req, tenant_id):
- rval = self.identity_service.delete_tenant(utils.get_auth_token(req),
- tenant_id)
- return utils.send_result(204, req, rval)
diff --git a/keystone/controllers/token.py b/keystone/controllers/token.py
deleted file mode 100644
index 1f2e36c8..00000000
--- a/keystone/controllers/token.py
+++ /dev/null
@@ -1,141 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Token Controller
-
-This module contains the TokenController class which receives token-related
-calls from the request routers.
-
-"""
-import logging
-
-from keystone import config
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.logic import extension_reader
-from keystone.logic.types import auth
-from keystone.logic.types import fault
-from keystone.logic import service
-
-CONF = config.CONF
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class TokenController(BaseController):
- """Controller for token related operations"""
-
- def __init__(self):
- self.identity_service = service.IdentityService()
- logger.debug("Token controller init with HP-IDM extension: %s" % \
- extension_reader.is_extension_supported('hpidm'))
-
- @utils.wrap_error
- def authenticate(self, req):
- credential_type = utils.detect_credential_type(req)
- if credential_type == "passwordCredentials":
- auth_with_credentials = utils.get_normalized_request_content(
- auth.AuthWithPasswordCredentials, req)
- result = self.identity_service.authenticate(
- auth_with_credentials)
- return utils.send_result(200, req, result)
- elif credential_type == "token":
- unscoped = utils.get_normalized_request_content(
- auth.AuthWithUnscopedToken, req)
- result = self.identity_service.\
- authenticate_with_unscoped_token(unscoped)
- return utils.send_result(200, req, result)
- elif credential_type == "OS-KSEC2:ec2Credentials":
- return self._authenticate_ec2(req)
- elif credential_type == "OS-KSS3:s3Credentials":
- return self._authenticate_s3(req)
- elif credential_type in ["ec2Credentials", "OS-KSEC2-ec2Credentials"]:
- logger.warning('Received EC2 credentials in %s format. Processing '
- 'may fail. Update the client code sending this '
- 'format' % credential_type)
- return self._authenticate_ec2(req)
- else:
- raise fault.BadRequestFault("Invalid credentials %s" %
- credential_type)
-
- @utils.wrap_error
- def authenticate_ec2(self, req):
- return self._authenticate_ec2(req)
-
- def _authenticate_ec2(self, req):
- """Undecorated EC2 handler"""
- creds = utils.get_normalized_request_content(auth.Ec2Credentials, req)
- return utils.send_result(200, req,
- self.identity_service.authenticate_ec2(creds))
-
- @utils.wrap_error
- def authenticate_s3(self, req):
- return self._authenticate_s3(req)
-
- def _authenticate_s3(self, req):
- """Undecorated S3 handler"""
- creds = utils.get_normalized_request_content(auth.S3Credentials, req)
- return utils.send_result(200, req,
- self.identity_service.authenticate_s3(creds))
-
- def _validate_token(self, req, token_id):
- """Validates the token, and that it belongs to the specified tenant"""
- belongs_to = req.GET.get('belongsTo')
- service_ids = None
- if extension_reader.is_extension_supported('hpidm'):
- # service IDs are only relevant if hpidm extension is enabled
- service_ids = req.GET.get('HP-IDM-serviceId')
- return self.identity_service.validate_token(
- utils.get_auth_token(req), token_id, belongs_to, service_ids)
-
- @utils.wrap_error
- def validate_token(self, req, token_id):
- if CONF.disable_tokens_in_url:
- fault.ServiceUnavailableFault()
- else:
- result = self._validate_token(req, token_id)
- return utils.send_result(200, req, result)
-
- @utils.wrap_error
- def check_token(self, req, token_id):
- """Validates the token, but only returns a status code (HEAD)"""
- if CONF.disable_tokens_in_url:
- fault.ServiceUnavailableFault()
- else:
- self._validate_token(req, token_id)
- return utils.send_result(200, req)
-
- @utils.wrap_error
- def delete_token(self, req, token_id):
- if CONF.disable_tokens_in_url:
- fault.ServiceUnavailableFault()
- else:
- return utils.send_result(204, req,
- self.identity_service.revoke_token(
- utils.get_auth_token(req), token_id))
-
- @utils.wrap_error
- def endpoints(self, req, token_id):
- if CONF.disable_tokens_in_url:
- fault.ServiceUnavailableFault()
- else:
- marker, limit, url = self.get_marker_limit_and_url(req)
- return utils.send_result(200, req,
- self.identity_service.get_endpoints_for_token(
- utils.get_auth_token(req),
- token_id, marker, limit, url))
diff --git a/keystone/controllers/user.py b/keystone/controllers/user.py
deleted file mode 100644
index c7f37f64..00000000
--- a/keystone/controllers/user.py
+++ /dev/null
@@ -1,105 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-User Controller
-
-"""
-import logging
-
-from keystone import utils
-from keystone.controllers.base_controller import BaseController
-from keystone.logic import service
-from keystone.logic.types.user import User, User_Update
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class UserController(BaseController):
- """Controller for User related operations"""
-
- def __init__(self):
- self.identity_service = service.IdentityService()
-
- @utils.wrap_error
- def create_user(self, req):
- u = utils.get_normalized_request_content(User, req)
- return utils.send_result(201, req, self.identity_service.create_user(
- utils.get_auth_token(req), u))
-
- @utils.wrap_error
- def get_users(self, req):
- user_name = req.GET["name"] if "name" in req.GET else None
- if user_name:
- tenant = self.identity_service.get_user_by_name(
- utils.get_auth_token(req),
- user_name)
- return utils.send_result(200, req, tenant)
- else:
- marker, limit, url = self.get_marker_limit_and_url(req)
- users = self.identity_service.get_users(utils.get_auth_token(req),
- marker, limit, url)
- return utils.send_result(200, req, users)
-
- @utils.wrap_error
- def get_user(self, req, user_id):
- user = self.identity_service.get_user(utils.get_auth_token(req),
- user_id)
- return utils.send_result(200, req, user)
-
- @utils.wrap_error
- def update_user(self, req, user_id):
- user = utils.get_normalized_request_content(User_Update, req)
- rval = self.identity_service.update_user(utils.get_auth_token(req),
- user_id, user)
- return utils.send_result(200, req, rval)
-
- @utils.wrap_error
- def delete_user(self, req, user_id):
- rval = self.identity_service.delete_user(utils.get_auth_token(req),
- user_id)
- return utils.send_result(204, req, rval)
-
- @utils.wrap_error
- def set_user_password(self, req, user_id):
- user = utils.get_normalized_request_content(User_Update, req)
- rval = self.identity_service.set_user_password(
- utils.get_auth_token(req), user_id, user)
- return utils.send_result(200, req, rval)
-
- @utils.wrap_error
- def set_user_enabled(self, req, user_id):
- user = utils.get_normalized_request_content(User_Update, req)
- rval = self.identity_service.enable_disable_user(
- utils.get_auth_token(req), user_id, user)
- return utils.send_result(200, req, rval)
-
- @utils.wrap_error
- def update_user_tenant(self, req, user_id):
- user = utils.get_normalized_request_content(User_Update, req)
- rval = self.identity_service.set_user_tenant(utils.get_auth_token(req),
- user_id, user)
- return utils.send_result(200, req, rval)
-
- @utils.wrap_error
- def get_tenant_users(self, req, tenant_id):
- marker, limit, url = self.get_marker_limit_and_url(req)
- role_id = req.GET["roleId"] if "roleId" in req.GET else None
- users = self.identity_service.get_tenant_users(
- utils.get_auth_token(req), tenant_id, role_id, marker, limit, url)
- return utils.send_result(200, req, users)
diff --git a/keystone/controllers/version.py b/keystone/controllers/version.py
deleted file mode 100644
index b494c5f5..00000000
--- a/keystone/controllers/version.py
+++ /dev/null
@@ -1,116 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Version Controller
-
-"""
-import logging
-import os
-from webob import Response
-
-from keystone import utils
-from keystone import version
-from keystone.common import template
-from keystone.controllers.base_controller import BaseController
-
-# Calculate root path (to get to static files)
-POSSIBLE_TOPDIR = os.path.normpath(os.path.join(os.path.dirname(__file__),
- os.pardir,
- os.pardir))
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class VersionController(BaseController):
- """Controller for version related methods"""
- @utils.wrap_error
- def get_version_info(self, req, file="version"):
- resp = Response()
- resp.charset = 'UTF-8'
- if utils.is_xml_response(req):
- resp_file = os.path.join(POSSIBLE_TOPDIR,
- "keystone/content/%s.xml.tpl" % file)
- resp.content_type = "application/xml"
- elif utils.is_atom_response(req):
- resp_file = os.path.join(POSSIBLE_TOPDIR,
- "keystone/content/%s.atom.tpl" % file)
- resp.content_type = "application/atom+xml"
- else:
- resp_file = os.path.join(POSSIBLE_TOPDIR,
- "keystone/content/%s.json.tpl" % file)
- resp.content_type = "application/json"
-
- hostname = req.environ.get("SERVER_NAME")
- port = req.environ.get("SERVER_PORT")
- if 'HTTPS' in req.environ:
- protocol = 'https'
- else:
- protocol = 'http'
-
- resp.unicode_body = template.template(resp_file,
- PROTOCOL=protocol,
- HOST=hostname,
- PORT=port,
- API_VERSION=version.API_VERSION,
- API_VERSION_STATUS=version.API_VERSION_STATUS,
- API_VERSION_DATE=version.API_VERSION_DATE)
-
- return resp
-
- @utils.wrap_error
- def get_multiple_choice(self, req, file="multiple_choice", path=None):
- """ Returns a multiple-choices response based on API spec
-
- Response will include in it only one choice, which is for the
- current API version. The response is a 300 Multiple Choice
- response with either an XML or JSON body.
-
- """
- if path is None:
- path = ''
- logger.debug("300 Multiple Choices response: %s" % path)
- resp = Response(status="300 Multiple Choices")
- resp.charset = 'UTF-8'
- if utils.is_xml_response(req):
- resp_file = os.path.join(POSSIBLE_TOPDIR,
- "keystone/content/%s.xml.tpl" % file)
- resp.content_type = "application/xml"
- else:
- resp_file = os.path.join(POSSIBLE_TOPDIR,
- "keystone/content/%s.json.tpl" % file)
- resp.content_type = "application/json"
-
- hostname = req.environ.get("SERVER_NAME")
- port = req.environ.get("SERVER_PORT")
- if 'HTTPS' in req.environ:
- protocol = 'https'
- else:
- protocol = 'http'
-
- resp.unicode_body = template.template(resp_file,
- PROTOCOL=protocol,
- HOST=hostname,
- PORT=port,
- API_VERSION=version.API_VERSION,
- API_VERSION_STATUS=version.API_VERSION_STATUS,
- API_VERSION_DATE=version.API_VERSION_DATE,
- RESOURCE_PATH=path
- )
-
- return resp
diff --git a/keystone/exception.py b/keystone/exception.py
new file mode 100644
index 00000000..c2f32afa
--- /dev/null
+++ b/keystone/exception.py
@@ -0,0 +1,58 @@
+import re
+
+
+class Error(StandardError):
+ """Base error class.
+
+ Child classes should define an HTTP status code, title, and a doc string.
+
+ """
+ code = None
+ title = None
+
+ def __init__(self, message=None, **kwargs):
+ """Use the doc string as the error message by default."""
+ message = message or self.__doc__ % kwargs
+ super(Error, self).__init__(message)
+
+ def __str__(self):
+ """Cleans up line breaks and indentation from doc strings."""
+ string = super(Error, self).__str__()
+ string = re.sub('[ \n]+', ' ', string)
+ string = string.strip()
+ return string
+
+
+class ValidationError(Error):
+ """Expecting to find %(attribute)s in %(target)s.
+
+ The server could not comply with the request since it is either malformed
+ or otherwise incorrect.
+
+ The client is assumed to be in error.
+
+ """
+ code = 400
+ title = 'Bad Request'
+
+
+class Unauthorized(Error):
+ """The request you have made requires authentication."""
+ code = 401
+ title = 'Not Authorized'
+
+
+class Forbidden(Error):
+ """You are not authorized to perform the requested action: %(action)s"""
+ code = 403
+ title = 'Not Authorized'
+
+
+class NotFound(Error):
+ """Could not find: %(target)s"""
+ code = 404
+ title = 'Not Found'
+
+
+class TokenNotFound(NotFound):
+ """Could not find token: %(token_id)s"""
diff --git a/keystone/frontends/__init__.py b/keystone/frontends/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/frontends/__init__.py
+++ /dev/null
diff --git a/keystone/frontends/d5_compat.py b/keystone/frontends/d5_compat.py
deleted file mode 100644
index 46395db7..00000000
--- a/keystone/frontends/d5_compat.py
+++ /dev/null
@@ -1,455 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-"""
-D5 API Compatibility Module
-
-This WSGI component adds support for the D5 API contract. That contract was
-an unofficial contract that made it into live deployments in the wild, so
-this middleware is an attempt to support production deployemnts of that
-code and allow them to interoperate with Keystone trunk while gradually moving
-to updated Keystone code.
-
-The middleware transforms responses in this way:
-- POST /tokens that come in D5 format (not wrapped in "auth":{}) will receive
- a D5 formatted response (wrapped in "auth":{} instead of "access":{})
-- GET /tokens/{id} will respond with both an "auth" and an "access" wrapper
- (since we can't tell if the caller is expecting a D5 or Diablo final
- response)
-
-Notes:
-- GET /tokens will not repond in D5 syntax in XML (because only one root
- can exist in XML and I chose not to break Diablo)
-- This relies on the URL normalizer (middlewre/url.py) to set
- KEYSTONE_API_VERSION. Without that set to '2.0', this middleware does
- nothing
-"""
-
-import copy
-import json
-import logging
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-try:
- from lxml import etree
-except ImportError as exc:
- logging.exception(exc)
- raise exc
-from webob.exc import Request
-
-from keystone.logic.types import fault
-import keystone.utils as utils
-
-PROTOCOL_NAME = "D5 API Compatibility"
-
-
-class D5AuthBase(object):
- """ Handles validating json and XML syntax of auth requests """
-
- def __init__(self, tenant_id=None, tenant_name=None):
- self.tenant_id = tenant_id
- self.tenant_name = tenant_name
-
- @staticmethod
- def _validate_auth(obj, *valid_keys):
- root = obj.keys()[0]
-
- for key in root:
- if not key in valid_keys:
- logger.debug("Invalid attribute: " % key)
- raise fault.BadRequestFault('Invalid attribute(s): %s' % key)
-
- if root.get('tenantId') and root.get('tenantName'):
- msg = _('Expecting either Tenant ID or Tenant Name, but not both')
- logger.debug(msg)
- raise fault.BadRequestFault(msg)
-
- return root
-
- @staticmethod
- def _validate_key(obj, key, required_keys, optional_keys):
- if not key in obj:
- raise fault.BadRequestFault('Expecting %s' % key)
-
- ret = obj[key]
-
- for skey in ret:
- if not skey in required_keys and not skey in optional_keys:
- msg = _('Invalid attribute(s): %s' % skey)
- logger.debug(msg)
- raise fault.BadRequestFault(msg)
-
- for required_key in required_keys:
- if not ret.get(required_key):
- msg = _('Expecting %s:%s' % (key, required_key))
- logger.debug(msg)
- raise fault.BadRequestFault(msg)
- return ret
-
-
-class D5AuthWithPasswordCredentials(D5AuthBase):
- def __init__(self, username, password, tenant_id=None, tenant_name=None):
- super(D5AuthWithPasswordCredentials, self).__init__(tenant_id,
- tenant_name)
- self.username = username
- self.password = password
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- password_credentials = \
- dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "passwordCredentials")
- if password_credentials is None:
- raise fault.BadRequestFault("Expecting passwordCredentials")
- tenant_id = password_credentials.get("tenantId")
- tenant_name = password_credentials.get("tenantName")
- username = password_credentials.get("username")
- utils.check_empty_string(username, "Expecting a username")
- password = password_credentials.get("password")
- utils.check_empty_string(password, "Expecting a password")
-
- if tenant_id and tenant_name:
- msg = _("Expecting either Tenant ID or Tenant Name, but not "
- "both")
- logger.debug(msg)
- raise fault.BadRequestFault(msg)
-
- return D5AuthWithPasswordCredentials(username, password,
- tenant_id, tenant_name)
- except etree.LxmlError as e:
- msg = _("Cannot parse passwordCredentials")
- logger.debug(msg)
- raise fault.BadRequestFault(msg, str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
-
- cred = D5AuthBase._validate_key(obj, 'passwordCredentials',
- required_keys=['username', 'password'],
- optional_keys=['tenantId', 'tenantName'])
-
- return D5AuthWithPasswordCredentials(cred['username'],
- cred['password'],
- cred.get('tenantId'),
- cred.get('tenantName'))
- except (ValueError, TypeError) as e:
- msg = _("Cannot parse passwordCredentials")
- logger.debug(msg)
- raise fault.BadRequestFault(msg, str(e))
-
- def to_json(self):
- """ Format the response in Diablo/Stable contract format """
- data = {"auth": {"passwordCredentials": {
- "username": self.username,
- "password": self.password}}}
- if self.tenant_id:
- data["auth"]["tenantId"] = self.tenant_id
- else:
- if self.tenant_name:
- data["auth"]["tenant_name"] = self.tenant_name
- return json.dumps(data)
-
- def to_xml(self):
- """ Format the response in Diablo/Stable contract format """
- dom = etree.Element("auth",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
-
- password_credentials = etree.Element("passwordCredentials",
- username=self.username,
- password=self.password)
-
- if self.tenant_id:
- dom.set("tenantId", self.tenant_id)
- else:
- if self.tenant_name:
- dom.set("tenant_name", self.tenant_name)
-
- dom.append(password_credentials)
-
- return etree.tostring(dom)
-
-
-class D5toDiabloAuthData(object):
- """Authentation Information returned upon successful login.
-
- This class handles rendering to JSON and XML. It renders
- the token, the user data, the roles, and the service catalog.
- """
- xml = None
- json = None
-
- def __init__(self, init_json=None, init_xml=None):
- if init_json:
- logger.debug("init D5toDiabloAuthData with json")
- self.json = init_json
- if init_xml is not None:
- logger.debug("init D5toDiabloAuthData with xml")
- self.xml = init_xml
-
- @staticmethod
- def from_xml(xml_str):
- """ Verify Diablo syntax and return class initialized with data"""
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = \
- dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "access")
- if root is None:
- logger.debug("Expecting access")
- raise fault.BadRequestFault("Expecting access")
- return D5toDiabloAuthData(init_xml=root)
- except etree.LxmlError as e:
- msg = _("Cannot parse Diablo response")
- logger.debug(msg)
- raise fault.BadRequestFault(msg, str(e))
-
- @staticmethod
- def from_json(json_str):
- """ Verify Diablo syntax and return class initialized with data"""
- try:
- obj = json.loads(json_str)
- auth = obj["access"]
- return D5toDiabloAuthData(init_json=auth)
- except (ValueError, TypeError) as e:
- msg = _("Cannot parse auth response")
- logger.debug(msg)
- raise fault.BadRequestFault(msg, str(e))
-
- def to_xml(self):
- """ Convert to D5 syntax from Diablo"""
- if self.xml is None:
- if self.json is None:
- logger.debug("Cannot deserialize response since no json or xml"
- "data seems to have been passed in")
- raise NotImplementedError
- else:
- msg = _("%s initialized with json, but xml requested" %
- self.__class__.__str__)
- logger.debug(msg)
- raise fault.IdentityFault(msg)
- dom = etree.Element("auth",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- for element in self.xml:
- dom.append(element)
- return etree.tostring(dom)
-
- def to_json(self):
- """ Convert to D5 syntax from Diablo"""
- if self.json is None:
- if self.xml is None:
- logger.debug("Cannot deserialize response since no json or xml"
- "data seems to have been passed in")
- raise NotImplementedError
- else:
- msg = _("%s initialized with xml, but json requested" %
- self.__class__.__str__)
- logger.debug(msg)
- raise fault.IdentityFault(msg)
- d5_data = {"auth": self.json.copy()}
- if 'auth' in d5_data and 'serviceCatalog' in d5_data['auth']:
- d5_data['auth']['serviceCatalog'] = \
- dict([(s['type'], s['endpoints'])
- for s in d5_data['auth']['serviceCatalog']])
-
- return json.dumps(d5_data)
-
-
-class D5ValidateData(object):
- """Authentation Information returned upon successful token validation."""
- xml = None
- json = None
-
- def __init__(self, init_json=None, init_xml=None):
- if init_json:
- self.json = init_json
- if init_xml is not None:
- self.xml = init_xml
-
- @staticmethod
- def from_xml(xml_str):
- """ Verify Diablo syntax and return class initialized with data"""
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = \
- dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "access")
- if root is None:
- logger.debug("Expecting 'access' element")
- raise fault.BadRequestFault("Expecting access")
- return D5ValidateData(init_xml=root)
- except etree.LxmlError as e:
- msg = _("Cannot parse Diablo response")
- logger.debug(msg)
- raise fault.BadRequestFault(msg, str(e))
-
- @staticmethod
- def from_json(json_str):
- """ Verify Diablo syntax and return class initialized with data"""
- try:
- obj = json.loads(json_str)
- return D5ValidateData(init_json=obj)
- except (ValueError, TypeError) as e:
- msg = _("Cannot parse Diablo response")
- logger.debug(msg)
- raise fault.BadRequestFault(msg, str(e))
-
- def to_xml(self):
- """ Returns only Diablo syntax (can only have one root in XML)
-
- This middleware is designed to provide D5 compatibility but NOT
- at the expense of breaking the Diablo contract."""
- if self.xml is None:
- if self.json is None:
- logger.debug("Cannot deserialize response since no json or xml"
- "data seems to have been passed in")
- raise NotImplementedError
- else:
- msg = _("%s initialized with json, but xml requested" %
- self.__class__.__str__)
- logger.debug(msg)
- raise fault.IdentityFault(msg)
- return etree.tostring(self.xml)
-
- def to_json(self):
- """ Returns both Diablo and D5 syntax ("access" and "auth")"""
- if self.json is None:
- if self.xml is None:
- logger.debug("Cannot deserialize response since no json or xml"
- "data seems to have been passed in")
- raise NotImplementedError
- else:
- msg = _("%s initialized with xml, but json requested" %
- self.__class__.__str__)
- logger.debug(msg)
- raise fault.IdentityFault(msg)
- d5_data = self.json.copy()
- auth = {}
- for key, value in self.json["access"].iteritems():
- auth[key] = copy.copy(value)
- if "user" in auth:
- # D5 returns 'username' only
- user = auth["user"]
- user["username"] = user["name"]
- del user["name"]
- del user["id"]
-
- # D5 has 'tenantId' under token
- token = auth["token"]
- if 'tenant' in token:
- tenant = token["tenant"]
- token["tenantId"] = tenant["id"]
-
- if "roles" in auth["user"]:
- auth["user"]["roleRefs"] = []
- rolerefs = auth["user"]["roleRefs"]
- for role in auth["user"]["roles"]:
- ref = {}
- ref["id"] = role["id"]
- ref["roleId"] = role["name"]
- if "tenantId" in role:
- ref["tenantId"] = role["tenantId"]
- rolerefs.append(ref)
- del auth["user"]["roles"]
- d5_data["auth"] = auth
-
- return json.dumps(d5_data)
-
-
-class D5AuthProtocol(object):
- """D5 Cmpatibility Middleware that transforms client calls and responses"""
-
- def __init__(self, app, conf):
- """ Common initialization code """
- msg = _("Starting the %s component" % PROTOCOL_NAME)
- logger.info(msg)
- self.conf = conf
- self.app = app
-
- def __call__(self, env, start_response):
- """ Handle incoming request. Transform. And send downstream. """
- logger.debug("Entering D5AuthProtocol.__call__")
- request = Request(env)
- if 'KEYSTONE_API_VERSION' in env and \
- env['KEYSTONE_API_VERSION'] == '2.0':
- if request.path.startswith("/tokens"):
- is_d5_request = False
- if request.method == "POST":
- try:
- auth_with_credentials = \
- utils.get_normalized_request_content(
- D5AuthWithPasswordCredentials, request)
- # Convert request body to Diablo syntax
- if request.content_type == "application/xml":
- request.body = auth_with_credentials.to_xml()
- else:
- request.body = auth_with_credentials.to_json()
- is_d5_request = True
- logger.warn("Detected a D5-formatted call")
- except:
- pass
-
- if is_d5_request:
- response = request.get_response(self.app)
- #Handle failures.
- if not str(response.status).startswith('20'):
- return response(env, start_response)
- logger.warn("Responding in D5-format")
- auth_data = utils.get_normalized_request_content(
- D5toDiabloAuthData, response)
- resp = utils.send_result(response.status_int, request,
- auth_data)
- return resp(env, start_response)
- else:
- # Pass through
- return self.app(env, start_response)
-
- elif request.method == "GET":
- if request.path.endswith("/endpoints"):
- # Pass through
- return self.app(env, start_response)
- else:
- response = request.get_response(self.app)
- #Handle failures.
- if not str(response.status).startswith('20'):
- return response(env, start_response)
- logger.warn("Adding D5-format to call validate call")
- validate_data = utils.get_normalized_request_content(
- D5ValidateData, response)
- resp = utils.send_result(response.status_int, request,
- validate_data)
- return resp(env, start_response)
-
- # All other calls pass to downstream WSGI component
- return self.app(env, start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(wsgiapp):
- """Closure to return"""
- return D5AuthProtocol(wsgiapp, conf)
- return auth_filter
diff --git a/keystone/frontends/legacy_token_auth.py b/keystone/frontends/legacy_token_auth.py
deleted file mode 100644
index a63395d5..00000000
--- a/keystone/frontends/legacy_token_auth.py
+++ /dev/null
@@ -1,126 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-"""
-RACKSPACE LEGACY AUTH - STUB
-
-This WSGI component
-- transforms rackspace auth header credentials to keystone credentials
-and makes an authentication call on keystone.- transforms response it
-receives into custom headers defined in properties and returns
-the response.
-"""
-
-import ast
-import json
-import logging
-from webob.exc import Request
-
-import keystone.utils as utils
-
-PROTOCOL_NAME = "Legacy Authentication"
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class AuthProtocol(object):
- """Legacy Auth Middleware that handles authenticating client calls"""
-
- def __init__(self, app, conf):
- """ Common initialization code """
- msg = _("Starting the %s component" % PROTOCOL_NAME)
- logger.info(msg)
- self.conf = conf
- self.app = app
-
- # Handle 1.0 and 1.1 calls via middleware.
- # Right now I am treating every call of 1.0 and 1.1 as call
- # to authenticate
- def __call__(self, env, start_response):
- """ Handle incoming request. Transform. And send downstream. """
- logger.debug("Entering AuthProtocol.__call__")
- request = Request(env)
- if env.get('KEYSTONE_API_VERSION') in ['1.0', '1.1']:
- logger.debug("This is a v%s call, so taking over" %
- env.get('KEYSTONE_API_VERSION'))
- params = {"auth": {"passwordCredentials":
- {"username": utils.get_auth_user(request),
- "password": utils.get_auth_key(request)}}}
- #Make request to keystone
- new_request = Request.blank('/tokens')
- new_request.method = 'POST'
- new_request.headers['Content-type'] = 'application/json'
- new_request.accept = 'application/json'
- new_request.body = json.dumps(params)
- logger.debug("Sending v2.0-formatted request downstream")
- response = new_request.get_response(self.app)
- logger.debug("Got back %s" % response.status)
- #Handle failures.
- if not str(response.status).startswith('20'):
- return response(env, start_response)
- headers = self.__transform_headers(
- json.loads(response.body))
- logger.debug("Transformed the response. Responding to v1.x client")
- resp = utils.send_legacy_result(204, headers)
- return resp(env, start_response)
- else:
- logger.debug("Not a v1.0/v1.1 call, so passing downstream")
- return self.app(env, start_response)
-
- def __transform_headers(self, content):
- """Transform Keystone auth to legacy headers"""
- headers = {}
- if "access" in content:
- auth = content["access"]
- if "token" in auth:
- headers["X-Auth-Token"] = auth["token"]["id"]
- if "serviceCatalog" in auth:
- services = auth["serviceCatalog"]
- service_mappings = ast.literal_eval(
- self.conf.get("service_header_mappings",
- self.conf["service-header-mappings"]))
- for service in services:
- service_name = service["name"]
- service_urls = ''
- for endpoint in service["endpoints"]:
- if len(service_urls) > 0:
- service_urls += ','
- service_urls += endpoint["publicURL"]
- if len(service_urls) > 0:
- if service_mappings.get(service_name):
- headers[service_mappings.get(
- service_name)] = service_urls
- else:
- #For Services that are not mapped,
- #use X- prefix followed by service name.
- header = 'X-%s' % service_name.upper()
- logger.debug("Adding header to response: %s=%s" %
- (header, service_urls))
- headers[header] = service_urls
- return headers
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- """Closure to return"""
- return AuthProtocol(app, conf)
- return auth_filter
diff --git a/keystone/frontends/normalizer.py b/keystone/frontends/normalizer.py
deleted file mode 100644
index 6c2246b5..00000000
--- a/keystone/frontends/normalizer.py
+++ /dev/null
@@ -1,212 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010 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.
-
-
-"""
-Auth Middleware that accepts URL query extension.
-
-This module can be installed as a filter in front of your service to
-detect extension in the resource URI (e.g., foo/resource.xml) to
-specify HTTP response body type. If an extension is specified, it
-overwrites the Accept header in the request, if present.
-
-"""
-
-import logging
-import webob.acceptparse
-from webob import Request
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-# Maps supported URL prefixes to API_VERSION
-PATH_PREFIXES = {
- '/v2.0': '2.0',
- '/v1.1': '1.1',
- '/v1.0': '1.0'}
-
-# Maps supported URL extensions to RESPONSE_ENCODING
-PATH_SUFFIXES = {
- '.json': 'json',
- '.xml': 'xml',
- '.atom': 'atom+xml'}
-
-# Maps supported Accept headers to RESPONSE_ENCODING and API_VERSION
-ACCEPT_HEADERS = {
- 'application/vnd.openstack.identity+json;version=2.0': ('json', '2.0'),
- 'application/vnd.openstack.identity+xml;version=2.0': ('xml', '2.0'),
- 'application/vnd.openstack.identity-v2.0+json': ('json', '2.0'),
- 'application/vnd.openstack.identity-v2.0+xml': ('xml', '2.0'),
- 'application/vnd.openstack.identity+json;version=1.1': ('json', '1.1'),
- 'application/vnd.openstack.identity+xml;version=1.1': ('xml', '1.1'),
- 'application/vnd.openstack.identity-v1.1+json': ('json', '1.1'),
- 'application/vnd.openstack.identity-v1.1+xml': ('xml', '1.1'),
- 'application/vnd.openstack.identity-v1.0+json': ('json', '1.0'),
- 'application/vnd.openstack.identity-v1.0+xml': ('xml', '1.0'),
- 'application/vnd.openstack.identity+json;version=1.0': ('json', '1.0'),
- 'application/vnd.openstack.identity+xml;version=1.0': ('xml', '1.0'),
- 'application/json': ('json', None),
- 'application/xml': ('xml', None),
- 'application/atom+xml': ('atom+xml', None)}
-
-DEFAULT_RESPONSE_ENCODING = 'json'
-PROTOCOL_NAME = "URL Normalizer"
-
-
-class NormalizingFilter(object):
- """Middleware filter to handle URL and Accept header normalization"""
-
- def __init__(self, app, conf):
- msg = "Starting the %s component" % PROTOCOL_NAME
- logger.info(msg)
- # app is the next app in WSGI chain - eventually the OpenStack service
- self.app = app
- self.conf = conf
-
- def __call__(self, env, start_response):
- # Inspect the request for mime type and API version
- env = normalize_accept_header(env)
- env = normalize_path_prefix(env)
- env = normalize_path_suffix(env)
- env['PATH_INFO'] = normalize_starting_slash(env.get('PATH_INFO'))
- env['PATH_INFO'] = normalize_trailing_slash(env['PATH_INFO'])
-
- # Fall back on defaults, if necessary
- env['KEYSTONE_RESPONSE_ENCODING'] = env.get(
- 'KEYSTONE_RESPONSE_ENCODING') or DEFAULT_RESPONSE_ENCODING
- env['HTTP_ACCEPT'] = 'application/' + (env.get(
- 'KEYSTONE_RESPONSE_ENCODING') or DEFAULT_RESPONSE_ENCODING)
-
- if 'KEYSTONE_API_VERSION' not in env:
- # Version was not specified in path or headers
- # return multiple choice unless the version controller can handle
- # this request
- if env['PATH_INFO'] not in ['/', '']:
- logger.debug("Call without a version - returning 300. Path=%s"
- % env.get('PATH_INFO', ''))
- from keystone.controllers.version import VersionController
- controller = VersionController()
- response = controller.get_multiple_choice(req=Request(env),
- file='multiple_choice')
- return response(env, start_response)
-
- return self.app(env, start_response)
-
-
-def normalize_accept_header(env):
- """Matches the preferred Accept encoding to supported encodings.
-
- Sets KEYSTONE_RESPONSE_ENCODING and KEYSTONE_API_VERSION, if appropriate.
-
- Note:: webob.acceptparse ignores ';version=' values
- """
- accept_value = env.get('HTTP_ACCEPT')
-
- if accept_value:
- if accept_value in ACCEPT_HEADERS.keys():
- logger.debug("Found direct match for mimetype %s" % accept_value)
- best_accept = accept_value
- else:
- try:
- accept = webob.acceptparse.Accept(accept_value)
- except TypeError:
- logger.warn("Falling back to `webob` v1.1 and older support. "
- "Check your version of webob")
- accept = webob.acceptparse.Accept('Accept', accept_value)
-
- best_accept = accept.best_match(ACCEPT_HEADERS.keys())
-
- if best_accept:
- response_encoding, api_version = ACCEPT_HEADERS[best_accept]
- logger.debug('%s header matched with %s (API=%s, TYPE=%s)',
- accept_value, best_accept, api_version,
- response_encoding)
-
- if response_encoding:
- env['KEYSTONE_RESPONSE_ENCODING'] = response_encoding
-
- if api_version:
- env['KEYSTONE_API_VERSION'] = api_version
- else:
- logger.debug('%s header could not be matched', accept_value)
-
- return env
-
-
-def normalize_path_prefix(env):
- """Handles recognized PATH_INFO prefixes.
-
- Looks for a version prefix on the PATH_INFO, sets KEYSTONE_API_VERSION
- accordingly, and removes the prefix to normalize the request."""
- for prefix in PATH_PREFIXES.keys():
- if env['PATH_INFO'].startswith(prefix):
- env['KEYSTONE_API_VERSION'] = PATH_PREFIXES[prefix]
- env['PATH_INFO'] = env['PATH_INFO'][len(prefix):]
- break
-
- return env
-
-
-def normalize_path_suffix(env):
- """Hnadles recognized PATH_INFO suffixes.
-
- Looks for a recognized suffix on the PATH_INFO, sets the
- KEYSTONE_RESPONSE_ENCODING accordingly, and removes the suffix to normalize
- the request."""
- for suffix in PATH_SUFFIXES.keys():
- if env['PATH_INFO'].endswith(suffix):
- env['KEYSTONE_RESPONSE_ENCODING'] = PATH_SUFFIXES[suffix]
- env['PATH_INFO'] = env['PATH_INFO'][:-len(suffix)]
- break
-
- return env
-
-
-def normalize_starting_slash(path_info):
- """Removes a trailing slash from the given path, if any."""
- # Ensure the path at least contains a slash
- if not path_info:
- return '/'
-
- # Ensure the path starts with a slash
- elif path_info[0] != '/':
- return '/' + path_info
-
- # No need to change anything
- else:
- return path_info
-
-
-def normalize_trailing_slash(path_info):
- """Removes a trailing slash from the given path, if any."""
- # Remove trailing slash, unless it's the only char
- if len(path_info) > 1 and path_info[-1] == '/':
- return path_info[:-1]
-
- # No need to change anything
- else:
- return path_info
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def ext_filter(app):
- return NormalizingFilter(app, conf)
- return ext_filter
diff --git a/keystone/identity/__init__.py b/keystone/identity/__init__.py
new file mode 100644
index 00000000..3a86d5a5
--- /dev/null
+++ b/keystone/identity/__init__.py
@@ -0,0 +1 @@
+from keystone.identity.core import *
diff --git a/keystone/contrib/extensions/admin/raxkey/__init__.py b/keystone/identity/backends/__init__.py
index e69de29b..e69de29b 100644
--- a/keystone/contrib/extensions/admin/raxkey/__init__.py
+++ b/keystone/identity/backends/__init__.py
diff --git a/keystone/identity/backends/kvs.py b/keystone/identity/backends/kvs.py
new file mode 100644
index 00000000..7dfc8633
--- /dev/null
+++ b/keystone/identity/backends/kvs.py
@@ -0,0 +1,222 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from keystone import identity
+from keystone.common import kvs
+from keystone.common import utils
+
+
+def _filter_user(user_ref):
+ if user_ref:
+ user_ref = user_ref.copy()
+ user_ref.pop('password', None)
+ user_ref.pop('tenants', None)
+ return user_ref
+
+
+def _ensure_hashed_password(user_ref):
+ pw = user_ref.get('password', None)
+ if pw is not None:
+ user_ref['password'] = utils.hash_password(pw)
+ return user_ref
+
+
+class Identity(kvs.Base, identity.Driver):
+ # Public interface
+ def authenticate(self, user_id=None, tenant_id=None, password=None):
+ """Authenticate based on a user, tenant and password.
+
+ Expects the user object to have a password field and the tenant to be
+ in the list of tenants on the user.
+
+ """
+ user_ref = self._get_user(user_id)
+ tenant_ref = None
+ metadata_ref = None
+ if (not user_ref
+ or not utils.check_password(password, user_ref.get('password'))):
+ raise AssertionError('Invalid user / password')
+ if tenant_id and tenant_id not in user_ref['tenants']:
+ raise AssertionError('Invalid tenant')
+
+ tenant_ref = self.get_tenant(tenant_id)
+ if tenant_ref:
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ else:
+ metadata_ref = {}
+ return (_filter_user(user_ref), tenant_ref, metadata_ref)
+
+ def get_tenant(self, tenant_id):
+ tenant_ref = self.db.get('tenant-%s' % tenant_id)
+ return tenant_ref
+
+ def get_tenant_by_name(self, tenant_name):
+ tenant_ref = self.db.get('tenant_name-%s' % tenant_name)
+ return tenant_ref
+
+ def _get_user(self, user_id):
+ user_ref = self.db.get('user-%s' % user_id)
+ return user_ref
+
+ def _get_user_by_name(self, user_name):
+ user_ref = self.db.get('user_name-%s' % user_name)
+ return user_ref
+
+ def get_user(self, user_id):
+ return _filter_user(self._get_user(user_id))
+
+ def get_user_by_name(self, user_name):
+ return _filter_user(self._get_user_by_name(user_name))
+
+ def get_metadata(self, user_id, tenant_id):
+ return self.db.get('metadata-%s-%s' % (tenant_id, user_id))
+
+ def get_role(self, role_id):
+ role_ref = self.db.get('role-%s' % role_id)
+ return role_ref
+
+ def list_users(self):
+ user_ids = self.db.get('user_list', [])
+ return [self.get_user(x) for x in user_ids]
+
+ def list_roles(self):
+ role_ids = self.db.get('role_list', [])
+ return [self.get_role(x) for x in role_ids]
+
+ # These should probably be part of the high-level API
+ def add_user_to_tenant(self, tenant_id, user_id):
+ user_ref = self._get_user(user_id)
+ tenants = set(user_ref.get('tenants', []))
+ tenants.add(tenant_id)
+ self.update_user(user_id, {'tenants': list(tenants)})
+
+ def remove_user_from_tenant(self, tenant_id, user_id):
+ user_ref = self._get_user(user_id)
+ tenants = set(user_ref.get('tenants', []))
+ tenants.remove(tenant_id)
+ self.update_user(user_id, {'tenants': list(tenants)})
+
+ def get_tenants_for_user(self, user_id):
+ user_ref = self._get_user(user_id)
+ return user_ref.get('tenants', [])
+
+ def get_roles_for_user_and_tenant(self, user_id, tenant_id):
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ if not metadata_ref:
+ metadata_ref = {}
+ return metadata_ref.get('roles', [])
+
+ def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ if not metadata_ref:
+ metadata_ref = {}
+ roles = set(metadata_ref.get('roles', []))
+ roles.add(role_id)
+ metadata_ref['roles'] = list(roles)
+ self.update_metadata(user_id, tenant_id, metadata_ref)
+
+ def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ if not metadata_ref:
+ metadata_ref = {}
+ roles = set(metadata_ref.get('roles', []))
+ roles.remove(role_id)
+ metadata_ref['roles'] = list(roles)
+ self.update_metadata(user_id, tenant_id, metadata_ref)
+
+ # CRUD
+ def create_user(self, user_id, user):
+ if self.get_user(user_id):
+ raise Exception('Duplicate id')
+ if self.get_user_by_name(user['name']):
+ raise Exception('Duplicate name')
+ user = _ensure_hashed_password(user)
+ self.db.set('user-%s' % user_id, user)
+ self.db.set('user_name-%s' % user['name'], user)
+ user_list = set(self.db.get('user_list', []))
+ user_list.add(user_id)
+ self.db.set('user_list', list(user_list))
+ return user
+
+ def update_user(self, user_id, user):
+ if 'name' in user:
+ existing = self.db.get('user_name-%s' % user['name'])
+ if existing and user_id != existing['id']:
+ raise Exception('Duplicate name')
+ # get the old name and delete it too
+ old_user = self.db.get('user-%s' % user_id)
+ new_user = old_user.copy()
+ user = _ensure_hashed_password(user)
+ new_user.update(user)
+ new_user['id'] = user_id
+ self.db.delete('user_name-%s' % old_user['name'])
+ self.db.set('user-%s' % user_id, new_user)
+ self.db.set('user_name-%s' % new_user['name'], new_user)
+ return new_user
+
+ def delete_user(self, user_id):
+ old_user = self.db.get('user-%s' % user_id)
+ self.db.delete('user_name-%s' % old_user['name'])
+ self.db.delete('user-%s' % user_id)
+ user_list = set(self.db.get('user_list', []))
+ user_list.remove(user_id)
+ self.db.set('user_list', list(user_list))
+ return None
+
+ def create_tenant(self, tenant_id, tenant):
+ if self.get_tenant(tenant_id):
+ raise Exception('Duplicate id')
+ if self.get_tenant_by_name(tenant['name']):
+ raise Exception('Duplicate name')
+ self.db.set('tenant-%s' % tenant_id, tenant)
+ self.db.set('tenant_name-%s' % tenant['name'], tenant)
+ return tenant
+
+ def update_tenant(self, tenant_id, tenant):
+ if 'name' in tenant:
+ existing = self.db.get('tenant_name-%s' % tenant['name'])
+ if existing and tenant_id != existing['id']:
+ raise Exception('Duplicate name')
+ # get the old name and delete it too
+ old_tenant = self.db.get('tenant-%s' % tenant_id)
+ new_tenant = old_tenant.copy()
+ new_tenant['id'] = tenant_id
+ self.db.delete('tenant_name-%s' % old_tenant['name'])
+ self.db.set('tenant-%s' % tenant_id, new_tenant)
+ self.db.set('tenant_name-%s' % new_tenant['name'], new_tenant)
+ return tenant
+
+ def delete_tenant(self, tenant_id):
+ old_tenant = self.db.get('tenant-%s' % tenant_id)
+ self.db.delete('tenant_name-%s' % old_tenant['name'])
+ self.db.delete('tenant-%s' % tenant_id)
+ return None
+
+ def create_metadata(self, user_id, tenant_id, metadata):
+ self.db.set('metadata-%s-%s' % (tenant_id, user_id), metadata)
+ return metadata
+
+ def update_metadata(self, user_id, tenant_id, metadata):
+ self.db.set('metadata-%s-%s' % (tenant_id, user_id), metadata)
+ return metadata
+
+ def delete_metadata(self, user_id, tenant_id):
+ self.db.delete('metadata-%s-%s' % (tenant_id, user_id))
+ return None
+
+ def create_role(self, role_id, role):
+ self.db.set('role-%s' % role_id, role)
+ role_list = set(self.db.get('role_list', []))
+ role_list.add(role_id)
+ self.db.set('role_list', list(role_list))
+ return role
+
+ def update_role(self, role_id, role):
+ self.db.set('role-%s' % role_id, role)
+ return role
+
+ def delete_role(self, role_id):
+ self.db.delete('role-%s' % role_id)
+ role_list = set(self.db.get('role_list', []))
+ role_list.remove(role_id)
+ self.db.set('role_list', list(role_list))
+ return None
diff --git a/keystone/identity/backends/pam.py b/keystone/identity/backends/pam.py
new file mode 100644
index 00000000..d9606601
--- /dev/null
+++ b/keystone/identity/backends/pam.py
@@ -0,0 +1,29 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from __future__ import absolute_import
+
+import pam
+
+
+class PamIdentity(object):
+ """Very basic identity based on PAM.
+
+ Tenant is always the same as User, root user has admin role.
+ """
+
+ def authenticate(self, username, password, **kwargs):
+ if pam.authenticate(username, password):
+ metadata = {}
+ if username == 'root':
+ metadata['is_admin'] == True
+
+ tenant = {'id': username,
+ 'name': username}
+ user = {'id': username,
+ 'name': username}
+
+ return (tenant, user, metadata)
+
+ def get_tenants(self, username):
+ return [{'id': username,
+ 'name': username}]
diff --git a/keystone/identity/backends/sql.py b/keystone/identity/backends/sql.py
new file mode 100644
index 00000000..4918a942
--- /dev/null
+++ b/keystone/identity/backends/sql.py
@@ -0,0 +1,366 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import copy
+
+from keystone import identity
+from keystone.common import sql
+from keystone.common import utils
+from keystone.common.sql import migration
+
+
+def _filter_user(user_ref):
+ if user_ref:
+ user_ref.pop('password', None)
+ return user_ref
+
+
+def _ensure_hashed_password(user_ref):
+ pw = user_ref.get('password', None)
+ if pw is not None:
+ user_ref['password'] = utils.hash_password(pw)
+ return user_ref
+
+
+class User(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'user'
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(64), unique=True)
+ #password = sql.Column(sql.String(64))
+ extra = sql.Column(sql.JsonBlob())
+
+ @classmethod
+ def from_dict(cls, user_dict):
+ # shove any non-indexed properties into extra
+ extra = {}
+ for k, v in user_dict.copy().iteritems():
+ # TODO(termie): infer this somehow
+ if k not in ['id', 'name']:
+ extra[k] = user_dict.pop(k)
+
+ user_dict['extra'] = extra
+ return cls(**user_dict)
+
+ def to_dict(self):
+ extra_copy = self.extra.copy()
+ extra_copy['id'] = self.id
+ extra_copy['name'] = self.name
+ return extra_copy
+
+
+class Tenant(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'tenant'
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(64), unique=True)
+ extra = sql.Column(sql.JsonBlob())
+
+ @classmethod
+ def from_dict(cls, tenant_dict):
+ # shove any non-indexed properties into extra
+ extra = {}
+ for k, v in tenant_dict.copy().iteritems():
+ # TODO(termie): infer this somehow
+ if k not in ['id', 'name']:
+ extra[k] = tenant_dict.pop(k)
+
+ tenant_dict['extra'] = extra
+ return cls(**tenant_dict)
+
+ def to_dict(self):
+ extra_copy = copy.deepcopy(self.extra)
+ extra_copy['id'] = self.id
+ extra_copy['name'] = self.name
+ return extra_copy
+
+
+class Role(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'role'
+ id = sql.Column(sql.String(64), primary_key=True)
+ name = sql.Column(sql.String(64))
+
+
+class Metadata(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'metadata'
+ #__table_args__ = (
+ # sql.Index('idx_metadata_usertenant', 'user', 'tenant'),
+ # )
+
+ user_id = sql.Column(sql.String(64), primary_key=True)
+ tenant_id = sql.Column(sql.String(64), primary_key=True)
+ data = sql.Column(sql.JsonBlob())
+
+
+class UserTenantMembership(sql.ModelBase, sql.DictBase):
+ """Tenant membership join table."""
+ __tablename__ = 'user_tenant_membership'
+ user_id = sql.Column(sql.String(64),
+ sql.ForeignKey('user.id'),
+ primary_key=True)
+ tenant_id = sql.Column(sql.String(64),
+ sql.ForeignKey('tenant.id'),
+ primary_key=True)
+
+
+class Identity(sql.Base, identity.Driver):
+ # Internal interface to manage the database
+ def db_sync(self):
+ migration.db_sync()
+
+ # Identity interface
+ def authenticate(self, user_id=None, tenant_id=None, password=None):
+ """Authenticate based on a user, tenant and password.
+
+ Expects the user object to have a password field and the tenant to be
+ in the list of tenants on the user.
+
+ """
+ user_ref = self._get_user(user_id)
+ tenant_ref = None
+ metadata_ref = None
+ if (not user_ref
+ or not utils.check_password(password, user_ref.get('password'))):
+ raise AssertionError('Invalid user / password')
+
+ tenants = self.get_tenants_for_user(user_id)
+ if tenant_id and tenant_id not in tenants:
+ raise AssertionError('Invalid tenant')
+
+ tenant_ref = self.get_tenant(tenant_id)
+ if tenant_ref:
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ else:
+ metadata_ref = {}
+ return (_filter_user(user_ref), tenant_ref, metadata_ref)
+
+ def get_tenant(self, tenant_id):
+ session = self.get_session()
+ tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
+ if not tenant_ref:
+ return
+ return tenant_ref.to_dict()
+
+ def get_tenant_by_name(self, tenant_name):
+ session = self.get_session()
+ tenant_ref = session.query(Tenant).filter_by(name=tenant_name).first()
+ if not tenant_ref:
+ return
+ return tenant_ref.to_dict()
+
+ def _get_user(self, user_id):
+ session = self.get_session()
+ user_ref = session.query(User).filter_by(id=user_id).first()
+ if not user_ref:
+ return
+ return user_ref.to_dict()
+
+ def _get_user_by_name(self, user_name):
+ session = self.get_session()
+ user_ref = session.query(User).filter_by(name=user_name).first()
+ if not user_ref:
+ return
+ return user_ref.to_dict()
+
+ def get_user(self, user_id):
+ return _filter_user(self._get_user(user_id))
+
+ def get_user_by_name(self, user_name):
+ return _filter_user(self._get_user_by_name(user_name))
+
+ def get_metadata(self, user_id, tenant_id):
+ session = self.get_session()
+ metadata_ref = session.query(Metadata)\
+ .filter_by(user_id=user_id)\
+ .filter_by(tenant_id=tenant_id)\
+ .first()
+ return getattr(metadata_ref, 'data', None)
+
+ def get_role(self, role_id):
+ session = self.get_session()
+ role_ref = session.query(Role).filter_by(id=role_id).first()
+ return role_ref
+
+ def list_users(self):
+ session = self.get_session()
+ user_refs = session.query(User)
+ return [_filter_user(x.to_dict()) for x in user_refs]
+
+ def list_roles(self):
+ session = self.get_session()
+ role_refs = session.query(Role)
+ return list(role_refs)
+
+ # These should probably be part of the high-level API
+ def add_user_to_tenant(self, tenant_id, user_id):
+ session = self.get_session()
+ q = session.query(UserTenantMembership)\
+ .filter_by(user_id=user_id)\
+ .filter_by(tenant_id=tenant_id)
+ rv = q.first()
+ if rv:
+ return
+
+ with session.begin():
+ session.add(UserTenantMembership(user_id=user_id,
+ tenant_id=tenant_id))
+ session.flush()
+
+ def remove_user_from_tenant(self, tenant_id, user_id):
+ session = self.get_session()
+ membership_ref = session.query(UserTenantMembership)\
+ .filter_by(user_id=user_id)\
+ .filter_by(tenant_id=tenant_id)\
+ .first()
+ with session.begin():
+ session.delete(membership_ref)
+ session.flush()
+
+ def get_tenants_for_user(self, user_id):
+ session = self.get_session()
+ membership_refs = session.query(UserTenantMembership)\
+ .filter_by(user_id=user_id)\
+ .all()
+
+ return [x.tenant_id for x in membership_refs]
+
+ def get_roles_for_user_and_tenant(self, user_id, tenant_id):
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ if not metadata_ref:
+ metadata_ref = {}
+ return metadata_ref.get('roles', [])
+
+ def add_role_to_user_and_tenant(self, user_id, tenant_id, role_id):
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ is_new = False
+ if not metadata_ref:
+ is_new = True
+ metadata_ref = {}
+ roles = set(metadata_ref.get('roles', []))
+ roles.add(role_id)
+ metadata_ref['roles'] = list(roles)
+ if not is_new:
+ self.update_metadata(user_id, tenant_id, metadata_ref)
+ else:
+ self.create_metadata(user_id, tenant_id, metadata_ref)
+
+ def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
+ metadata_ref = self.get_metadata(user_id, tenant_id)
+ is_new = False
+ if not metadata_ref:
+ is_new = True
+ metadata_ref = {}
+ roles = set(metadata_ref.get('roles', []))
+ roles.remove(role_id)
+ metadata_ref['roles'] = list(roles)
+ if not is_new:
+ self.update_metadata(user_id, tenant_id, metadata_ref)
+ else:
+ self.create_metadata(user_id, tenant_id, metadata_ref)
+
+ # CRUD
+ def create_user(self, user_id, user):
+ user = _ensure_hashed_password(user)
+ session = self.get_session()
+ with session.begin():
+ user_ref = User.from_dict(user)
+ session.add(user_ref)
+ session.flush()
+ return user_ref.to_dict()
+
+ def update_user(self, user_id, user):
+ session = self.get_session()
+ with session.begin():
+ user_ref = session.query(User).filter_by(id=user_id).first()
+ old_user_dict = user_ref.to_dict()
+ user = _ensure_hashed_password(user)
+ for k in user:
+ old_user_dict[k] = user[k]
+ new_user = User.from_dict(old_user_dict)
+
+ user_ref.name = new_user.name
+ user_ref.extra = new_user.extra
+ session.flush()
+ return user_ref
+
+ def delete_user(self, user_id):
+ session = self.get_session()
+ user_ref = session.query(User).filter_by(id=user_id).first()
+ with session.begin():
+ session.delete(user_ref)
+ session.flush()
+
+ def create_tenant(self, tenant_id, tenant):
+ session = self.get_session()
+ with session.begin():
+ tenant_ref = Tenant.from_dict(tenant)
+ session.add(tenant_ref)
+ session.flush()
+ return tenant_ref.to_dict()
+
+ def update_tenant(self, tenant_id, tenant):
+ session = self.get_session()
+ with session.begin():
+ tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
+ old_tenant_dict = tenant_ref.to_dict()
+ for k in tenant:
+ old_tenant_dict[k] = tenant[k]
+ new_tenant = Tenant.from_dict(old_tenant_dict)
+
+ tenant_ref.name = new_tenant.name
+ tenant_ref.extra = new_tenant.extra
+ session.flush()
+ return tenant_ref
+
+ def delete_tenant(self, tenant_id):
+ session = self.get_session()
+ tenant_ref = session.query(Tenant).filter_by(id=tenant_id).first()
+ with session.begin():
+ session.delete(tenant_ref)
+ session.flush()
+
+ def create_metadata(self, user_id, tenant_id, metadata):
+ session = self.get_session()
+ with session.begin():
+ session.add(Metadata(user_id=user_id,
+ tenant_id=tenant_id,
+ data=metadata))
+ session.flush()
+ return metadata
+
+ def update_metadata(self, user_id, tenant_id, metadata):
+ session = self.get_session()
+ with session.begin():
+ metadata_ref = session.query(Metadata)\
+ .filter_by(user_id=user_id)\
+ .filter_by(tenant_id=tenant_id)\
+ .first()
+ data = metadata_ref.data.copy()
+ for k in metadata:
+ data[k] = metadata[k]
+ metadata_ref.data = data
+ session.flush()
+ return metadata_ref
+
+ def delete_metadata(self, user_id, tenant_id):
+ self.db.delete('metadata-%s-%s' % (tenant_id, user_id))
+ return None
+
+ def create_role(self, role_id, role):
+ session = self.get_session()
+ with session.begin():
+ session.add(Role(**role))
+ session.flush()
+ return role
+
+ def update_role(self, role_id, role):
+ session = self.get_session()
+ with session.begin():
+ role_ref = session.query(Role).filter_by(id=role_id).first()
+ for k in role:
+ role_ref[k] = role[k]
+ session.flush()
+ return role_ref
+
+ def delete_role(self, role_id):
+ session = self.get_session()
+ role_ref = session.query(Role).filter_by(id=role_id).first()
+ with session.begin():
+ session.delete(role_ref)
diff --git a/keystone/identity/core.py b/keystone/identity/core.py
new file mode 100644
index 00000000..66c2cdce
--- /dev/null
+++ b/keystone/identity/core.py
@@ -0,0 +1,537 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Main entry point into the Identity service."""
+
+import uuid
+import urllib
+import urlparse
+
+import webob.exc
+
+from keystone import catalog
+from keystone import config
+from keystone import exception
+from keystone import policy
+from keystone import token
+from keystone.common import manager
+from keystone.common import wsgi
+
+
+CONF = config.CONF
+
+
+class Manager(manager.Manager):
+ """Default pivot point for the Identity backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.identity.driver)
+
+
+class Driver(object):
+ """Interface description for an Identity driver."""
+
+ def authenticate(self, user_id=None, tenant_id=None, password=None):
+ """Authenticate a given user, tenant and password.
+
+ Returns: (user, tenant, metadata).
+
+ """
+ raise NotImplementedError()
+
+ def get_tenant(self, tenant_id):
+ """Get a tenant by id.
+
+ Returns: tenant_ref or None.
+
+ """
+ raise NotImplementedError()
+
+ def get_tenant_by_name(self, tenant_name):
+ """Get a tenant by name.
+
+ Returns: tenant_ref or None.
+
+ """
+ raise NotImplementedError()
+
+ def get_user(self, user_id):
+ """Get a user by id.
+
+ Returns: user_ref or None.
+
+ """
+ raise NotImplementedError()
+
+ def get_user_by_name(self, user_name):
+ """Get a user by name.
+
+ Returns: user_ref or None.
+
+ """
+ raise NotImplementedError()
+
+ def get_role(self, role_id):
+ """Get a role by id.
+
+ Returns: role_ref or None.
+
+ """
+ raise NotImplementedError()
+
+ def list_users(self):
+ """List all users in the system.
+
+ NOTE(termie): I'd prefer if this listed only the users for a given
+ tenant.
+
+ Returns: a list of user_refs or an empty list.
+
+ """
+ raise NotImplementedError()
+
+ def list_roles(self):
+ """List all roles in the system.
+
+ Returns: a list of role_refs or an empty list.
+
+ """
+ raise NotImplementedError()
+
+ # NOTE(termie): six calls below should probably be exposed by the api
+ # more clearly when the api redesign happens
+ def add_user_to_tenant(self, tenant_id, user_id):
+ raise NotImplementedError()
+
+ def remove_user_from_tenant(self, tenant_id, user_id):
+ raise NotImplementedError()
+
+ def get_tenants_for_user(self, user_id):
+ """Get the tenants associated with a given user.
+
+ Returns: a list of tenant ids.
+
+ """
+ raise NotImplementedError()
+
+ def get_roles_for_user_and_tenant(self, user_id, tenant_id):
+ """Get the roles associated with a user within given tenant.
+
+ Returns: a list of role ids.
+
+ """
+ raise NotImplementedError()
+
+ def add_role_for_user_and_tenant(self, user_id, tenant_id, role_id):
+ """Add a role to a user within given tenant."""
+ raise NotImplementedError()
+
+ def remove_role_from_user_and_tenant(self, user_id, tenant_id, role_id):
+ """Remove a role from a user within given tenant."""
+ raise NotImplementedError()
+
+ # user crud
+ def create_user(self, user_id, user):
+ raise NotImplementedError()
+
+ def update_user(self, user_id, user):
+ raise NotImplementedError()
+
+ def delete_user(self, user_id):
+ raise NotImplementedError()
+
+ # tenant crud
+ def create_tenant(self, tenant_id, tenant):
+ raise NotImplementedError()
+
+ def update_tenant(self, tenant_id, tenant):
+ raise NotImplementedError()
+
+ def delete_tenant(self, tenant_id, tenant):
+ raise NotImplementedError()
+
+ # metadata crud
+ def create_metadata(self, user_id, tenant_id, metadata):
+ raise NotImplementedError()
+
+ def update_metadata(self, user_id, tenant_id, metadata):
+ raise NotImplementedError()
+
+ def delete_metadata(self, user_id, tenant_id, metadata):
+ raise NotImplementedError()
+
+ # role crud
+ def create_role(self, role_id, role):
+ raise NotImplementedError()
+
+ def update_role(self, role_id, role):
+ raise NotImplementedError()
+
+ def delete_role(self, role_id):
+ raise NotImplementedError()
+
+
+class PublicRouter(wsgi.ComposableRouter):
+ def add_routes(self, mapper):
+ tenant_controller = TenantController()
+ mapper.connect('/tenants',
+ controller=tenant_controller,
+ action='get_tenants_for_token',
+ conditions=dict(methods=['GET']))
+
+
+class AdminRouter(wsgi.ComposableRouter):
+ def add_routes(self, mapper):
+ # Tenant Operations
+ tenant_controller = TenantController()
+ mapper.connect('/tenants',
+ controller=tenant_controller,
+ action='get_tenants_for_token',
+ conditions=dict(method=['GET']))
+ mapper.connect('/tenants/{tenant_id}',
+ controller=tenant_controller,
+ action='get_tenant',
+ conditions=dict(method=['GET']))
+
+ # User Operations
+ user_controller = UserController()
+ mapper.connect('/users/{user_id}',
+ controller=user_controller,
+ action='get_user',
+ conditions=dict(method=['GET']))
+
+ # Role Operations
+ roles_controller = RoleController()
+ mapper.connect('/tenants/{tenant_id}/users/{user_id}/roles',
+ controller=roles_controller,
+ action='get_user_roles',
+ conditions=dict(method=['GET']))
+ mapper.connect('/users/{user_id}/roles',
+ controller=user_controller,
+ action='get_user_roles',
+ conditions=dict(method=['GET']))
+
+
+class TenantController(wsgi.Application):
+ def __init__(self):
+ self.identity_api = Manager()
+ self.policy_api = policy.Manager()
+ self.token_api = token.Manager()
+ super(TenantController, self).__init__()
+
+ def get_tenants_for_token(self, context, **kw):
+ """Get valid tenants for token based on token used to authenticate.
+
+ Pulls the token from the context, validates it and gets the valid
+ tenants for the user in the token.
+
+ Doesn't care about token scopedness.
+
+ """
+ try:
+ token_ref = self.token_api.get_token(context=context,
+ token_id=context['token_id'])
+ except exception.NotFound:
+ raise exception.Unauthorized()
+
+ user_ref = token_ref['user']
+ tenant_ids = self.identity_api.get_tenants_for_user(
+ context, user_ref['id'])
+ tenant_refs = []
+ for tenant_id in tenant_ids:
+ tenant_refs.append(self.identity_api.get_tenant(
+ context=context,
+ tenant_id=tenant_id))
+ params = {
+ 'limit': context['query_string'].get('limit'),
+ 'marker': context['query_string'].get('marker'),
+ }
+ return self._format_tenant_list(tenant_refs, **params)
+
+ def get_tenant(self, context, tenant_id):
+ # TODO(termie): this stuff should probably be moved to middleware
+ self.assert_admin(context)
+ tenant = self.identity_api.get_tenant(context, tenant_id)
+ if not tenant:
+ return webob.exc.HTTPNotFound()
+ return {'tenant': tenant}
+
+ # CRUD Extension
+ def create_tenant(self, context, tenant):
+ tenant_ref = self._normalize_dict(tenant)
+ self.assert_admin(context)
+ tenant_id = (tenant_ref.get('id')
+ and tenant_ref.get('id')
+ or uuid.uuid4().hex)
+ tenant_ref['id'] = tenant_id
+
+ tenant = self.identity_api.create_tenant(
+ context, tenant_id, tenant_ref)
+ return {'tenant': tenant}
+
+ def update_tenant(self, context, tenant_id, tenant):
+ self.assert_admin(context)
+ tenant_ref = self.identity_api.update_tenant(
+ context, tenant_id, tenant)
+ return {'tenant': tenant_ref}
+
+ def delete_tenant(self, context, tenant_id, **kw):
+ self.assert_admin(context)
+ self.identity_api.delete_tenant(context, tenant_id)
+
+ def get_tenant_users(self, context, **kw):
+ self.assert_admin(context)
+ raise NotImplementedError()
+
+ def _format_tenant_list(self, tenant_refs, **kwargs):
+ marker = kwargs.get('marker')
+ page_idx = 0
+ if marker is not None:
+ for (marker_idx, tenant) in enumerate(tenant_refs):
+ if tenant['id'] == marker:
+ # we start pagination after the marker
+ page_idx = marker_idx + 1
+ break
+ else:
+ msg = 'Marker could not be found'
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ limit = kwargs.get('limit')
+ if limit is not None:
+ try:
+ limit = int(limit)
+ assert limit >= 0
+ except (ValueError, AssertionError):
+ msg = 'Invalid limit value'
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+
+ tenant_refs = tenant_refs[page_idx:limit]
+
+ for x in tenant_refs:
+ x['enabled'] = True
+ o = {'tenants': tenant_refs,
+ 'tenants_links': []}
+ return o
+
+
+class UserController(wsgi.Application):
+ def __init__(self):
+ self.catalog_api = catalog.Manager()
+ self.identity_api = Manager()
+ self.policy_api = policy.Manager()
+ self.token_api = token.Manager()
+ super(UserController, self).__init__()
+
+ def get_user(self, context, user_id):
+ self.assert_admin(context)
+ user_ref = self.identity_api.get_user(context, user_id)
+ if not user_ref:
+ raise webob.exc.HTTPNotFound()
+ return {'user': user_ref}
+
+ def get_users(self, context):
+ # NOTE(termie): i can't imagine that this really wants all the data
+ # about every single user in the system...
+ self.assert_admin(context)
+ user_refs = self.identity_api.list_users(context)
+ return {'users': user_refs}
+
+ # CRUD extension
+ def create_user(self, context, user):
+ user = self._normalize_dict(user)
+ self.assert_admin(context)
+ tenant_id = user.get('tenantId', None)
+ user_id = uuid.uuid4().hex
+ user_ref = user.copy()
+ user_ref['id'] = user_id
+ new_user_ref = self.identity_api.create_user(
+ context, user_id, user_ref)
+ if tenant_id:
+ self.identity_api.add_user_to_tenant(tenant_id, user_id)
+ return {'user': new_user_ref}
+
+ def update_user(self, context, user_id, user):
+ # NOTE(termie): this is really more of a patch than a put
+ self.assert_admin(context)
+ user_ref = self.identity_api.update_user(context, user_id, user)
+ return {'user': user_ref}
+
+ def delete_user(self, context, user_id):
+ self.assert_admin(context)
+ self.identity_api.delete_user(context, user_id)
+
+ def set_user_enabled(self, context, user_id, user):
+ return self.update_user(context, user_id, user)
+
+ def set_user_password(self, context, user_id, user):
+ return self.update_user(context, user_id, user)
+
+ def update_user_tenant(self, context, user_id, user):
+ """Update the default tenant."""
+ # ensure that we're a member of that tenant
+ tenant_id = user.get('tenantId')
+ self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
+ return self.update_user(context, user_id, user)
+
+
+class RoleController(wsgi.Application):
+ def __init__(self):
+ self.catalog_api = catalog.Manager()
+ self.identity_api = Manager()
+ self.token_api = token.Manager()
+ self.policy_api = policy.Manager()
+ super(RoleController, self).__init__()
+
+ # COMPAT(essex-3)
+ def get_user_roles(self, context, user_id, tenant_id=None):
+ """Get the roles for a user and tenant pair.
+
+ Since we're trying to ignore the idea of user-only roles we're
+ not implementing them in hopes that the idea will die off.
+
+ """
+ if tenant_id is None:
+ raise Exception('User roles not supported: tenant_id required')
+ roles = self.identity_api.get_roles_for_user_and_tenant(
+ context, user_id, tenant_id)
+ return {'roles': [self.identity_api.get_role(context, x)
+ for x in roles]}
+
+ # CRUD extension
+ def get_role(self, context, role_id):
+ self.assert_admin(context)
+ role_ref = self.identity_api.get_role(context, role_id)
+ if not role_ref:
+ raise webob.exc.HTTPNotFound()
+ return {'role': role_ref}
+
+ def create_role(self, context, role):
+ role = self._normalize_dict(role)
+ self.assert_admin(context)
+ role_id = uuid.uuid4().hex
+ role['id'] = role_id
+ role_ref = self.identity_api.create_role(context, role_id, role)
+ return {'role': role_ref}
+
+ def delete_role(self, context, role_id):
+ self.assert_admin(context)
+ role_ref = self.identity_api.delete_role(context, role_id)
+
+ def get_roles(self, context):
+ self.assert_admin(context)
+ roles = self.identity_api.list_roles(context)
+ # TODO(termie): probably inefficient at some point
+ return {'roles': roles}
+
+ def add_role_to_user(self, context, user_id, role_id, tenant_id=None):
+ """Add a role to a user and tenant pair.
+
+ Since we're trying to ignore the idea of user-only roles we're
+ not implementing them in hopes that the idea will die off.
+
+ """
+ self.assert_admin(context)
+ if tenant_id is None:
+ raise Exception('User roles not supported: tenant_id required')
+
+ # This still has the weird legacy semantics that adding a role to
+ # a user also adds them to a tenant
+ self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
+ self.identity_api.add_role_to_user_and_tenant(
+ context, user_id, tenant_id, role_id)
+ role_ref = self.identity_api.get_role(context, role_id)
+ return {'role': role_ref}
+
+ def remove_role_from_user(self, context, user_id, role_id, tenant_id=None):
+ """Remove a role from a user and tenant pair.
+
+ Since we're trying to ignore the idea of user-only roles we're
+ not implementing them in hopes that the idea will die off.
+
+ """
+ self.assert_admin(context)
+ if tenant_id is None:
+ raise Exception('User roles not supported: tenant_id required')
+
+ # This still has the weird legacy semantics that adding a role to
+ # a user also adds them to a tenant
+ self.identity_api.remove_role_from_user_and_tenant(
+ context, user_id, tenant_id, role_id)
+ roles = self.identity_api.get_roles_for_user_and_tenant(
+ context, user_id, tenant_id)
+ if not roles:
+ self.identity_api.remove_user_from_tenant(
+ context, tenant_id, user_id)
+ return
+
+ # COMPAT(diablo): CRUD extension
+ def get_role_refs(self, context, user_id):
+ """Ultimate hack to get around having to make role_refs first-class.
+
+ This will basically iterate over the various roles the user has in
+ all tenants the user is a member of and create fake role_refs where
+ the id encodes the user-tenant-role information so we can look
+ up the appropriate data when we need to delete them.
+
+ """
+ self.assert_admin(context)
+ user_ref = self.identity_api.get_user(context, user_id)
+ tenant_ids = self.identity_api.get_tenants_for_user(context, user_id)
+ o = []
+ for tenant_id in tenant_ids:
+ role_ids = self.identity_api.get_roles_for_user_and_tenant(
+ context, user_id, tenant_id)
+ for role_id in role_ids:
+ ref = {'roleId': role_id,
+ 'tenantId': tenant_id,
+ 'userId': user_id}
+ ref['id'] = urllib.urlencode(ref)
+ o.append(ref)
+ return {'roles': o}
+
+ # COMPAT(diablo): CRUD extension
+ def create_role_ref(self, context, user_id, role):
+ """This is actually used for adding a user to a tenant.
+
+ In the legacy data model adding a user to a tenant required setting
+ a role.
+
+ """
+ self.assert_admin(context)
+ # TODO(termie): for now we're ignoring the actual role
+ tenant_id = role.get('tenantId')
+ role_id = role.get('roleId')
+ self.identity_api.add_user_to_tenant(context, tenant_id, user_id)
+ self.identity_api.add_role_to_user_and_tenant(
+ context, user_id, tenant_id, role_id)
+ role_ref = self.identity_api.get_role(context, role_id)
+ return {'role': role_ref}
+
+ # COMPAT(diablo): CRUD extension
+ def delete_role_ref(self, context, user_id, role_ref_id):
+ """This is actually used for deleting a user from a tenant.
+
+ In the legacy data model removing a user from a tenant required
+ deleting a role.
+
+ To emulate this, we encode the tenant and role in the role_ref_id,
+ and if this happens to be the last role for the user-tenant pair,
+ we remove the user from the tenant.
+
+ """
+ self.assert_admin(context)
+ # TODO(termie): for now we're ignoring the actual role
+ role_ref_ref = urlparse.parse_qs(role_ref_id)
+ tenant_id = role_ref_ref.get('tenantId')[0]
+ role_id = role_ref_ref.get('roleId')[0]
+ self.identity_api.remove_role_from_user_and_tenant(
+ context, user_id, tenant_id, role_id)
+ roles = self.identity_api.get_roles_for_user_and_tenant(
+ context, user_id, tenant_id)
+ if not roles:
+ self.identity_api.remove_user_from_tenant(
+ context, tenant_id, user_id)
diff --git a/keystone/logic/__init__.py b/keystone/logic/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/logic/__init__.py
+++ /dev/null
diff --git a/keystone/logic/extension_reader.py b/keystone/logic/extension_reader.py
deleted file mode 100644
index 79a7fd49..00000000
--- a/keystone/logic/extension_reader.py
+++ /dev/null
@@ -1,142 +0,0 @@
-# Copyright (c) 2011 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 os
-import json
-from lxml import etree
-
-from keystone import config
-from keystone import utils
-from keystone.contrib.extensions import CONFIG_EXTENSION_PROPERTY
-from keystone.contrib.extensions import DEFAULT_EXTENSIONS
-from keystone.logic.types.extension import Extensions
-
-EXTENSIONS_PATH = 'contrib/extensions'
-CONF = config.CONF
-
-
-def get_supported_extensions():
- """
- Returns list of supported extensions.
- """
- extensions = CONF[CONFIG_EXTENSION_PROPERTY] or DEFAULT_EXTENSIONS
- return [extension.strip() for extension in extensions]
-
-
-def is_extension_supported(extension_name):
- """
- Return True if the extension is enabled, False otherwise.
- extension_name - extension name
- extension_name is case-sensitive.
- """
- if extension_name is not None:
- return extension_name in get_supported_extensions()
- return False
-
-
-class ExtensionsReader(object):
- """Reader to read static extensions content"""
- def __init__(self, extension_prefix):
- self.extensions = None
- self.extension_prefix = extension_prefix
- self.root = None
- self.supported_extensions = None
- self.__init_extensions()
-
- def __init_extensions(self):
- self.extensions = Extensions(self.__get_json_extensions(),
- self.__get_xml_extensions())
-
- def __get_json_extensions(self):
- """ Initializes and returns all json static extension content."""
- body = self.__get_all_json_extensions()
- extensionsarray = body["extensions"]["values"]
- for supported_extension in self.__get_supported_extensions():
- thisextensionjson = self.__get_extension_json(
- supported_extension)
- if thisextensionjson is not None:
- extensionsarray.append(thisextensionjson)
- return json.dumps(body)
-
- def __get_xml_extensions(self):
- """ Initializes and returns all xml static extension content."""
- body = self.__get_all_xml_extensions()
- for supported_extension in self.__get_supported_extensions():
- thisextensionxml = self.__get_extension_xml(supported_extension)
- if thisextensionxml is not None:
- body.append(thisextensionxml)
- return etree.tostring(body)
-
- def __get_root(self):
- """ Returns application root.Has a local reference for reuse."""
- if self.root is None:
- self.root = utils.get_app_root()
- self.root = os.path.abspath(self.root) + os.sep
- return self.root
-
- def __get_file(self, resp_file):
- """ Helper get file method."""
- root = self.__get_root()
- filename = os.path.abspath(os.path.join(root, resp_file.strip('/\\')))
- return open(filename).read()
-
- def __get_all_json_extensions(self):
- """ Gets empty json extensions content to which specific
- extensions are added."""
- resp_file = "%s/%s.json" % (EXTENSIONS_PATH, 'extensions')
- allextensions = self.__get_file(resp_file)
- return json.loads(allextensions)
-
- def __get_all_xml_extensions(self):
- """ Gets empty xml extensions content
- to which specific extensions are added."""
- resp_file = "%s/%s.xml" % (EXTENSIONS_PATH, 'extensions')
- allextensions = self.__get_file(resp_file)
- return etree.fromstring(allextensions)
-
- def __get_supported_extensions(self):
- """ Returns list of supported extensions."""
- if self.supported_extensions is None:
- self.supported_extensions = get_supported_extensions()
- return self.supported_extensions
-
- def __get_extension_json(self, extension_name):
- """Returns specific extension's json content."""
- thisextension = self.__get_extension_file(extension_name, 'json')
- return thisextension if not thisextension\
- else json.loads(thisextension.read())
-
- def __get_extension_xml(self, extension_name):
- """Returns specific extension's xml content."""
- thisextension = self.__get_extension_file(extension_name, 'xml')
- return thisextension if not thisextension\
- else etree.parse(thisextension).getroot()
-
- def __get_extension_file(self, extension_name, request_type):
- """Returns specific static extension file."""
- try:
- extension_dir = "%s/%s/%s" % (EXTENSIONS_PATH,
- self.extension_prefix, extension_name)
- extension_dir = os.path.abspath(os.path.join(self.__get_root(),
- extension_dir.strip('/\\')))
- extension_file = open(os.path.join(extension_dir,
- "extension." + request_type))
- return extension_file
- except IOError:
- return None
-
- def get_extensions(self):
- """Return Extensions result."""
- return self.extensions
diff --git a/keystone/logic/service.py b/keystone/logic/service.py
deleted file mode 100755
index 9387464d..00000000
--- a/keystone/logic/service.py
+++ /dev/null
@@ -1,1558 +0,0 @@
-# Copyright (c) 2010-2011 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.
-#
-# pylint: disable=C0302,W0603,W0602
-
-from datetime import datetime, timedelta
-import functools
-import logging
-import uuid
-
-from keystone import config
-from keystone.logic.types import auth, atom
-from keystone.logic.signer import Signer
-import keystone.backends as backends
-import keystone.backends.models as models
-from keystone.logic.types import fault
-from keystone.logic.types.tenant import Tenants
-from keystone.logic.types.user import User, User_Update, Users
-from keystone.logic.types.endpoint import Endpoint, Endpoints, \
- EndpointTemplate, EndpointTemplates
-from keystone.logic.types.credential import Credentials, PasswordCredentials
-from keystone import utils
-# New imports as we refactor old backend design and models
-from keystone.models import Tenant, Token
-from keystone.models import Role, Roles
-from keystone.models import Service, Services
-from keystone.managers.token import Manager as TokenManager
-from keystone.managers.tenant import Manager as TenantManager
-from keystone.managers.user import Manager as UserManager
-from keystone.managers.role import Manager as RoleManager
-from keystone.managers.grant import Manager as GrantManager
-from keystone.managers.service import Manager as ServiceManager
-from keystone.managers.endpoint_template import Manager \
- as EndpointTemplateManager
-from keystone.managers.endpoint import Manager as EndpointManager
-from keystone.managers.credential import Manager as CredentialManager
-
-CONF = config.CONF
-
-#Reference to Admin Role.
-ADMIN_ROLE_ID = None
-ADMIN_ROLE_NAME = None
-SERVICE_ADMIN_ROLE_ID = None
-SERVICE_ADMIN_ROLE_NAME = None
-GLOBAL_SERVICE_ID = None # to facilitate global roles for validate tokens
-
-LOG = logging.getLogger(__name__)
-
-
-def admin_token_validator(fnc):
- """Decorator that applies the validate_admin_token() method."""
- @functools.wraps(fnc)
- def _wrapper(self, token_id, *args, **kwargs):
- self.validate_admin_token(token_id)
- return fnc(self, token_id, *args, **kwargs)
- return _wrapper
-
-
-def service_admin_token_validator(fnc):
- """Decorator that applies the validate_service_admin_token() method."""
- @functools.wraps(fnc)
- def _wrapper(self, token_id, *args, **kwargs):
- self.validate_service_admin_token(token_id)
- return fnc(self, token_id, *args, **kwargs)
- return _wrapper
-
-
-# pylint: disable=R0902
-class IdentityService(object):
- """Implements the Identity service
-
- This class handles all logic of routing requests to the correct
- backend as well as validating incoming/outgoing data
- """
-
- def __init__(self):
- """ Initialize
-
- Loads all necessary backends to handle incoming requests.
- """
- backends.configure_backends()
- self.token_manager = TokenManager()
- self.tenant_manager = TenantManager()
- self.user_manager = UserManager()
- self.role_manager = RoleManager()
- self.grant_manager = GrantManager()
- self.service_manager = ServiceManager()
- self.endpoint_template_manager = EndpointTemplateManager()
- self.endpoint_manager = EndpointManager()
- self.credential_manager = CredentialManager()
-
- # pylint: disable=W0603
- global ADMIN_ROLE_NAME
- ADMIN_ROLE_NAME = CONF.keystone_admin_role
-
- global SERVICE_ADMIN_ROLE_NAME
- SERVICE_ADMIN_ROLE_NAME = CONF.keystone_service_admin_role
-
- global GLOBAL_SERVICE_ID
- GLOBAL_SERVICE_ID = CONF.global_service_id or "global"
-
- LOG.debug("init with ADMIN_ROLE_NAME=%s, SERVICE_ADMIN_ROLE_NAME=%s, "
- "GLOBAL_SERVICE_ID=%s" % (ADMIN_ROLE_NAME,
- SERVICE_ADMIN_ROLE_NAME,
- GLOBAL_SERVICE_ID))
-
- #
- # Token Operations
- #
- def authenticate(self, auth_request):
- LOG.debug("Authenticating with passwordCredentials")
- if not isinstance(auth_request, auth.AuthWithPasswordCredentials):
- raise fault.BadRequestFault(
- "Expecting auth_with_password_credentials!")
-
- def validate(duser):
- return self.user_manager.check_password(duser.id,
- auth_request.password)
-
- if auth_request.tenant_name:
- dtenant = self.validate_tenant_by_name(auth_request.tenant_name)
- auth_request.tenant_id = dtenant.id
- elif auth_request.tenant_id:
- dtenant = self.validate_tenant_by_id(auth_request.tenant_id)
-
- user = self.user_manager.get_by_name(auth_request.username)
- if not user:
- LOG.debug("Did not find user with name=%s" % auth_request.username)
- raise fault.UnauthorizedFault("Unauthorized")
-
- return self._authenticate(validate, user.id, auth_request.tenant_id)
-
- def authenticate_with_unscoped_token(self, auth_request):
- LOG.debug("Authenticating with token (unscoped)")
- if not isinstance(auth_request, auth.AuthWithUnscopedToken):
- raise fault.BadRequestFault("Expecting auth_with_unscoped_token!")
-
- # We *should* check for an unscoped token here, but as long as
- # POST /tokens w/ credentials auto-scopes to User.tenantId, users can't
- # reach this flow.
- # _token, user = validate_unscoped_token(auth_request.token_id)
- _token, user = self._validate_token(auth_request.token_id)
-
- if auth_request.tenant_name:
- dtenant = self.validate_tenant_by_name(auth_request.tenant_name)
- auth_request.tenant_id = dtenant.id
- elif auth_request.tenant_id:
- dtenant = self.validate_tenant_by_id(auth_request.tenant_id)
-
- # pylint: disable=W0613
- def validate(duser):
- # The user is already authenticated
- return True
- return self._authenticate(validate, user.id, auth_request.tenant_id)
-
- def authenticate_ec2(self, credentials):
- LOG.debug("Authenticating with EC2 credentials")
- if not isinstance(credentials, auth.Ec2Credentials):
- raise fault.BadRequestFault("Expecting Ec2 Credentials!")
-
- creds = self.credential_manager.get_by_access(credentials.access)
- if not creds:
- raise fault.UnauthorizedFault("No credentials found for %s"
- % credentials.access)
-
- # pylint: disable=W0613
- def validate(duser):
- signer = Signer(creds.secret)
- signature = signer.generate(credentials)
- if signature == credentials.signature:
- return True
- # NOTE(vish): Some libraries don't use the port when signing
- # requests, so try again without port.
- if ':' in credentials.host:
- hostname, _port = credentials.host.split(":")
- credentials.host = hostname
- signature = signer.generate(credentials)
- return signature == credentials.signature
- return False
- return self._authenticate(validate, creds.user_id,
- creds.tenant_id)
-
- def authenticate_s3(self, credentials):
- # Check credentials
- if not isinstance(credentials, auth.S3Credentials):
- raise fault.BadRequestFault("Expecting S3 Credentials!")
-
- creds = self.credential_manager.get_by_access(credentials.access)
- if not creds:
- raise fault.UnauthorizedFault("No credentials found for %s"
- % credentials.access)
-
- def validate(duser): # pylint: disable=W0613
- signer = Signer(creds.secret)
- signature = signer.generate(credentials, s3=True)
- if signature == credentials.signature:
- return True
- return False
-
- return self._authenticate(validate, creds.user_id, creds.tenant_id)
-
- def _authenticate(self, validate, user_id, tenant_id=None):
- LOG.debug("Authenticating user %s (tenant: %s)" % (user_id, tenant_id))
- if tenant_id:
- duser = self.user_manager.get_by_tenant(user_id, tenant_id)
- if duser is None:
- LOG.debug("User %s is not authorized on tenant %s" % (
- user_id, tenant_id))
- raise fault.UnauthorizedFault("Unauthorized on this tenant")
- else:
- duser = self.user_manager.get(user_id)
- if duser is None:
- LOG.debug("User with id %s not found" % user_id)
- raise fault.UnauthorizedFault("Unauthorized")
-
- if not duser.enabled:
- LOG.debug("User %s is not enabled" % user_id)
- raise fault.UserDisabledFault("Your account has been disabled")
-
- if not validate(duser):
- LOG.debug("validate() returned false")
- raise fault.UnauthorizedFault("Unauthorized")
-
- # use user's default tenant_id if one is not specified
- tenant_id = tenant_id or duser.tenant_id
-
- # check for an existing token
- dtoken = self.token_manager.find(duser.id, tenant_id)
-
- if not dtoken or dtoken.expires < datetime.now():
- LOG.debug("Token was not found or expired. Creating a new token "
- "for the user")
- # Create new token
- dtoken = Token()
- dtoken.id = str(uuid.uuid4())
- dtoken.user_id = duser.id
- dtoken.tenant_id = tenant_id
- dtoken.expires = datetime.now() + timedelta(days=1)
- dtoken = self.token_manager.create(dtoken)
- return self.get_auth_data(dtoken)
-
- # pylint: disable=W0613
- @service_admin_token_validator
- def validate_token(self, admin_token, token_id, belongs_to=None,
- service_ids=None):
- (token, user) = self._validate_token(token_id, belongs_to, True)
- if service_ids and (token.tenant_id or belongs_to):
- # scope token, validate the service IDs if present
- service_ids = self.parse_service_ids(service_ids)
- self.validate_service_ids(service_ids)
- auth_data = self.get_validate_data(token, user, service_ids)
- if service_ids and (token.tenant_id or belongs_to):
- # we have service Ids and scope token, make sure we have some roles
- if not auth_data.user.rolegrants.values:
- raise fault.UnauthorizedFault("No roles found for scope token")
- return auth_data
-
- @admin_token_validator
- def revoke_token(self, admin_token, token_id):
- dtoken = self.token_manager.get(token_id)
- if not dtoken:
- raise fault.ItemNotFoundFault("Token not found")
-
- self.token_manager.delete(token_id)
-
- @staticmethod
- def parse_service_ids(service_ids):
- """
- Method to parse the service IDs string.
- service_ids -- comma-separated service IDs
- parse and return a list of service IDs.
- """
- if service_ids:
- return [x.strip() for x in service_ids.split(',')]
- return []
-
- def validate_service_ids(self, service_ids):
- """
- Method to validate the service IDs.
- service_ids -- list of service IDs
- If not service IDs or encounter an invalid service ID,
- fault.UnauthorizedFault will be raised.
- """
- if not service_ids:
- raise fault.UnauthorizedFault("Missing service IDs")
-
- services = [self.service_manager.get(service_id) for service_id in
- service_ids if not service_id == GLOBAL_SERVICE_ID]
- if not all(services):
- raise fault.UnauthorizedFault(
- "Invalid service ID: %s" % (service_ids))
-
- def get_roles_names_by_service_ids(self, service_ids):
- """
- Method to find all the roles for the given service IDs.
- service_ids -- list of service IDs
- """
- roles = []
- for service_id in service_ids:
- if service_id != GLOBAL_SERVICE_ID:
- sroles = self.role_manager.get_by_service(
- service_id=service_id)
- if sroles:
- roles = roles + sroles
- return [role.name for role in roles]
-
- def get_global_roles_for_user(self, user_id):
- """
- Method to return all the global roles for the given user.
- user_id -- user ID
- """
- ts = []
- drolegrants = self.grant_manager.list_global_roles_for_user(user_id)
- for drolegrant in drolegrants:
- drole = self.role_manager.get(drolegrant.role_id)
- ts.append(Role(drolegrant.role_id, drole.name,
- None, drolegrant.tenant_id))
- return ts
-
- def get_tenant_roles_for_user_and_services(self, user_id, tenant_id,
- service_ids):
- """
- Method to return all the tenant roles for the given user,
- filtered by service ID.
- user_id -- user ID
- tenant_id -- tenant ID
- service_ids -- service IDs
- If service_ids are specified, will return the roles filtered by
- service IDs.
- """
- ts = []
- if tenant_id and user_id:
- drolegrants = self.grant_manager.list_tenant_roles_for_user(
- user_id, tenant_id)
- for drolegrant in drolegrants:
- drole = self.role_manager.get(drolegrant.role_id)
- ts.append(Role(drolegrant.role_id, drole.name,
- None, drolegrant.tenant_id))
-
- if service_ids:
- # if service IDs are specified, filter roles by service IDs
- sroles_names = self.get_roles_names_by_service_ids(service_ids)
- return [role for role in ts
- if role.name in sroles_names]
- else:
- return ts
-
- @service_admin_token_validator
- def get_endpoints_for_token(self, admin_token,
- token_id, marker, limit, url,):
- dtoken = self.token_manager.get(token_id)
- if not dtoken:
- raise fault.ItemNotFoundFault("Token not found")
- if not dtoken.tenant_id:
- raise fault.ItemNotFoundFault("Token not mapped to any tenant.")
- return self.fetch_tenant_endpoints(
- marker, limit, url, dtoken.tenant_id)
-
- def get_token_info(self, token_id):
- """returns token and user object for a token_id"""
-
- token = None
- user = None
- if token_id:
- token = self.token_manager.get(token_id)
- if token:
- user = self.user_manager.get(token.user_id)
- return (token, user)
-
- def _validate_token(self, token_id, belongs_to=None, is_check_token=None):
- """
- Method to validate a token.
- token_id -- id of the token that needs to be validated.
- belongs_to -- optional tenant_id to check whether the token is
- mapped to a specific tenant.
- is_check_token -- optional argument that tells whether
- we check the existence of a Token using another Token
- to authenticate. This value decides the faults that are to be thrown.
- """
- if not token_id:
- raise fault.UnauthorizedFault("Missing token")
-
- (token, user) = self.get_token_info(token_id)
-
- if not token:
- if is_check_token:
- raise fault.ItemNotFoundFault("Token does not exist.")
- else:
- raise fault.UnauthorizedFault(
- "Bad token, please reauthenticate")
-
- if token.expires < datetime.now():
- if is_check_token:
- raise fault.ItemNotFoundFault("Token expired, please renew.")
- else:
- raise fault.ForbiddenFault("Token expired, please renew.")
-
- if not user.enabled:
- raise fault.UserDisabledFault("User %s has been disabled!"
- % user.id)
-
- if user.tenant_id:
- self.validate_tenant_by_id(user.tenant_id)
-
- if token.tenant_id:
- self.validate_tenant_by_id(token.tenant_id)
-
- if belongs_to and unicode(token.tenant_id) != unicode(belongs_to):
- raise fault.UnauthorizedFault("Unauthorized on this tenant")
-
- return (token, user)
-
- def has_admin_role(self, token_id):
- """ Checks if the token belongs to a user who has Keystone admin
- rights.
-
- Returns (token, user) if true. False otherwise.
-
- This is currently assigned using a global role assignment
- (i.e. role assigned without a tenant id). The actual name of the
- role is defined in the config file using the keystone-admin-role
- setting
- """
- (token, user) = self._validate_token(token_id)
- self.init_admin_role_identifiers()
- if self.has_role(None, user, ADMIN_ROLE_ID):
- return (token, user)
- else:
- return False
-
- def has_service_admin_role(self, token_id):
- """ Checks if the token belongs to a user who has Keystone Service
- Admin rights. (Note: Keystone Admin rights include Keystone Service
- Admin).
-
- Returns (token, user) if true. False otherwise.
-
- This is currently assigned using a global role assignment
- (i.e. role assigned without a tenant id). The actual name of the role
- is defined in the config file using the keystone-admin-role setting
- """
- (token, user) = self._validate_token(token_id)
- self.init_admin_role_identifiers()
- if self.has_role(None, user, SERVICE_ADMIN_ROLE_ID):
- return (token, user)
- else:
- return self.has_admin_role(token_id)
-
- def validate_admin_token(self, token_id):
- """ Validates that the token belongs to a user who has Keystone admin
- rights. Raises an Unauthorized exception if not.
-
- This is currently assigned using a global role assignment
- (i.e. role assigned without a tenant id). The actual name of the role
- is defined in the config file using the keystone-admin-role setting
- """
- result = self.has_admin_role(token_id)
- if result:
- return result
- else:
- raise fault.UnauthorizedFault(
- "You are not authorized to make this call")
-
- def validate_service_admin_token(self, token_id):
- """ Validates that the token belongs to a user who has Keystone admin
- or Keystone Service Admin rights. Raises an Unaithorized exception if
- not.
-
- These are currently assigned using a global role assignments
- (i.e. roles assigned without a tenant id). The actual name of the roles
- is defined in the config file using the keystone-admin-role and
- keystone-service-admin-role settings
- """
- # Does the user have the Service Admin role
- result = self.has_service_admin_role(token_id)
- if result:
- LOG.debug("token is associated with service admin role")
- return result
- # Does the user have the Admin role (which includes Service Admin
- # rights)
- result = self.has_admin_role(token_id)
- if result:
- LOG.debug("token is associated with admin role, so responding"
- "positively from validate_service_admin_token")
- return result
-
- LOG.debug("token is not associated with admin or service admin role")
- raise fault.UnauthorizedFault(
- "You are not authorized to make this call")
-
- def init_admin_role_identifiers(self):
- global ADMIN_ROLE_ID, SERVICE_ADMIN_ROLE_ID
- if SERVICE_ADMIN_ROLE_ID is None:
- role = self.role_manager.get_by_name(SERVICE_ADMIN_ROLE_NAME)
- if role:
- SERVICE_ADMIN_ROLE_ID = role.id
- else:
- LOG.warn('No service admin role found (searching for name=%s.'
- % SERVICE_ADMIN_ROLE_NAME)
- if ADMIN_ROLE_ID is None:
- role = self.role_manager.get_by_name(ADMIN_ROLE_NAME)
- if role:
- ADMIN_ROLE_ID = role.id
- else:
- LOG.warn('No admin role found (searching for name=%s.'
- % ADMIN_ROLE_NAME)
-
- def has_role(self, env, user, role):
- """Checks if a user has a specific role.
-
- env: provides the context
- user: the user to be checked
- role: the role to check that the user has
- """
- for rolegrant in\
- self.grant_manager.list_global_roles_for_user(user.id):
- if ((rolegrant.role_id == role)
- and rolegrant.tenant_id is None):
- return True
- LOG.debug("User %s failed check - did not have role %s" %
- (user.id, role))
- return False
-
- # pylint: disable=W0613
- @staticmethod
- def is_owner(env, user, object):
- """Checks if a user is the owner of an object.
-
- This is done by checking if the user id matches the 'owner_id'
- field of the object
-
- env: provides the context
- user: the user to be checked
- role: the role to check that the user has
- """
- if hasattr(object, 'owner_id'):
- if object.owner_id == user.id:
- return True
- return False
-
- def validate_unscoped_token(self, token_id, belongs_to=None):
- (token, user) = self._validate_token(token_id, belongs_to)
-
- if token.tenant_id:
- raise fault.ForbiddenFault("Expecting unscoped token")
- return (token, user)
-
- def validate_tenant_by_id(self, tenant_id):
- if not tenant_id:
- raise fault.UnauthorizedFault("Missing tenant id")
-
- dtenant = self.tenant_manager.get(tenant_id)
- return self.validate_tenant(dtenant)
-
- def validate_tenant_by_name(self, tenant_name):
- if not tenant_name:
- raise fault.UnauthorizedFault("Missing tenant name")
-
- dtenant = self.tenant_manager.get_by_name(name=tenant_name)
- return self.validate_tenant(dtenant)
-
- def get_auth_data(self, dtoken):
- """returns AuthData object for a token
-
- AuthData is used for rendering authentication responses
- """
- tenant = None
- endpoints = None
-
- if dtoken.tenant_id:
- dtenant = self.tenant_manager.get(dtoken.tenant_id)
- tenant = auth.Tenant(id=dtenant.id, name=dtenant.name)
- endpoints = self.tenant_manager.get_all_endpoints(dtoken.tenant_id)
- else:
- endpoints = self.tenant_manager.get_all_endpoints(None)
-
- token = auth.Token(dtoken.expires, dtoken.id, tenant)
- duser = self.user_manager.get(dtoken.user_id)
-
- ts = []
- if dtoken.tenant_id:
- drolegrants = self.grant_manager.list_tenant_roles_for_user(
- duser.id, dtoken.tenant_id)
- for drolegrant in drolegrants:
- drole = self.role_manager.get(drolegrant.role_id)
- ts.append(Role(drolegrant.role_id, drole.name,
- description=drole.desc, tenant_id=drolegrant.tenant_id))
- drolegrants = self.grant_manager.list_global_roles_for_user(duser.id)
- for drolegrant in drolegrants:
- drole = self.role_manager.get(drolegrant.role_id)
- ts.append(Role(drolegrant.role_id, drole.name,
- description=drole.desc, tenant_id=drolegrant.tenant_id))
- user = auth.User(duser.id, duser.name, None, None, Roles(ts, []))
- if self.has_service_admin_role(token.id):
- # Privileged users see the adminURL as well
- url_types = ['admin', 'internal', 'public']
- else:
- url_types = ['internal', 'public']
- return auth.AuthData(token, user, endpoints, url_types=url_types)
-
- def get_validate_data(self, dtoken, duser, service_ids=None):
- """return ValidateData object for a token/user pair"""
- global GLOBAL_SERVICE_ID
- tenant = None
- if dtoken.tenant_id:
- dtenant = self.tenant_manager.get(dtoken.tenant_id)
- tenant = auth.Tenant(id=dtenant.id, name=dtenant.name)
-
- token = auth.Token(dtoken.expires, dtoken.id, tenant)
-
- ts = self.get_tenant_roles_for_user_and_services(duser.id,
- dtoken.tenant_id,
- service_ids)
- if (not dtoken.tenant_id or not service_ids or
- (GLOBAL_SERVICE_ID in service_ids)):
- # return the global roles for unscoped tokens or
- # its ID is in the service IDs
- ts = ts + self.get_global_roles_for_user(duser.id)
-
- # Also get the user's tenant's name
- tenant_name = None
- if duser.tenant_id:
- utenant = self.tenant_manager.get(duser.tenant_id)
- tenant_name = utenant.name
-
- user = auth.User(duser.id, duser.name, duser.tenant_id,
- tenant_name, Roles(ts, []))
- return auth.ValidateData(token, user)
-
- @staticmethod
- def validate_tenant(dtenant):
- if not dtenant:
- raise fault.UnauthorizedFault("Tenant not found")
-
- if dtenant.enabled is None or \
- str(dtenant.enabled).lower() not in ['1', 'true']:
- raise fault.TenantDisabledFault("Tenant %s has been disabled!"
- % dtenant.id)
- return dtenant
-
- #
- # Tenant Operations
- #
- @admin_token_validator
- def create_tenant(self, admin_token, tenant):
- if not isinstance(tenant, Tenant):
- raise fault.BadRequestFault("Expecting a Tenant")
-
- utils.check_empty_string(tenant.name, "Expecting a unique Tenant Name")
- if self.tenant_manager.get_by_name(tenant.name) is not None:
- raise fault.TenantConflictFault(
- "A tenant with that name already exists")
- dtenant = Tenant()
- dtenant.name = tenant.name
- dtenant.description = tenant.description
- dtenant.enabled = tenant.enabled
- return self.tenant_manager.create(dtenant)
-
- # pylint: disable=R0914
- def get_tenants(self, admin_token, marker, limit, url,
- is_service_operation=False):
- """Fetch tenants for either an admin or service operation."""
- ts = []
-
- if is_service_operation:
- # Check regular token validity.
- (_token, user) = self._validate_token(admin_token, belongs_to=None,
- is_check_token=False)
- scope = _token.tenant_id
- default_tenant = user.tenant_id
-
- if (scope is None or
- ((scope and default_tenant) and (scope == default_tenant))):
- # Return all tenants specific to user if token has no scope
- # or if token is scoped to a default tenant
- dtenants = self.tenant_manager.list_for_user_get_page(
- user.id, marker, limit)
- prev_page, next_page = self.tenant_manager.\
- list_for_user_get_page_markers(user.id, marker, limit)
- else:
- # Return scoped tenant only
- dtenants = [self.tenant_manager.get(scope or default_tenant)]
- prev_page = 2
- next_page = None
- limit = 10
- else:
- #Check Admin Token
- (_token, user) = self.validate_admin_token(admin_token)
- # Return all tenants
- dtenants = self.tenant_manager.get_page(marker, limit)
- prev_page, next_page = self.tenant_manager.get_page_markers(marker,
- limit)
-
- for dtenant in dtenants:
- t = Tenant(id=dtenant.id, name=dtenant.name,
- description=dtenant.desc, enabled=dtenant.enabled)
- ts.append(t)
-
- links = self.get_links(url, prev_page, next_page, limit)
- return Tenants(ts, links)
-
- @admin_token_validator
- def get_tenant(self, admin_token, tenant_id):
- dtenant = self.tenant_manager.get(tenant_id)
- if not dtenant:
- raise fault.ItemNotFoundFault("The tenant could not be found")
- return Tenant(dtenant.id, dtenant.name, dtenant.desc, dtenant.enabled)
-
- @admin_token_validator
- def get_tenant_by_name(self, admin_token, tenant_name):
- dtenant = self.tenant_manager.get_by_name(tenant_name)
- if not dtenant:
- raise fault.ItemNotFoundFault("The tenant could not be found")
- return dtenant
-
- @admin_token_validator
- def update_tenant(self, admin_token, tenant_id, tenant):
- if not isinstance(tenant, Tenant):
- raise fault.BadRequestFault("Expecting a Tenant")
-
- dtenant = self.tenant_manager.get(tenant_id)
- if dtenant is None:
- raise fault.ItemNotFoundFault("The tenant could not be found")
-
- utils.check_empty_string(tenant.name, "Expecting a unique Tenant Name")
-
- if tenant.name != dtenant.name and \
- self.tenant_manager.get_by_name(tenant.name):
- raise fault.TenantConflictFault(
- "A tenant with that name already exists")
- values = {'id': tenant_id, 'desc': tenant.description,
- 'enabled': tenant.enabled, 'name': tenant.name}
- self.tenant_manager.update(values)
- dtenant = self.tenant_manager.get(tenant_id)
- return dtenant
-
- @admin_token_validator
- def delete_tenant(self, admin_token, tenant_id):
- dtenant = self.tenant_manager.get(tenant_id)
- if dtenant is None:
- raise fault.ItemNotFoundFault("The tenant could not be found")
-
- self.tenant_manager.delete(dtenant.id)
- return None
-
- #
- # User Operations
- #
- @admin_token_validator
- def create_user(self, admin_token, user):
- self.validate_and_fetch_user_tenant(user.tenant_id)
-
- if not isinstance(user, User):
- raise fault.BadRequestFault("Expecting a User")
-
- utils.check_empty_string(user.name,
- "Expecting a unique user Name")
-
- if self.user_manager.get_by_name(user.name):
- raise fault.UserConflictFault(
- "A user with that name already exists")
-
- if self.user_manager.get_by_email(user.email):
- raise fault.EmailConflictFault(
- "A user with that email already exists")
-
- duser = models.User()
- duser.name = user.name
- duser.password = user.password
- duser.email = user.email
- duser.enabled = user.enabled
- duser.tenant_id = user.tenant_id
- duser = self.user_manager.create(duser)
- user.id = duser.id
- return user
-
- def validate_and_fetch_user_tenant(self, tenant_id):
- if tenant_id:
- dtenant = self.tenant_manager.get(tenant_id)
- if dtenant is None:
- raise fault.ItemNotFoundFault("The tenant is not found")
- elif not dtenant.enabled:
- raise fault.TenantDisabledFault(
- "Your account has been disabled")
- return dtenant
-
- # pylint: disable=R0913
- @admin_token_validator
- def get_tenant_users(self, admin_token, tenant_id,
- role_id, marker, limit, url):
- if tenant_id is None:
- raise fault.BadRequestFault("Expecting a Tenant Id")
- dtenant = self.tenant_manager.get(tenant_id)
- if dtenant is None:
- raise fault.ItemNotFoundFault("The tenant not found")
- if not dtenant.enabled:
- raise fault.TenantDisabledFault("Your account has been disabled")
- if role_id:
- if not self.role_manager.get(role_id):
- raise fault.ItemNotFoundFault("The role not found")
- ts = []
- dtenantusers = self.user_manager.users_get_by_tenant_get_page(
- tenant_id, role_id, marker, limit)
- for dtenantuser in dtenantusers:
- try:
- troles = dtenantuser.tenant_roles
- except AttributeError:
- troles = None
- ts.append(User(None, dtenantuser.id, dtenantuser.name, tenant_id,
- dtenantuser.email, dtenantuser.enabled, troles))
- links = []
- if ts.__len__():
- prev, next = self.\
- user_manager.users_get_by_tenant_get_page_markers(
- tenant_id, role_id, marker, limit)
- links = self.get_links(url, prev, next, limit)
- return Users(ts, links)
-
- @admin_token_validator
- def get_users(self, admin_token, marker, limit, url):
- ts = []
- dusers = self.user_manager.users_get_page(marker, limit)
- for duser in dusers:
- ts.append(User(None, duser.id, duser.name, duser.tenant_id,
- duser.email, duser.enabled))
- links = []
- if ts.__len__():
- prev, next = self.user_manager.users_get_page_markers(marker,
- limit)
- links = self.get_links(url, prev, next, limit)
- return Users(ts, links)
-
- @admin_token_validator
- def get_user(self, admin_token, user_id):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- return User_Update(id=duser.id, tenant_id=duser.tenant_id,
- email=duser.email, enabled=duser.enabled, name=duser.name)
-
- @admin_token_validator
- def get_user_by_name(self, admin_token, user_name):
- duser = self.user_manager.get_by_name(user_name)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- return User_Update(id=duser.id, tenant_id=duser.tenant_id,
- email=duser.email, enabled=duser.enabled, name=duser.name)
-
- @admin_token_validator
- def update_user(self, admin_token, user_id, user):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- if not isinstance(user, User):
- raise fault.BadRequestFault("Expecting a User")
-
- utils.check_empty_string(user.name,
- "Expecting a unique username")
-
- if user.name != duser.name and \
- self.user_manager.get_by_name(user.name):
- raise fault.UserConflictFault(
- "A user with that name already exists")
-
- if user.email != duser.email and \
- self.user_manager.get_by_email(user.email) is not None:
- raise fault.EmailConflictFault("Email already exists")
-
- values = {'id': user_id, 'email': user.email, 'name': user.name}
- self.user_manager.update(values)
- duser = self.user_manager.get(user_id)
- return User(duser.password, duser.id, duser.name, duser.tenant_id,
- duser.email, duser.enabled)
-
- @admin_token_validator
- def set_user_password(self, admin_token, user_id, user):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- if not isinstance(user, User):
- raise fault.BadRequestFault("Expecting a User")
-
- duser = self.user_manager.get(user_id)
- if duser is None:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- values = {'id': user_id, 'password': user.password}
-
- self.user_manager.update(values)
-
- return User_Update(password=user.password)
-
- @admin_token_validator
- def enable_disable_user(self, admin_token, user_id, user):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- if not isinstance(user, User):
- raise fault.BadRequestFault("Expecting a User")
-
- values = {'id': user_id, 'enabled': user.enabled}
-
- self.user_manager.update(values)
-
- duser = self.user_manager.get(user_id)
-
- return User_Update(enabled=user.enabled)
-
- @admin_token_validator
- def set_user_tenant(self, admin_token, user_id, user):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- if not isinstance(user, User):
- raise fault.BadRequestFault("Expecting a User")
-
- self.validate_and_fetch_user_tenant(user.tenant_id)
- values = {'id': user_id, 'tenant_id': user.tenant_id}
- self.user_manager.update(values)
- return User_Update(tenant_id=user.tenant_id)
-
- @admin_token_validator
- def delete_user(self, admin_token, user_id):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- self.user_manager.delete(user_id)
- return None
-
- def create_role(self, admin_token, role):
- user = self.validate_service_admin_token(admin_token)[1]
-
- if not isinstance(role, Role):
- raise fault.BadRequestFault("Expecting a Role")
-
- utils.check_empty_string(role.name, "Expecting a Role name")
-
- if self.role_manager.get_by_name(role.name) is not None:
- raise fault.RoleConflictFault(
- "A role with that name '%s' already exists" % role.name)
-
- #Check if the role name includes an embedded service: in it
- #if so, verify the service exists
- if role.service_id is None:
- split = role.name.split(":")
- if isinstance(split, list) and len(split) > 1:
- service_name = split[0]
- service = self.service_manager.get_by_name(service_name)
- if service is None:
- raise fault.BadRequestFault(
- "A service with the name %s doesn't exist."
- % service_name)
- role.service_id = service.id
-
- # Check ownership of the service (or overriding admin rights)
- if role.service_id:
- service = self.service_manager.get(role.service_id)
- if service is None:
- raise fault.BadRequestFault(
- "A service with that id doesn't exist.")
- if not role.name.startswith(service.name + ":"):
- raise fault.BadRequestFault(
- "Role should begin with service name '%s:'" % service.name)
- if not self.is_owner(None, user, service):
- if not self.has_admin_role(admin_token):
- raise fault.UnauthorizedFault(
- "You do not have ownership of the '%s' service" \
- % service.name)
-
- drole = models.Role()
- drole.name = role.name
- drole.desc = role.description
- drole.service_id = role.service_id
- drole = self.role_manager.create(drole)
- role.id = drole.id
- return role
-
- @service_admin_token_validator
- def get_roles(self, admin_token, marker, limit, url):
- droles = self.role_manager.get_page(marker, limit)
- prev, next = self.role_manager.get_page_markers(marker, limit)
- links = self.get_links(url, prev, next, limit)
- ts = self.transform_roles(droles)
- return Roles(ts, links)
-
- @service_admin_token_validator
- def get_roles_by_service(self, admin_token, marker, limit, url,
- service_id):
- droles = self.role_manager.get_by_service_get_page(service_id, marker,
- limit)
- prev, next = self.role_manager.get_by_service_get_page_markers(
- service_id, marker, limit)
- links = self.get_links(url, prev, next, limit)
- ts = self.transform_roles(droles)
- return Roles(ts, links)
-
- @staticmethod
- def transform_roles(droles):
- return [Role(drole.id, drole.name, drole.desc, drole.service_id)
- for drole in droles]
-
- @service_admin_token_validator
- def get_role(self, admin_token, role_id):
- drole = self.role_manager.get(role_id)
- if not drole:
- raise fault.ItemNotFoundFault("The role could not be found")
- return Role(drole.id, drole.name, drole.desc, drole.service_id)
-
- @service_admin_token_validator
- def get_role_by_name(self, admin_token, role_name):
- drole = self.role_manager.get_by_name(role_name)
- if not drole:
- raise fault.ItemNotFoundFault("The role could not be found")
- return Role(drole.id, drole.name,
- drole.desc, drole.service_id)
-
- def delete_role(self, admin_token, role_id):
- user = self.validate_service_admin_token(admin_token)[1]
-
- drole = self.role_manager.get(role_id)
- if not drole:
- raise fault.ItemNotFoundFault("The role could not be found")
-
- # Check ownership of the service (or overriding admin rights)
- if drole.service_id:
- service = self.service_manager.get(drole.service_id)
- if service:
- if not self.is_owner(None, user, service):
- if not self.has_admin_role(admin_token):
- raise fault.UnauthorizedFault(
- "You do not have ownership of the '%s' service"
- % service.name)
-
- rolegrants = self.grant_manager.rolegrant_list_by_role(role_id)
- if rolegrants is not None:
- for rolegrant in rolegrants:
- self.grant_manager.rolegrant_delete(rolegrant.id)
- self.role_manager.delete(role_id)
-
- @service_admin_token_validator
- def add_role_to_user(self, admin_token, user_id, role_id, tenant_id=None):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- drole = self.role_manager.get(role_id)
- if drole is None:
- raise fault.ItemNotFoundFault("The role not found")
- if tenant_id is not None:
- dtenant = self.tenant_manager.get(tenant_id)
- if dtenant is None:
- raise fault.ItemNotFoundFault("The tenant not found")
-
- drolegrant = self.grant_manager.rolegrant_get_by_ids(user_id, role_id,
- tenant_id)
- if drolegrant is not None:
- raise fault.RoleConflictFault(
- "This role is already mapped to the user.")
-
- drolegrant = models.UserRoleAssociation()
- drolegrant.user_id = duser.id
- drolegrant.role_id = drole.id
- if tenant_id is not None:
- drolegrant.tenant_id = dtenant.id
- self.user_manager.user_role_add(drolegrant)
-
- @service_admin_token_validator
- def remove_role_from_user(self, admin_token, user_id, role_id,
- tenant_id=None):
- drolegrant = self.grant_manager.rolegrant_get_by_ids(user_id, role_id,
- tenant_id)
- if drolegrant is None:
- raise fault.ItemNotFoundFault(
- "This role is not mapped to the user.")
- self.grant_manager.rolegrant_delete(drolegrant.id)
-
- # pylint: disable=R0913, R0914
- @service_admin_token_validator
- def get_user_roles(self, admin_token, marker,
- limit, url, user_id, tenant_id):
- duser = self.user_manager.get(user_id)
-
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- if tenant_id is not None:
- dtenant = self.tenant_manager.get(tenant_id)
- if not dtenant:
- raise fault.ItemNotFoundFault("The tenant could not be found.")
- ts = []
- drolegrants = self.grant_manager.rolegrant_get_page(marker, limit,
- user_id, tenant_id)
- for drolegrant in drolegrants:
- drole = self.role_manager.get(drolegrant.role_id)
- ts.append(Role(drole.id, drole.name,
- drole.desc, drole.service_id))
- prev, next = self.grant_manager.rolegrant_get_page_markers(
- user_id, tenant_id, marker, limit)
- links = self.get_links(url, prev, next, limit)
- return Roles(ts, links)
-
- def add_endpoint_template(self, admin_token, endpoint_template):
- user = self.validate_service_admin_token(admin_token)[1]
-
- if not isinstance(endpoint_template, EndpointTemplate):
- raise fault.BadRequestFault("Expecting a EndpointTemplate")
-
- utils.check_empty_string(endpoint_template.name,
- "Expecting Endpoint Template name.")
- utils.check_empty_string(endpoint_template.type,
- "Expecting Endpoint Template type.")
-
- dservice = self.service_manager.get_by_name_and_type(
- endpoint_template.name,
- endpoint_template.type)
- if dservice is None:
- raise fault.BadRequestFault(
- "A service with that name and type doesn't exist.")
-
- # Check ownership of the service (or overriding admin rights)
- if not self.is_owner(None, user, dservice):
- if not self.has_admin_role(admin_token):
- raise fault.UnauthorizedFault(
- "You do not have ownership of the '%s' service" \
- % dservice.name)
-
- dendpoint_template = models.EndpointTemplates()
- dendpoint_template.region = endpoint_template.region
- dendpoint_template.service_id = dservice.id
- dendpoint_template.public_url = endpoint_template.public_url
- dendpoint_template.admin_url = endpoint_template.admin_url
- dendpoint_template.internal_url = endpoint_template.internal_url
- dendpoint_template.enabled = endpoint_template.enabled
- dendpoint_template.is_global = endpoint_template.is_global
- dendpoint_template.version_id = endpoint_template.version_id
- dendpoint_template.version_list = endpoint_template.version_list
- dendpoint_template.version_info = endpoint_template.version_info
- dendpoint_template = self.endpoint_template_manager.create(
- dendpoint_template)
- endpoint_template.id = dendpoint_template.id
- return endpoint_template
-
- def modify_endpoint_template(self, admin_token, endpoint_template_id,
- endpoint_template):
- user = self.validate_service_admin_token(admin_token)[1]
-
- if not isinstance(endpoint_template, EndpointTemplate):
- raise fault.BadRequestFault("Expecting a EndpointTemplate")
- dendpoint_template = self.endpoint_template_manager.get(
- endpoint_template_id)
- if not dendpoint_template:
- raise fault.ItemNotFoundFault(
- "The endpoint template could not be found")
-
- #Check if the passed service exist.
- utils.check_empty_string(endpoint_template.name,
- "Expecting Endpoint Template name.")
- utils.check_empty_string(endpoint_template.type,
- "Expecting Endpoint Template type.")
-
- dservice = self.service_manager.get(dendpoint_template.service_id)
- if not dservice:
- raise fault.BadRequestFault(
- "A service with that name and type doesn't exist.")
-
- # Check ownership of the service (or overriding admin rights)
- if not self.is_owner(None, user, dservice):
- if not self.has_admin_role(admin_token):
- raise fault.UnauthorizedFault(
- "You do not have ownership of the '%s' service" \
- % dservice.name)
-
- dendpoint_template.region = endpoint_template.region
- dendpoint_template.service_id = dservice.id
- dendpoint_template.public_url = endpoint_template.public_url
- dendpoint_template.admin_url = endpoint_template.admin_url
- dendpoint_template.internal_url = endpoint_template.internal_url
- dendpoint_template.enabled = endpoint_template.enabled
- dendpoint_template.is_global = endpoint_template.is_global
- dendpoint_template.version_id = endpoint_template.version_id
- dendpoint_template.version_list = endpoint_template.version_list
- dendpoint_template.version_info = endpoint_template.version_info
- dendpoint_template = self.endpoint_template_manager.update(
- dendpoint_template)
- return EndpointTemplate(
- dendpoint_template.id,
- dendpoint_template.region,
- dservice.name,
- dservice.type,
- dendpoint_template.public_url,
- dendpoint_template.admin_url,
- dendpoint_template.internal_url,
- dendpoint_template.enabled,
- dendpoint_template.is_global,
- dendpoint_template.version_id,
- dendpoint_template.version_list,
- dendpoint_template.version_info
- )
-
- def delete_endpoint_template(self, admin_token, endpoint_template_id):
- user = self.validate_service_admin_token(admin_token)[1]
- dendpoint_template = self.endpoint_template_manager.get(
- endpoint_template_id)
- if not dendpoint_template:
- raise fault.ItemNotFoundFault(
- "The endpoint template could not be found")
-
- dservice = self.service_manager.get(dendpoint_template.service_id)
- if dservice:
- # Check ownership of the service (or overriding admin rights)
- if not self.is_owner(None, user, dservice):
- if not self.has_admin_role(admin_token):
- raise fault.UnauthorizedFault(
- "You do not have ownership of the '%s' service" \
- % dservice.name)
- else:
- # Cannot verify service ownership, so verify full admin rights
- if not self.has_admin_role(admin_token):
- raise fault.UnauthorizedFault(
- "You do not have ownership of the '%s' service" \
- % dservice.name)
-
- #Delete Related endpoints
- endpoints = self.endpoint_manager.\
- endpoint_get_by_endpoint_template(endpoint_template_id)
- if endpoints is not None:
- for endpoint in endpoints:
- self.endpoint_manager.delete(endpoint.id)
- self.endpoint_template_manager.delete(endpoint_template_id)
-
- @service_admin_token_validator
- def get_endpoint_templates(self, admin_token, marker, limit, url):
- dendpoint_templates = self.endpoint_template_manager.get_page(marker,
- limit)
- ts = self.transform_endpoint_templates(dendpoint_templates)
- prev, next = self.endpoint_template_manager.get_page_markers(marker,
- limit)
- links = self.get_links(url, prev, next, limit)
- return EndpointTemplates(ts, links)
-
- @service_admin_token_validator
- def get_endpoint_templates_by_service(self, admin_token,
- service_id, marker, limit, url):
- dservice = self.service_manager.get(service_id)
- if dservice is None:
- raise fault.ItemNotFoundFault(
- "No service with the id %s found." % service_id)
- dendpoint_templates = self.endpoint_template_manager.\
- get_by_service_get_page(service_id, marker, limit)
- ts = self.transform_endpoint_templates(dendpoint_templates)
- prev, next = self.endpoint_template_manager.\
- get_by_service_get_page_markers(service_id, marker, limit)
- links = self.get_links(url, prev, next, limit)
- return EndpointTemplates(ts, links)
-
- def transform_endpoint_templates(self, dendpoint_templates):
- ts = []
- for dendpoint_template in dendpoint_templates:
- dservice = self.service_manager.get(dendpoint_template.service_id)
- ts.append(EndpointTemplate(
- dendpoint_template.id,
- dendpoint_template.region,
- dservice.name,
- dservice.type,
- dendpoint_template.public_url,
- dendpoint_template.admin_url,
- dendpoint_template.internal_url,
- dendpoint_template.enabled,
- dendpoint_template.is_global,
- dendpoint_template.version_id,
- dendpoint_template.version_list,
- dendpoint_template.version_info
- ))
- return ts
-
- @service_admin_token_validator
- def get_endpoint_template(self, admin_token, endpoint_template_id):
- dendpoint_template = self.endpoint_template_manager.get(
- endpoint_template_id)
- if not dendpoint_template:
- raise fault.ItemNotFoundFault(
- "The endpoint template could not be found")
- dservice = self.service_manager.get(dendpoint_template.service_id)
- return EndpointTemplate(
- dendpoint_template.id,
- dendpoint_template.region,
- dservice.name,
- dservice.type,
- dendpoint_template.public_url,
- dendpoint_template.admin_url,
- dendpoint_template.internal_url,
- dendpoint_template.enabled,
- dendpoint_template.is_global,
- dendpoint_template.version_id,
- dendpoint_template.version_list,
- dendpoint_template.version_info
- )
-
- @service_admin_token_validator
- def get_tenant_endpoints(self, admin_token, marker, limit, url, tenant_id):
- return self.fetch_tenant_endpoints(marker, limit,
- url, tenant_id)
-
- def fetch_tenant_endpoints(self, marker, limit, url, tenant_id):
- if tenant_id is None:
- raise fault.BadRequestFault("Expecting a Tenant Id")
-
- if self.tenant_manager.get(tenant_id) is None:
- raise fault.ItemNotFoundFault("The tenant not found")
-
- ts = []
-
- dtenant_endpoints = \
- self.endpoint_manager.endpoint_get_by_tenant_get_page(tenant_id,
- marker, limit)
- for dtenant_endpoint in dtenant_endpoints:
- dendpoint_template = self.endpoint_template_manager.get(
- dtenant_endpoint.endpoint_template_id)
- dservice = self.service_manager.get(dendpoint_template.service_id)
- ts.append(Endpoint(
- dtenant_endpoint.id,
- dtenant_endpoint.tenant_id,
- dendpoint_template.region,
- dservice.name,
- dservice.type,
- dendpoint_template.public_url,
- dendpoint_template.admin_url,
- dendpoint_template.internal_url,
- dendpoint_template.version_id,
- dendpoint_template.version_list,
- dendpoint_template.version_info
- ))
- links = []
- if ts.__len__():
- prev, next = \
- self.endpoint_manager.endpoint_get_by_tenant_get_page_markers(
- tenant_id, marker, limit)
- links = self.get_links(url, prev, next, limit)
- return Endpoints(ts, links)
-
- @service_admin_token_validator
- def create_endpoint_for_tenant(self, admin_token, tenant_id,
- endpoint_template):
- utils.check_empty_string(tenant_id, "Expecting a Tenant Id.")
- if self.tenant_manager.get(tenant_id) is None:
- raise fault.ItemNotFoundFault("The tenant not found")
-
- dendpoint_template = self.endpoint_template_manager.get(
- endpoint_template.id)
- if not dendpoint_template:
- raise fault.ItemNotFoundFault(
- "The endpoint template could not be found")
- dendpoint = models.Endpoints()
- dendpoint.tenant_id = tenant_id
- dendpoint.endpoint_template_id = endpoint_template.id
- dendpoint = self.endpoint_manager.create(dendpoint)
- dservice = self.service_manager.get(dendpoint_template.service_id)
- dendpoint = Endpoint(
- dendpoint.id,
- dendpoint.tenant_id,
- dendpoint_template.region,
- dservice.name,
- dservice.type,
- dendpoint_template.public_url,
- dendpoint_template.admin_url,
- dendpoint_template.internal_url,
- dendpoint_template.version_id,
- dendpoint_template.version_list,
- dendpoint_template.version_info
- )
- return dendpoint
-
- @service_admin_token_validator
- def delete_endpoint(self, admin_token, endpoint_id):
- if self.endpoint_manager.get(endpoint_id) is None:
- raise fault.ItemNotFoundFault("The Endpoint is not found.")
- self.endpoint_manager.delete(endpoint_id)
- return None
-
- #Service Operations
- @service_admin_token_validator
- def create_service(self, admin_token, service):
- if not isinstance(service, Service):
- raise fault.BadRequestFault("Expecting a Service")
-
- if self.service_manager.get_by_name(service.name) is not None:
- raise fault.ServiceConflictFault(
- "A service with that name already exists")
-
- user = self._validate_token(admin_token)[1]
-
- dservice = models.Service()
- dservice.name = service.name
- dservice.type = service.type
- dservice.desc = service.description
- dservice.owner_id = user.id
- dservice = self.service_manager.create(dservice)
- service.id = dservice.id
-
- return service
-
- @service_admin_token_validator
- def get_services(self, admin_token, marker, limit, url):
- ts = []
- dservices = self.service_manager.get_page(marker, limit)
- for dservice in dservices:
- ts.append(Service(dservice.id, dservice.name, dservice.type,
- dservice.desc))
- prev, next = self.service_manager.get_page_markers(marker, limit)
- links = self.get_links(url, prev, next, limit)
- return Services(ts, links)
-
- @service_admin_token_validator
- def get_service(self, admin_token, service_id):
- dservice = self.service_manager.get(service_id)
- if not dservice:
- raise fault.ItemNotFoundFault("The service could not be found")
- return Service(dservice.id, dservice.name, dservice.type,
- dservice.desc)
-
- @service_admin_token_validator
- def get_service_by_name(self, admin_token, service_name):
- dservice = self.service_manager.get_by_name(service_name)
- if not dservice:
- raise fault.ItemNotFoundFault("The service could not be found")
- return Service(dservice.id, dservice.name, dservice.type,
- dservice.desc)
-
- @service_admin_token_validator
- def delete_service(self, admin_token, service_id):
- dservice = self.service_manager.get(service_id)
-
- if not dservice:
- raise fault.ItemNotFoundFault("The service could not be found")
-
- #Delete Related Endpointtemplates and Endpoints.
- endpoint_templates = self.endpoint_template_manager.get_by_service(
- service_id)
- if endpoint_templates is not None:
- for endpoint_template in endpoint_templates:
- endpoints = self.endpoint_manager.\
- endpoint_get_by_endpoint_template(endpoint_template.id)
- if endpoints is not None:
- for endpoint in endpoints:
- self.endpoint_manager.delete(endpoint.id)
- self.endpoint_template_manager.delete(endpoint_template.id)
- #Delete Related Role and RoleRefs
- roles = self.role_manager.get_by_service(service_id)
- if roles is not None:
- for role in roles:
- rolegrants = self.grant_manager.rolegrant_list_by_role(role.id)
- if rolegrants is not None:
- for rolegrant in rolegrants:
- self.grant_manager.rolegrant_delete(rolegrant.id)
- self.role_manager.delete(role.id)
- self.service_manager.delete(service_id)
-
- @admin_token_validator
- def get_credentials(self, admin_token, user_id, marker, limit, url):
- ts = []
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- ts.append(PasswordCredentials(duser.name, None))
- links = []
- return Credentials(ts, links)
-
- @admin_token_validator
- def get_password_credentials(self, admin_token, user_id):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- if not duser.password:
- raise fault.ItemNotFoundFault(
- "Password credentials could not be found")
- return PasswordCredentials(duser.name, None)
-
- @admin_token_validator
- def delete_password_credentials(self, admin_token, user_id):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
- values = {'id': user_id, 'password': None}
- self.user_manager.update(values)
-
- @admin_token_validator
- def update_password_credentials(self, admin_token, user_id,
- password_credentials):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- if (password_credentials.user_name is None
- or not password_credentials.user_name.strip()):
- raise fault.BadRequestFault("Expecting a username.")
- duser_name = self.user_manager.get_by_name(
- password_credentials.user_name)
- if duser_name.id != duser.id:
- raise fault.UserConflictFault(
- "A user with that name already exists")
- values = {'id': user_id, 'password': password_credentials.password,
- 'name': password_credentials.user_name}
- self.user_manager.update(values)
- duser = self.user_manager.get(user_id)
- return PasswordCredentials(duser.name, duser.password)
-
- @admin_token_validator
- def create_password_credentials(self, admin_token, user_id,
- password_credentials):
- duser = self.user_manager.get(user_id)
- if not duser:
- raise fault.ItemNotFoundFault("The user could not be found")
-
- if password_credentials.user_name is None or\
- not password_credentials.user_name.strip():
- raise fault.BadRequestFault("Expecting a username.")
-
- if password_credentials.user_name != duser.name:
- duser_name = self.user_manager.get_by_name(
- password_credentials.user_name)
- if duser_name:
- raise fault.UserConflictFault(
- "A user with that name already exists")
- if duser.password:
- raise fault.BadRequestFault(
- "Password credentials already available.")
- values = {'id': user_id, 'password': password_credentials.password,
- 'name': password_credentials.user_name}
- self.user_manager.update(values)
- duser = self.user_manager.get(user_id)
- return PasswordCredentials(duser.name, duser.password)
-
- @staticmethod
- def get_links(url, prev, next, limit):
- """Method to form and return pagination links."""
- links = []
- if prev:
- links.append(atom.Link('prev', "%s?marker=%s&limit=%s" \
- % (url, prev, limit)))
- if next:
- links.append(atom.Link('next', "%s?marker=%s&limit=%s" \
- % (url, next, limit)))
- return links
diff --git a/keystone/logic/signer.py b/keystone/logic/signer.py
deleted file mode 100644
index 4ca171be..00000000
--- a/keystone/logic/signer.py
+++ /dev/null
@@ -1,166 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-#
-# PORTIONS OF THIS FILE ARE FROM:
-# http://code.google.com/p/boto
-# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
-#
-# Permission is hereby granted, free of charge, to any person obtaining a
-# copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish, dis-
-# tribute, sublicense, and/or sell copies of the Software, and to permit
-# persons to whom the Software is furnished to do so, subject to the fol-
-# lowing conditions:
-#
-# The above copyright notice and this permission notice shall be included
-# in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
-# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
-# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
-# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
-# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
-# IN THE SOFTWARE.
-
-"""
-Utility class for parsing signed AMI manifests.
-"""
-
-import base64
-import hashlib
-import hmac
-import logging
-import urllib
-
-
-LOG = logging.getLogger('keystone.signer')
-
-
-class Signer(object):
- """Hacked up code from boto/connection.py"""
-
- # pylint: disable=E1101
- def __init__(self, secret_key):
- secret_key = secret_key.encode()
- self.hmac = hmac.new(secret_key, digestmod=hashlib.sha1)
- if hashlib.sha256:
- self.hmac_256 = hmac.new(secret_key, digestmod=hashlib.sha256)
-
- def generate(self, credentials, s3=False):
- """Generate auth string according to what SignatureVersion is given."""
- if s3:
- return self._calc_signature_s3(credentials.verb,
- credentials.expire,
- credentials.path,
- credentials.content_type,
- credentials.content_md5,
- credentials.xheaders)
- if credentials.params['SignatureVersion'] == '0':
- return self._calc_signature_0(credentials.params)
- if credentials.params['SignatureVersion'] == '1':
- return self._calc_signature_1(credentials.params)
- if credentials.params['SignatureVersion'] == '2':
- return self._calc_signature_2(credentials.params,
- credentials.verb,
- credentials.host,
- credentials.path)
- raise Exception('Unknown Signature Version: %s' %
- credentials.params['SignatureVersion'])
-
- @staticmethod
- def _get_utf8_value(value):
- """Get the UTF8-encoded version of a value."""
- if not isinstance(value, str) and not isinstance(value, unicode):
- value = str(value)
- if isinstance(value, unicode):
- return value.encode('utf-8')
- else:
- return value
-
- def _calc_signature_0(self, params):
- """Generate AWS signature version 0 string."""
- s = params['Action'] + params['Timestamp']
- self.hmac.update(s)
- return base64.b64encode(self.hmac.digest())
-
- def _calc_signature_1(self, params):
- """Generate AWS signature version 1 string."""
- keys = params.keys()
- keys.sort(cmp=lambda x, y: cmp(x.lower(), y.lower()))
- for key in keys:
- self.hmac.update(key)
- val = self._get_utf8_value(params[key])
- self.hmac.update(val)
- return base64.b64encode(self.hmac.digest())
-
- def _calc_signature_2(self, params, verb, server_string, path):
- """Generate AWS signature version 2 string."""
- LOG.debug('using _calc_signature_2')
- string_to_sign = '%s\n%s\n%s\n' % (verb, server_string, path)
- if self.hmac_256:
- current_hmac = self.hmac_256
- params['SignatureMethod'] = 'HmacSHA256'
- else:
- current_hmac = self.hmac
- params['SignatureMethod'] = 'HmacSHA1'
- keys = params.keys()
- keys.sort()
- pairs = []
- for key in keys:
- val = self._get_utf8_value(params[key])
- val = urllib.quote(val, safe='-_~')
- pairs.append(urllib.quote(key, safe='') + '=' + val)
- qs = '&'.join(pairs)
- LOG.debug('query string: %s', qs)
- string_to_sign += qs
- LOG.debug('string_to_sign: %s', string_to_sign)
- current_hmac.update(string_to_sign)
- b64 = base64.b64encode(current_hmac.digest())
- LOG.debug('len(b64)=%d', len(b64))
- LOG.debug('base64 encoded digest: %s', b64)
- return b64
-
- # pylint: disable=R0913
- def _calc_signature_s3(self, verb, expire, path, content_type, content_md5,
- xheaders):
- """Generate AWS signature for S3 string."""
- LOG.debug('using _calc_signature_s3')
- string_to_sign = '%s\n%s\n%s\n%s\n' % (
- verb, content_md5, content_type, expire)
- if xheaders:
- xheader_keys = xheaders.keys()
- xheader_keys.sort()
- for key in xheader_keys:
- string_to_sign += '%s:%s\n' % (key, xheaders[key])
- string_to_sign += path
- current_hmac = self.hmac
- LOG.debug('string_to_sign: %s', string_to_sign)
- current_hmac.update(string_to_sign)
- b64 = base64.b64encode(current_hmac.digest())
- LOG.debug('len(b64)=%d', len(b64))
- LOG.debug('base64 encoded digest: %s', b64)
- return b64
-
-
-if __name__ == '__main__':
- # pylint: disable=E1121
- print Signer('foo').generate({'SignatureMethod': 'HmacSHA256',
- 'SignatureVersion': '2'},
- 'get', 'server', '/foo')
diff --git a/keystone/logic/types/__init__.py b/keystone/logic/types/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/logic/types/__init__.py
+++ /dev/null
diff --git a/keystone/logic/types/atom.py b/keystone/logic/types/atom.py
deleted file mode 100644
index a4e03a9f..00000000
--- a/keystone/logic/types/atom.py
+++ /dev/null
@@ -1,57 +0,0 @@
-# Copyright (c) 2010-2011 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.
-
-# pylint: disable=C0103
-
-from lxml import etree
-
-
-class Link(object):
- """An atom link"""
-
- def __init__(self, rel, href, link_type=None, hreflang=None, title=None):
- self.rel = rel
- self.href = href
- self.link_type = link_type
- self.hreflang = hreflang
- self.title = title
-
- def to_dict(self):
- links = {}
- if self.link_type:
- links["link_type"] = self.link_type
- if self.hreflang:
- links["hreflang"] = self.hreflang
- if self.title:
- links["title"] = self.title
-
- links["rel"] = self.rel
- links["href"] = self.href
- return {'links': links}
-
- def to_dom(self):
- ATOM_NAMESPACE = "http://www.w3.org/2005/Atom"
- ATOM = "{%s}" % ATOM_NAMESPACE
- NSMAP = {'atom': ATOM_NAMESPACE}
- dom = etree.Element(ATOM + "link", nsmap=NSMAP)
- if self.link_type:
- dom.set("link_type", self.link_type)
- if self.link_type:
- dom.set("hreflang", self.hreflang)
- if self.title:
- dom.set("title", self.title)
- dom.set("rel", self.rel)
- dom.set("href", self.href)
- return dom
diff --git a/keystone/logic/types/auth.py b/keystone/logic/types/auth.py
deleted file mode 100755
index ace6aa6b..00000000
--- a/keystone/logic/types/auth.py
+++ /dev/null
@@ -1,673 +0,0 @@
-# Copyright (c) 2010-2011 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.
-
-# pylint: disable=C0103,R0912,R0913,R0914
-
-import json
-from lxml import etree
-from keystone.logic.types import fault
-import keystone.backends.api as db_api
-from keystone import utils
-
-
-class AuthBase(object):
- def __init__(self, tenant_id=None, tenant_name=None):
- self.tenant_id = tenant_id
- self.tenant_name = tenant_name
-
- @staticmethod
- def _validate_auth(obj, *valid_keys):
- if not 'auth' in obj:
- raise fault.BadRequestFault('Expecting auth')
-
- auth = obj.get('auth')
-
- for key in auth:
- if not key in valid_keys:
- raise fault.BadRequestFault('Invalid attribute(s): %s' % key)
-
- if auth.get('tenantId') and auth.get('tenantName'):
- raise fault.BadRequestFault(
- 'Expecting either Tenant ID or Tenant Name, but not both')
-
- return auth
-
- @staticmethod
- def _validate_key(obj, key, *required_keys):
- if not key in obj:
- raise fault.BadRequestFault('Expecting %s' % key)
-
- ret = obj[key]
-
- for skey in ret:
- if not skey in required_keys:
- raise fault.BadRequestFault('Invalid attribute(s): %s' % skey)
-
- for required_key in required_keys:
- if not ret.get(required_key):
- raise fault.BadRequestFault('Expecting %s:%s' %
- (key, required_key))
- return ret
-
-
-class AuthWithUnscopedToken(AuthBase):
- def __init__(self, token_id, tenant_id=None, tenant_name=None):
- super(AuthWithUnscopedToken, self).__init__(tenant_id, tenant_name)
- self.token_id = token_id
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "auth")
- if root is None:
- raise fault.BadRequestFault("Expecting auth")
- token = root.find("{http://docs.openstack.org/identity/api/v2.0}"
- "token")
- if token is None:
- raise fault.BadRequestFault("Expecting token")
-
- token_id = token.get("id")
- tenant_id = root.get("tenantId")
- tenant_name = root.get("tenantName")
- utils.check_empty_string(token_id, "Expecting a token id.")
- if tenant_id and tenant_name:
- raise fault.BadRequestFault(
- "Expecting either Tenant ID or Tenant Name, but not both")
-
- return AuthWithUnscopedToken(token_id, tenant_id, tenant_name)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse password access", str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
-
- auth = AuthBase._validate_auth(obj, 'tenantId', 'tenantName',
- 'token')
- token = AuthBase._validate_key(auth, 'token', 'id')
-
- return AuthWithUnscopedToken(token['id'],
- auth.get('tenantId'),
- auth.get('tenantName'))
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse auth", str(e))
-
-
-class AuthWithPasswordCredentials(AuthBase):
- def __init__(self, username, password, tenant_id=None, tenant_name=None):
- super(AuthWithPasswordCredentials, self).__init__(tenant_id,
- tenant_name)
- self.username = username
- self.password = password
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "auth")
- if root is None:
- raise fault.BadRequestFault("Expecting auth")
- tenant_id = root.get("tenantId")
- tenant_name = root.get("tenantName")
- password_credentials = \
- root.find("{http://docs.openstack.org/identity/api/v2.0}"
- "passwordCredentials")
- if password_credentials is None:
- raise fault.BadRequestFault("Expecting passwordCredentials")
- username = password_credentials.get("username")
- utils.check_empty_string(username, "Expecting a username")
- password = password_credentials.get("password")
- utils.check_empty_string(password, "Expecting a password")
-
- if tenant_id and tenant_name:
- raise fault.BadRequestFault(
- "Expecting either Tenant ID or Tenant Name, but not both")
-
- return AuthWithPasswordCredentials(username, password, tenant_id,
- tenant_name)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse password access", str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
-
- auth = AuthBase._validate_auth(obj, 'tenantId', 'tenantName',
- 'passwordCredentials', 'token')
- cred = AuthBase._validate_key(auth, 'passwordCredentials',
- 'username', 'password')
-
- return AuthWithPasswordCredentials(cred['username'],
- cred['password'],
- auth.get('tenantId'),
- auth.get('tenantName'))
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse auth", str(e))
-
-
-class Ec2Credentials(object):
- """Credentials based on username, access_key, signature and data.
-
- @type access: str
- @param access: Access key for user in the form of access:project.
-
- @type signature: str
- @param signature: Signature of the request.
-
- @type params: dictionary of str
- @param params: Web paramaters used for the signature.
-
- @type verb: str
- @param verb: Web request verb ('GET' or 'POST').
-
- @type host: str
- @param host: Web request host string (including port).
-
- @type path: str
- @param path: Web request path.
-
- """
-
- def __init__(self, access, signature, verb,
- host, path, params):
- self.access = access
- self.signature = signature
- self.verb = verb
- self.host = host
- self.path = path
- self.params = params
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "auth")
- xmlns = "http://docs.openstack.org/identity/api/ext/OS-KSEC2/v1.0"
- if root is None:
- root = dom.find("{%s}ec2Credentials" % xmlns)
- else:
- root = root.find("{%s}ec2Credentials" % xmlns)
- if root is None:
- raise fault.BadRequestFault("Expecting ec2Credentials")
- access = root.get("key")
- utils.check_empty_string(access, "Expecting an access key.")
- signature = root.get("signature")
- utils.check_empty_string(signature, "Expecting a signature.")
- verb = root.get("verb")
- utils.check_empty_string(verb, "Expecting a verb.")
- host = root.get("host")
- utils.check_empty_string(signature, "Expecting a host.")
- path = root.get("path")
- utils.check_empty_string(signature, "Expecting a path.")
- # TODO(vish): parse xml params
- params = {}
- return Ec2Credentials(access, signature, verb, host, path, params)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse password credentials",
- str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- root = json.loads(json_str)
- if "auth" in root:
- obj = root['auth']
- else:
- obj = root
-
- if "OS-KSEC2:ec2Credentials" in obj:
- cred = obj["OS-KSEC2:ec2Credentials"]
- elif "ec2Credentials" in obj:
- cred = obj["ec2Credentials"]
- else:
- raise fault.BadRequestFault("Expecting ec2Credentials")
- # Check that fields are valid
- invalid = [key for key in cred if key not in\
- ['username', 'access', 'signature', 'params',
- 'verb', 'host', 'path']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
- if not "access" in cred:
- raise fault.BadRequestFault("Expecting an access key")
- access = cred["access"]
- if not "signature" in cred:
- raise fault.BadRequestFault("Expecting a signature")
- signature = cred["signature"]
- if not "verb" in cred:
- raise fault.BadRequestFault("Expecting a verb")
- verb = cred["verb"]
- if not "host" in cred:
- raise fault.BadRequestFault("Expecting a host")
- host = cred["host"]
- if not "path" in cred:
- raise fault.BadRequestFault("Expecting a path")
- path = cred["path"]
- if not "params" in cred:
- raise fault.BadRequestFault("Expecting params")
- params = cred["params"]
- return Ec2Credentials(access, signature, verb, host, path, params)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse password credentials",
- str(e))
-
-
-# pylint: disable=R0902
-class S3Credentials(object):
- """Credentials based on username, access_key, signature and data.
-
- @type access: str
- @param access: Access key for user in the form of access:project.
-
- @type signature: str
- @param signature: Signature of the request.
-
- @type verb: str
- @param verb: Web request verb ('GET' or 'POST').
-
- @type host: expire
- @param host: Web request expire time.
-
- @type path: str
- @param path: Web request path.
-
- @type expire: str
- @param expire: Web request expire.
-
- @type content_type: str
- @param content_type: Web request content contenttype.
-
- @type content_md5: str
- @param content_md5: Web request content contentmd5.
-
- @type xheaders: str
- @param xheaders: Web request content extended headers.
-
- """
-
- def __init__(self, access, signature, verb, path, expire, content_type,
- content_md5, xheaders):
- self.access = access
- self.signature = signature
- self.verb = verb
- self.path = path
- self.expire = expire
- self.content_type = content_type
- self.content_md5 = content_md5
- self.xheaders = xheaders
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "auth")
- xmlns = "http://docs.openstack.org/identity/api/ext/OS-KSS3/v1.0"
- if root is None:
- root = dom.find("{%s}s3Credentials" % xmlns)
- else:
- root = root.find("{%s}s3Credentials" % xmlns)
-
- if root is None:
- raise fault.BadRequestFault("Expecting s3Credentials")
- access = root.get("access")
- if access == None:
- raise fault.BadRequestFault("Expecting an access key")
- signature = root.get("signature")
- if signature == None:
- raise fault.BadRequestFault("Expecting a signature")
- verb = root.get("verb")
- if verb == None:
- raise fault.BadRequestFault("Expecting a verb")
- path = root.get("path")
- if path == None:
- raise fault.BadRequestFault("Expecting a path")
- expire = root.get("expire")
- if expire == None:
- raise fault.BadRequestFault("Expecting a expire")
- content_type = root.get("content_type", '')
- content_md5 = root.get("content_md5", '')
- xheaders = root.get("xheaders", None)
- return S3Credentials(access, signature, verb, path, expire,
- content_type, content_md5, xheaders)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse password credentials",
- str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- root = json.loads(json_str)
- if "auth" in root:
- obj = root['auth']
- else:
- obj = root
-
- if "OS-KSS3:s3Credentials" in obj:
- cred = obj["OS-KSS3:s3Credentials"]
- elif "s3Credentials" in obj:
- cred = obj["s3Credentials"]
- else:
- raise fault.BadRequestFault("Expecting s3Credentials")
-
- # Check that fields are valid
- invalid = [key for key in cred if key not in\
- ['username', 'access', 'signature', 'verb', 'expire',
- 'path', 'content_type', 'content_md5', 'xheaders']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
- if not "access" in cred:
- raise fault.BadRequestFault("Expecting an access key")
- access = cred["access"]
- if not "signature" in cred:
- raise fault.BadRequestFault("Expecting a signature")
- signature = cred["signature"]
- if not "verb" in cred:
- raise fault.BadRequestFault("Expecting a verb")
- verb = cred["verb"]
- if not "path" in cred:
- raise fault.BadRequestFault("Expecting a path")
- path = cred["path"]
- if not "expire" in cred:
- raise fault.BadRequestFault("Expecting a expire")
- expire = cred["expire"]
- content_type = cred.get("content_type", '')
- content_md5 = cred.get("content_md5", '')
- xheaders = cred.get("xheaders", None)
- return S3Credentials(access, signature, verb, path, expire,
- content_type, content_md5, xheaders)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse password credentials",
- str(e))
-
-
-class Tenant(object):
- """Provides the scope of a token"""
-
- def __init__(self, id, name):
- self.id = id
- self.name = name
-
-
-class Token(object):
- """An auth token."""
-
- def __init__(self, expires, token_id, tenant=None):
- assert tenant is None or isinstance(tenant, Tenant)
-
- self.expires = expires
- self.id = token_id
- self.tenant = tenant
-
-
-class User(object):
- """A user."""
-
- id = None
- username = None
- tenant_id = None
- tenant_name = None
- rolegrants = None
-
- def __init__(self, id, username, tenant_id, tenant_name, rolegrants=None):
- self.id = id
- self.username = username
- self.tenant_id = tenant_id
- self.tenant_name = tenant_name
- self.rolegrants = rolegrants
-
-
-class AuthData(object):
- """Authentation Information returned upon successful login.
-
- This class handles rendering to JSON and XML. It renders
- the token, the user data, the roles, and the service catalog.
-
- The list of endpoint URLs in the service catalog can be filtered by
- URL type. For example, when we respond to a public call from a user
- without elevated privileges, the "adminURL" is not returned. The
- url_types paramater in the initializer lists the types to return.
- The actual authorization is done in logic/service.py
- """
-
- def __init__(self, token, user, base_urls=None, url_types=None):
- self.token = token
- self.user = user
- self.base_urls = base_urls
- if url_types is None:
- self.url_types = ["internal", "public", "admin"]
- else:
- self.url_types = url_types
- self.d = {}
- if self.base_urls is not None:
- self.__convert_baseurls_to_dict()
-
- def to_xml(self):
- dom = etree.Element("access",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- token = etree.Element("token",
- expires=self.token.expires.isoformat())
- token.set("id", self.token.id)
- if self.token.tenant:
- tenant = etree.Element("tenant",
- id=unicode(self.token.tenant.id),
- name=unicode(self.token.tenant.name))
- token.append(tenant)
- dom.append(token)
-
- user = etree.Element("user",
- id=unicode(self.user.id),
- name=unicode(self.user.username))
- dom.append(user)
-
- if self.user.rolegrants is not None:
- user.append(self.user.rolegrants.to_dom())
-
- if self.base_urls is not None and len(self.base_urls) > 0:
- service_catalog = etree.Element("serviceCatalog")
- for key, key_base_urls in self.d.items():
- dservice = db_api.SERVICE.get(key)
- if not dservice:
- raise fault.ItemNotFoundFault(
- "The service could not be found")
- service = etree.Element("service",
- name=dservice.name, type=dservice.type)
- for base_url in key_base_urls:
- include_this_endpoint = False
- endpoint = etree.Element("endpoint")
- if base_url.region:
- endpoint.set("region", base_url.region)
- for url_kind in self.url_types:
- base_url_item = getattr(base_url, url_kind + "_url")
- if base_url_item:
- if '%tenant_id%' in base_url_item:
- if self.token.tenant:
- # Don't return tenant endpoints if token
- # not scoped to a tenant
- endpoint.set(url_kind + "URL",
- base_url_item.replace('%tenant_id%',
- str(self.token.tenant.id)))
- endpoint.set('tenantId',
- str(self.token.tenant.id))
- include_this_endpoint = True
- else:
- endpoint.set(url_kind + "URL", base_url_item)
- include_this_endpoint = True
- if include_this_endpoint:
- endpoint.set("id", str(base_url.id))
- if hasattr(base_url, "version_id"):
- if base_url.version_id:
- endpoint.set("versionId",
- str(base_url.version_id))
- service.append(endpoint)
- if service.find("endpoint") is not None:
- service_catalog.append(service)
- dom.append(service_catalog)
- return etree.tostring(dom)
-
- def __convert_baseurls_to_dict(self):
- for base_url in self.base_urls:
- if base_url.service_id not in self.d:
- self.d[base_url.service_id] = list()
- self.d[base_url.service_id].append(base_url)
-
- def to_json(self):
- token = {}
- token["id"] = self.token.id
- token["expires"] = self.token.expires.isoformat()
- if self.token.tenant:
- tenant = {
- 'id': unicode(self.token.tenant.id),
- 'name': unicode(self.token.tenant.name)}
- token['tenant'] = tenant # v2.0/Diablo contract
- token['tenants'] = [tenant] # missed use case in v2.0
- auth = {}
- auth["token"] = token
- auth['user'] = {
- 'id': unicode(self.user.id),
- 'name': unicode(self.user.username)}
-
- if self.user.rolegrants is not None:
- auth['user']["roles"] = self.user.rolegrants.to_json_values()
-
- if self.base_urls is not None and len(self.base_urls) > 0:
- service_catalog = []
- for key, key_base_urls in self.d.items():
- service = {}
- endpoints = []
- for base_url in key_base_urls:
- include_this_endpoint = False
- endpoint = {}
- if base_url.region:
- endpoint["region"] = base_url.region
- for url_kind in self.url_types:
- base_url_item = getattr(base_url, url_kind + "_url")
- if base_url_item:
- if '%tenant_id%' in base_url_item:
- if self.token.tenant:
- # Don't return tenant endpoints if token
- # not scoped to a tenant
- endpoint[url_kind + "URL"] = \
- base_url_item.replace('%tenant_id%',
- str(self.token.tenant.id))
- endpoint['tenantId'] = \
- str(self.token.tenant.id)
- include_this_endpoint = True
- else:
- endpoint[url_kind + "URL"] = base_url_item
- include_this_endpoint = True
- if include_this_endpoint:
- endpoint['id'] = str(base_url.id)
- if hasattr(base_url, 'version_id'):
- if base_url.version_id:
- endpoint['versionId'] = \
- str(base_url.version_id)
- endpoints.append(endpoint)
- dservice = db_api.SERVICE.get(key)
- if not dservice:
- raise fault.ItemNotFoundFault(
- "The service could not be found for" + str(key))
- if len(endpoints):
- service["name"] = dservice.name
- service["type"] = dservice.type
- service["endpoints"] = endpoints
- service_catalog.append(service)
- auth["serviceCatalog"] = service_catalog
- ret = {}
- ret["access"] = auth
- return json.dumps(ret)
-
-
-class ValidateData(object):
- """Authentation Information returned upon successful token validation."""
-
- token = None
- user = None
-
- def __init__(self, token, user):
- self.token = token
- self.user = user
-
- def to_xml(self):
- dom = etree.Element("access",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
-
- token = etree.Element("token",
- id=unicode(self.token.id),
- expires=self.token.expires.isoformat())
-
- if self.token.tenant:
- tenant = etree.Element("tenant",
- id=unicode(self.token.tenant.id),
- name=unicode(self.token.tenant.name))
- token.append(tenant)
-
- user = etree.Element("user",
- id=unicode(self.user.id),
- name=unicode(self.user.username))
-
- if self.user.tenant_id is not None:
- user.set('tenantId', unicode(self.user.tenant_id))
- if self.user.tenant_name is not None:
- user.set('tenantName', unicode(self.user.tenant_name))
-
- if self.user.rolegrants is not None:
- user.append(self.user.rolegrants.to_dom())
-
- dom.append(token)
- dom.append(user)
- return etree.tostring(dom)
-
- def to_json(self):
- token = {
- "id": unicode(self.token.id),
- "expires": self.token.expires.isoformat()}
-
- if self.token.tenant:
- tenant = {
- 'id': unicode(self.token.tenant.id),
- 'name': unicode(self.token.tenant.name)}
- token['tenant'] = tenant # v2.0/Diablo contract
- token['tenants'] = [tenant] # missed use case in v2.0
-
- user = {
- "id": unicode(self.user.id),
- "name": unicode(self.user.username),
- # TODO(ziad) temporary until we are comfortable clients are updated
- "username": unicode(self.user.username)}
-
- if self.user.tenant_id is not None:
- user['tenantId'] = unicode(self.user.tenant_id)
- if self.user.tenant_name is not None:
- user['tenantName'] = unicode(self.user.tenant_name)
-
- if self.user.rolegrants is not None:
- user["roles"] = self.user.rolegrants.to_json_values()
-
- return json.dumps({
- "access": {
- "token": token,
- "user": user}})
diff --git a/keystone/logic/types/credential.py b/keystone/logic/types/credential.py
deleted file mode 100644
index 40e99f3c..00000000
--- a/keystone/logic/types/credential.py
+++ /dev/null
@@ -1,125 +0,0 @@
-# Copyright (c) 2010-2011 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
-from lxml import etree
-
-from keystone.logic.types import fault
-from keystone import utils
-
-
-class PasswordCredentials(object):
- def __init__(self, user_name, password):
- self.user_name = user_name
- self.password = password
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}" \
- "passwordCredentials")
- if root is None:
- raise fault.BadRequestFault("Expecting passwordCredentials")
- user_name = root.get("username")
- password = root.get("password")
- utils.check_empty_string(password, "Expecting a password.")
- return PasswordCredentials(user_name, password)
- except etree.LxmlError as e:
- raise fault.BadRequestFault(
- "Cannot parse passwordCredentials", str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
- if not "passwordCredentials" in obj:
- raise fault.BadRequestFault("Expecting passwordCredentials")
- password_credentials = obj["passwordCredentials"]
-
- # Check that fields are valid
- invalid = [key for key in password_credentials if key not in\
- ['username', 'password']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
-
- user_name = password_credentials.get('username')
- password = password_credentials.get('password')
- utils.check_empty_string(password, "Expecting a password.")
- return PasswordCredentials(user_name, password)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault(
- "Cannot parse passwordCredentials", str(e))
-
- def to_dom(self):
- dom = etree.Element("passwordCredentials",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- if self.user_name:
- dom.set("username", unicode(self.user_name))
- if self.password:
- dom.set("password", unicode(self.password))
- return dom
-
- def to_xml(self):
- return etree.tostring(self.to_dom())
-
- def to_dict(self):
- password_credentials = {}
- if self.user_name:
- password_credentials["username"] = unicode(self.user_name)
- if self.password:
- password_credentials['password'] = unicode(self.password)
- return {'passwordCredentials': password_credentials}
-
- def to_json(self):
- return json.dumps(self.to_dict())
-
-
-class Credentials(object):
- "A collection of credentials."
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("credentials")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return etree.tostring(dom)
-
- def to_dom(self):
- dom = etree.Element("credentials")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return dom
-
- def to_json(self):
- values = [t.to_dict() for t in self.values]
- links = [t.to_dict()["links"] for t in self.links]
- return json.dumps({"credentials": values, "credentials_links": links})
diff --git a/keystone/logic/types/endpoint.py b/keystone/logic/types/endpoint.py
deleted file mode 100644
index 3b4c8d64..00000000
--- a/keystone/logic/types/endpoint.py
+++ /dev/null
@@ -1,363 +0,0 @@
-# Copyright (c) 2010-2011 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
-from lxml import etree
-from keystone.logic.types import fault
-
-
-class EndpointTemplate(object):
- """Document me!"""
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find(
- "{http://docs.openstack.org/identity"\
- "/api/ext/OS-KSCATALOG/v1.0}" \
- "endpointTemplate")
- if root is None:
- raise fault.BadRequestFault("Expecting endpointTemplate")
- id = root.get("id")
- region = root.get("region")
- name = root.get("name")
- type = root.get("type")
- public_url = root.get("publicURL")
- admin_url = root.get("adminURL")
- internal_url = root.get("internalURL")
- enabled = root.get("enabled")
- is_global = root.get("global")
- version = root.find(
- "{http://docs.openstack.org/identity/"\
- "api/v2.0}" \
- "version")
- version_id = None
- version_info = None
- version_list = None
- if version is not None:
- if version.get('id'):
- version_id = version.get("id")
- if version.get('info'):
- version_info = version.get("info")
- if version.get('list'):
- version_list = version.get("list")
-
- return EndpointTemplate(id, region,
- name, type, public_url, admin_url,
- internal_url, enabled, is_global,
- version_id, version_list, version_info)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse endpointTemplate",
- str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
- region = None
- name = None
- type = None
- public_url = None
- admin_url = None
- internal_url = None
- enabled = None
- is_global = None
- version_id = None
- version_list = None
- version_info = None
- if not "OS-KSCATALOG:endpointTemplate" in obj:
- raise fault.BadRequestFault(
- "Expecting OS-KSCATALOG:endpointTemplate")
- endpoint_template = obj["OS-KSCATALOG:endpointTemplate"]
-
- # Check that fields are valid
- invalid = [key for key in endpoint_template if key not in
- ['id', 'region', 'name', 'type', 'publicURL',
- 'adminURL', 'internalURL', 'enabled', 'global',
- 'versionId', 'versionInfo', 'versionList']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
-
- if not "id" in endpoint_template:
- id = None
- else:
- id = endpoint_template["id"]
-
- if 'region' in endpoint_template:
- region = endpoint_template["region"]
- if 'name' in endpoint_template:
- name = endpoint_template["name"]
- if 'type' in endpoint_template:
- type = endpoint_template["type"]
- if 'publicURL' in endpoint_template:
- public_url = endpoint_template["publicURL"]
- if 'adminURL' in endpoint_template:
- admin_url = endpoint_template["adminURL"]
- if 'internalURL' in endpoint_template:
- internal_url = endpoint_template["internalURL"]
- if 'enabled' in endpoint_template:
- enabled = endpoint_template["enabled"]
- if 'global' in endpoint_template:
- is_global = endpoint_template["global"]
- if 'versionId' in endpoint_template:
- version_id = endpoint_template["versionId"]
- else:
- version_id = None
- if 'versionInfo' in endpoint_template:
- version_info = endpoint_template["versionInfo"]
- else:
- version_info = None
- if 'versionList' in endpoint_template:
- version_list = endpoint_template["versionList"]
- else:
- version_list = None
-
- return EndpointTemplate(
- id, region, name, type, public_url, admin_url,
- internal_url, enabled, is_global, version_id,
- version_list, version_info)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault(\
- "Cannot parse endpointTemplate", str(e))
-
- def __init__(self, id, region, name, type, public_url, admin_url,
- internal_url, enabled, is_global,
- version_id=None, version_list=None, version_info=None):
- self.id = id
- self.region = region
- self.name = name
- self.type = type
- self.public_url = public_url
- self.admin_url = admin_url
- self.internal_url = internal_url
- self.enabled = bool(enabled)
- self.is_global = bool(is_global)
- self.version_id = version_id
- self.version_list = version_list
- self.version_info = version_info
-
- def to_dom(self):
- dom = etree.Element("endpointTemplate",
- xmlns="http://docs.openstack.org/"
- "identity/api/ext/OS-KSCATALOG/v1.0")
- if self.id:
- dom.set("id", str(self.id))
- if self.region:
- dom.set("region", self.region)
- if self.name:
- dom.set("name", str(self.name))
- if self.type:
- dom.set("type", str(self.type))
- if self.public_url:
- dom.set("publicURL", self.public_url)
- if self.admin_url:
- dom.set("adminURL", self.admin_url)
- if self.internal_url:
- dom.set("internalURL", self.internal_url)
- if self.enabled:
- dom.set("enabled", str(self.enabled).lower())
- if self.is_global:
- dom.set("global", str(self.is_global).lower())
- version = etree.Element("version",
- xmlns="http://docs.openstack.org"
- "/identity/api/v2.0")
- if self.version_id:
- version.set("id", self.version_id)
- if self.version_info:
- version.set("info", self.version_info)
- if self.version_list:
- version.set("list", self.version_list)
- dom.append(version)
- return dom
-
- def to_xml(self):
- return etree.tostring(self.to_dom())
-
- def to_dict(self):
- endpoint_template = {}
- if self.id:
- endpoint_template["id"] = unicode(self.id)
- if self.region:
- endpoint_template["region"] = self.region
- if self.name:
- endpoint_template["name"] = self.name
- if self.type:
- endpoint_template["type"] = self.type
- if self.public_url:
- endpoint_template["publicURL"] = self.public_url
- if self.admin_url:
- endpoint_template["adminURL"] = self.admin_url
- if self.internal_url:
- endpoint_template["internalURL"] = self.internal_url
- if self.enabled:
- endpoint_template["enabled"] = self.enabled
- if self.is_global:
- endpoint_template["global"] = self.is_global
- if self.version_id:
- endpoint_template["versionId"] = self.version_id
- if self.version_info:
- endpoint_template["versionInfo"] = self.version_info
- if self.version_list:
- endpoint_template["versionList"] = self.version_list
- return {'OS-KSCATALOG:endpointTemplate': endpoint_template}
-
- def to_json(self):
- return json.dumps(self.to_dict())
-
-
-class EndpointTemplates(object):
- """A collection of endpointTemplates."""
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("endpointTemplates")
- dom.set(u"xmlns",
- "http://docs.openstack.org/identity/api/ext/OS-KSCATALOG/v1.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return etree.tostring(dom)
-
- def to_json(self):
- values = [t.to_dict()["OS-KSCATALOG:endpointTemplate"]
- for t in self.values]
- links = [t.to_dict()["links"] for t in self.links]
- return json.dumps({"OS-KSCATALOG:endpointTemplates": values,
- "OS-KSCATALOG:endpointTemplates_links": links})
-
-
-class Endpoint(object):
- """Document me!"""
-
- def __init__(self, id, tenant_id, region,
- name, type, public_url, admin_url,
- internal_url, version_id=None,
- version_list=None, version_info=None):
- self.id = id
- self.tenant_id = tenant_id
- self.region = region
- self.name = name
- self.type = type
- self.public_url = self.substitute_tenant_id(public_url)
- self.admin_url = self.substitute_tenant_id(admin_url)
- self.internal_url = self.substitute_tenant_id(internal_url)
- self.version_id = version_id
- self.version_list = version_list
- self.version_info = version_info
-
- def to_dom(self):
- dom = etree.Element("endpoint",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- if self.id:
- dom.set("id", str(self.id))
- if self.tenant_id:
- dom.set("tenantId", str(self.tenant_id))
- if self.region:
- dom.set("region", self.region)
- if self.name:
- dom.set("name", str(self.name))
- if self.type:
- dom.set("type", str(self.type))
- if self.public_url:
- dom.set("publicURL", self.public_url)
- if self.admin_url:
- dom.set("adminURL", self.admin_url)
- if self.internal_url:
- dom.set("internalURL", self.internal_url)
- version = etree.Element("version",
- xmlns="http://docs.openstack.org"
- "/identity/api/v2.0")
- if self.version_id:
- version.set("id", self.version_id)
- if self.version_info:
- version.set("info", self.version_info)
- if self.version_list:
- version.set("list", self.version_list)
- dom.append(version)
- return dom
-
- def to_xml(self):
- return etree.tostring(self.to_dom())
-
- def to_dict(self):
- endpoint = {}
- if self.id:
- endpoint["id"] = self.id
- if self.tenant_id:
- endpoint["tenantId"] = self.tenant_id
- if self.region:
- endpoint["region"] = self.region
- if self.name:
- endpoint["name"] = self.name
- if self.type:
- endpoint["type"] = self.type
- if self.public_url:
- endpoint["publicURL"] = self.public_url
- if self.admin_url:
- endpoint["adminURL"] = self.admin_url
- if self.internal_url:
- endpoint["internalURL"] = self.internal_url
- if self.version_id:
- endpoint["versionId"] = self.version_id
- if self.version_info:
- endpoint["versionInfo"] = self.version_info
- if self.version_list:
- endpoint["versionList"] = self.version_list
- return {'endpoint': endpoint}
-
- def substitute_tenant_id(self, url):
- if url:
- return url.replace('%tenant_id%',
- str(self.tenant_id))
- return url
-
- def to_json(self):
- return json.dumps(self.to_dict())
-
-
-class Endpoints(object):
- """A collection of endpoints."""
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("endpoints")
- dom.set(u"xmlns",
- "http://docs.openstack.org/identity/api/v2.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return etree.tostring(dom)
-
- def to_json(self):
- values = [t.to_dict()["endpoint"] for t in self.values]
- links = [t.to_dict()["links"] for t in self.links]
- return json.dumps({"endpoints": values, "endpoints_links": links})
diff --git a/keystone/logic/types/extension.py b/keystone/logic/types/extension.py
deleted file mode 100644
index bc8bab59..00000000
--- a/keystone/logic/types/extension.py
+++ /dev/null
@@ -1,12 +0,0 @@
-class Extensions(object):
- """An extensions type to hold static extensions content."""
-
- def __init__(self, json_content, xml_content):
- self.xml_content = xml_content
- self.json_content = json_content
-
- def to_json(self):
- return self.json_content
-
- def to_xml(self):
- return self.xml_content
diff --git a/keystone/logic/types/fault.py b/keystone/logic/types/fault.py
deleted file mode 100755
index 9ef4f8f0..00000000
--- a/keystone/logic/types/fault.py
+++ /dev/null
@@ -1,165 +0,0 @@
-# Copyright (c) 2010-2011 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
-from lxml import etree
-
-
-class IdentityFault(Exception):
- """Base Exception type for all auth exceptions"""
-
- def __init__(self, msg, details=None, code=500):
- self.args = (code, msg, details)
- self.code = code
- self.msg = msg
- self.details = details
- self.key = "IdentityFault"
-
- @property
- def message(self):
- return self.msg
-
- def to_xml(self):
- dom = etree.Element(self.key,
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- dom.set("code", str(self.code))
- msg = etree.Element("message")
- msg.text = self.msg
- dom.append(msg)
- if self.details and len(self.details.strip()):
- desc = etree.Element("details")
- desc.text = self.details
- dom.append(desc)
- return etree.tostring(dom)
-
- def to_json(self):
- fault = {}
- fault["message"] = self.msg
- fault["code"] = str(self.code)
- if self.details and len(self.details.strip()):
- fault["details"] = self.details
- ret = {}
- ret[self.key] = fault
- return json.dumps(ret)
-
-
-class ServiceUnavailableFault(IdentityFault):
- """The auth service is unavailable"""
-
- def __init__(self, msg, details=None, code=503):
- super(ServiceUnavailableFault, self).__init__(msg, details, code)
- self.key = "serviceUnavailable"
-
-
-class BadRequestFault(IdentityFault):
- """Bad user request"""
-
- def __init__(self, msg, details=None, code=400):
- super(BadRequestFault, self).__init__(msg, details, code)
- self.key = "badRequest"
-
-
-class UnauthorizedFault(IdentityFault):
- """User is unauthorized"""
-
- def __init__(self, msg, details=None, code=401):
- super(UnauthorizedFault, self).__init__(msg, details, code)
- self.key = "unauthorized"
-
-
-class ForbiddenFault(IdentityFault):
- """The user is forbidden"""
-
- def __init__(self, msg, details=None, code=403):
- super(ForbiddenFault, self).__init__(msg, details, code)
- self.key = "forbidden"
-
-
-class ItemNotFoundFault(IdentityFault):
- """The item is not found"""
-
- def __init__(self, msg, details=None, code=404):
- super(ItemNotFoundFault, self).__init__(msg, details, code)
- self.key = "itemNotFound"
-
-
-class TenantDisabledFault(IdentityFault):
- """The tenant is disabled"""
-
- def __init__(self, msg, details=None, code=403):
- super(TenantDisabledFault, self).__init__(msg, details, code)
- self.key = "tenantDisabled"
-
-
-class TenantConflictFault(IdentityFault):
- """The tenant already exists?"""
-
- def __init__(self, msg, details=None, code=409):
- super(TenantConflictFault, self).__init__(msg, details, code)
- self.key = "tenantConflict"
-
-
-class OverlimitFault(IdentityFault):
- """A limit has been exceeded"""
-
- def __init__(self, msg, details=None, code=409, retry_at=None):
- super(OverlimitFault, self).__init__(msg, details, code)
- self.args = (code, msg, details, retry_at)
- self.retry_at = retry_at
- self.key = "overLimit"
-
-
-class UserConflictFault(IdentityFault):
- """The User already exists?"""
-
- def __init__(self, msg, details=None, code=409):
- super(UserConflictFault, self).__init__(msg, details, code)
- self.key = "userConflict"
-
-
-class UserDisabledFault(IdentityFault):
- """The user is disabled"""
-
- def __init__(self, msg, details=None, code=403):
- super(UserDisabledFault, self).__init__(msg, details, code)
- self.key = "userDisabled"
-
-
-class EmailConflictFault(IdentityFault):
- """The Email already exists?"""
-
- def __init__(self, msg, details=None, code=409):
- super(EmailConflictFault, self).__init__(msg, details, code)
- self.key = "emailConflict"
-
-
-class RoleConflictFault(IdentityFault):
- """The User already exists?"""
-
- def __init__(self, msg, details=None, code=409):
- super(RoleConflictFault, self).__init__(msg, details, code)
- self.key = "roleConflict"
-
-
-class ServiceConflictFault(IdentityFault):
- """The Service already exists?"""
-
- def __init__(self, msg, details=None, code=409):
- super(ServiceConflictFault, self).__init__(msg, details, code)
- self.key = "serviceConflict"
-
-
-class DatabaseMigrationError(IdentityFault):
- message = _("There was an error migrating the database.")
diff --git a/keystone/logic/types/tenant.py b/keystone/logic/types/tenant.py
deleted file mode 100644
index ca6e024b..00000000
--- a/keystone/logic/types/tenant.py
+++ /dev/null
@@ -1,150 +0,0 @@
-# Copyright (c) 2010-2011 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
-from lxml import etree
-
-from keystone.logic.types import fault
-from keystone import models
-
-
-class Tenant(object):
- """Describes a tenant in the auth system"""
- id = None
- name = None
- description = None
- enabled = None
-
- def __init__(self, id=None, name=None, description=None, enabled=None):
- self.id = id # pylint: disable=C0103
- self.name = name
- self.description = description
- if enabled is not None:
- self.enabled = bool(enabled)
- else:
- self.enabled = None
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find(
- "{http://docs.openstack.org/identity/api/v2.0}tenant")
- if root is None:
- raise fault.BadRequestFault("Expecting Tenant")
- id = root.get("id")
- name = root.get("name")
- enabled = root.get("enabled")
- if enabled is None or enabled == "true" or enabled == "yes":
- set_enabled = True
- elif enabled == "false" or enabled == "no":
- set_enabled = False
- else:
- raise fault.BadRequestFault("Bad enabled attribute!")
- desc = root.find("{http://docs.openstack.org/identity/api/v2.0}"
- "description")
- if desc is None:
- description = None
- else:
- description = desc.text
- return models.Tenant(id=id, name=name, description=description,
- enabled=set_enabled)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse Tenant", str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
- if not "tenant" in obj:
- raise fault.BadRequestFault("Expecting tenant")
- tenant = obj["tenant"]
-
- # Check that fields are valid
- invalid = [key for key in tenant if key not in\
- ['id', 'name', 'enabled', 'description']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
-
- id = tenant.get("id", None)
- name = tenant.get("name", None)
- set_enabled = True
- if "enabled" in tenant:
- set_enabled = tenant["enabled"]
- if not isinstance(set_enabled, bool):
- raise fault.BadRequestFault("Bad enabled attribute!")
- description = tenant.get("description")
- return Tenant(id=id, name=name, description=description,
- enabled=set_enabled)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse Tenant", str(e))
-
- def to_dom(self):
- dom = etree.Element("tenant",
- xmlns="http://docs.openstack.org/identity/api/v2.0",
- enabled=str(self.enabled).lower())
- if self.id:
- dom.set("id", unicode(self.id))
- if self.name:
- dom.set("name", unicode(self.name))
- desc = etree.Element("description")
- if self.description:
- desc.text = unicode(self.description)
- dom.append(desc)
- return dom
-
- def to_xml(self):
- return etree.tostring(self.to_dom())
-
- def to_dict(self):
- tenant = {
- "enabled": self.enabled}
- if self.description:
- tenant['description'] = unicode(self.description)
- if self.id:
- tenant["id"] = unicode(self.id)
- if self.name:
- tenant["name"] = unicode(self.name)
- return {"tenant": tenant}
-
- def to_json(self):
- return json.dumps(self.to_dict())
-
-
-class Tenants(object):
- """A collection of tenants."""
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("tenants")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return etree.tostring(dom)
-
- def to_json(self):
- values = [t.to_dict()["tenant"] for t in self.values]
- links = [t.to_dict()["links"] for t in self.links]
- return json.dumps({"tenants": values, "tenants_links": links})
diff --git a/keystone/logic/types/user.py b/keystone/logic/types/user.py
deleted file mode 100755
index 5be5d488..00000000
--- a/keystone/logic/types/user.py
+++ /dev/null
@@ -1,280 +0,0 @@
-# Copyright (c) 2010-2011 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
-from lxml import etree
-
-from keystone.logic.types import fault
-from keystone import utils
-
-
-class User(object):
- """Document me!"""
-
- def __init__(self, password=None, id=None, name=None, tenant_id=None,
- email=None, enabled=None, tenant_roles=None):
- self.id = id
- self.name = name
- self.tenant_id = tenant_id
- self.password = password
- self.email = email
- self.enabled = enabled and True or False
- self.tenant_roles = tenant_roles
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}" \
- "user")
- if root is None:
- raise fault.BadRequestFault("Expecting User")
-
- name = root.get("name")
- tenant_id = root.get("tenantId")
- email = root.get("email")
- password = root.get("password")
- enabled = root.get("enabled")
- utils.check_empty_string(name, "Expecting User Name")
- utils.check_empty_string(password, "Expecting User Password")
- utils.check_empty_string(email, "Expecting User email")
- enabled = enabled is None or enabled.lower() in ["true", "yes"]
-
- return User(password, id, name, tenant_id, email, enabled)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse User", str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
- if not "user" in obj:
- raise fault.BadRequestFault("Expecting User")
- user = obj["user"]
-
- # Check that fields are valid
- invalid = [key for key in user if key not in
- ['id', 'name', 'password', 'tenantId', 'email',
- 'enabled']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
-
- id = user.get('id', None)
- name = user.get('name', None)
-
- if not "password" in user:
- raise fault.BadRequestFault("Expecting User Password")
- password = user["password"]
-
- if "tenantId" in user:
- tenant_id = user["tenantId"]
- else:
- tenant_id = None
- if "email" not in user:
- raise fault.BadRequestFault("Expecting User Email")
- email = user["email"]
- utils.check_empty_string(name, "Expecting User Name")
- utils.check_empty_string(password, "Expecting User Password")
- utils.check_empty_string(email, "Expecting User email")
- if "enabled" in user:
- set_enabled = user["enabled"]
- if not isinstance(set_enabled, bool):
- raise fault.BadRequestFault("Bad enabled attribute!")
- else:
- set_enabled = True
- return User(password, id, name, tenant_id, email, set_enabled)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse User", str(e))
-
- def to_dom(self):
- dom = etree.Element("user",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- if self.email:
- dom.set("email", unicode(self.email))
- if self.tenant_id:
- dom.set("tenantId", unicode(self.tenant_id))
- if self.id:
- dom.set("id", unicode(self.id))
- if self.name:
- dom.set("name", unicode(self.name))
- if self.enabled:
- dom.set("enabled", unicode(self.enabled).lower())
- if self.password:
- dom.set("password", unicode(self.password))
- if self.tenant_roles:
- dom_roles = etree.Element("tenantRoles")
- for role in self.tenant_roles:
- dom_role = etree.Element("tenantRole")
- dom_role.text = role
- dom_roles.append(dom_role)
- dom.append(dom_roles)
- return dom
-
- def to_xml(self):
- return etree.tostring(self.to_dom())
-
- def to_dict(self):
- user = {}
-
- if self.id:
- user["id"] = unicode(self.id)
- if self.name:
- user["name"] = unicode(self.name)
- if self.tenant_id:
- user["tenantId"] = unicode(self.tenant_id)
- if self.password:
- user["password"] = unicode(self.password)
- user["email"] = unicode(self.email)
- user["enabled"] = self.enabled
- if self.tenant_roles:
- user["tenantRoles"] = list(self.tenant_roles)
- return {'user': user}
-
- def to_json(self):
- return json.dumps(self.to_dict())
-
-
-class User_Update(object):
- """Document me!"""
-
- def __init__(self, password=None, id=None, name=None, tenant_id=None,
- email=None, enabled=None):
- self.id = id
- self.name = name
- self.tenant_id = tenant_id
- self.password = password
- self.email = email
- self.enabled = bool(enabled) if enabled is not None else None
-
- @staticmethod
- def from_xml(xml_str):
- try:
- dom = etree.Element("root")
- dom.append(etree.fromstring(xml_str))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}" \
- "user")
- if root is None:
- raise fault.BadRequestFault("Expecting User")
- id = root.get("id")
- name = root.get("name")
- tenant_id = root.get("tenantId")
- email = root.get("email")
- password = root.get("password")
- enabled = root.get("enabled")
- if enabled is None or enabled == "true" or enabled == "yes":
- set_enabled = True
- elif enabled == "false" or enabled == "no":
- set_enabled = False
- else:
- raise fault.BadRequestFault("Bad enabled attribute!")
-
- return User(password=password, id=id, name=name,
- tenant_id=tenant_id, email=email, enabled=set_enabled)
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse User", str(e))
-
- @staticmethod
- def from_json(json_str):
- try:
- obj = json.loads(json_str)
- if not "user" in obj:
- raise fault.BadRequestFault("Expecting User")
- user = obj["user"]
-
- # Check that fields are valid
- invalid = [key for key in user if key not in
- ['id', 'name', 'password', 'tenantId', 'email',
- 'enabled']]
- if invalid != []:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
-
- id = user.get('id', None)
- name = user.get('name', None)
- password = user.get('password', None)
- tenant_id = user.get('tenantId', None)
- email = user.get('email', None)
- enabled = user.get('enabled', True)
-
- if not isinstance(enabled, bool):
- raise fault.BadRequestFault("Bad enabled attribute!")
-
- return User(password, id, name, tenant_id, email, enabled)
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse Tenant", str(e))
-
- def to_dom(self):
- dom = etree.Element("user",
- xmlns="http://docs.openstack.org/identity/api/v2.0")
- if self.email:
- dom.set("email", unicode(self.email))
- if self.tenant_id:
- dom.set("tenantId", unicode(self.tenant_id))
- if self.id:
- dom.set("id", unicode(self.id))
- if self.name:
- dom.set("name", unicode(self.name))
- if self.enabled is not None:
- dom.set("enabled", unicode(self.enabled).lower())
- if self.password:
- dom.set("password", unicode(self.password))
- return dom
-
- def to_xml(self):
- return etree.tostring(self.to_dom())
-
- def to_dict(self):
- user = {}
-
- if self.id:
- user["id"] = unicode(self.id)
- if self.name:
- user["name"] = unicode(self.name)
- if self.tenant_id:
- user["tenantId"] = unicode(self.tenant_id)
- if self.password:
- user["password"] = unicode(self.password)
- if self.email:
- user["email"] = unicode(self.email)
- if self.enabled is not None:
- user["enabled"] = self.enabled
- return {'user': user}
-
- def to_json(self):
- return json.dumps(self.to_dict())
-
-
-class Users(object):
- """A collection of users."""
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("users")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
- for t in self.values:
- dom.append(t.to_dom())
- for t in self.links:
- dom.append(t.to_dom())
- return etree.tostring(dom)
-
- def to_json(self):
- values = [t.to_dict()["user"] for t in self.values]
- links = [t.to_dict()["links"] for t in self.links]
- return json.dumps({"users": values, "users_links": links})
diff --git a/keystone/manage/__init__.py b/keystone/manage/__init__.py
deleted file mode 100644
index 3b9d0f91..00000000
--- a/keystone/manage/__init__.py
+++ /dev/null
@@ -1,507 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Keystone Identity Server - CLI Management Interface
-"""
-
-import logging
-import optparse # deprecated in 2.7, in favor of argparse
-import os
-import sys
-import tempfile
-
-from keystone import version
-import keystone.backends as db
-from keystone.backends.sqlalchemy import migration
-# Need to give it a different alias
-from keystone import config as new_config
-from keystone.common import config
-from keystone.logic.types import fault
-from keystone.manage import api
-from keystone import utils
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-# We're using two config systems here, so we need to be clear
-# which one we're working with.
-CONF = new_config.CONF
-
-
-# CLI feature set
-OBJECTS = ['user', 'tenant', 'role', 'service',
- 'endpointTemplates', 'token', 'endpoint', 'credentials', 'database']
-ACTIONS = ['add', 'list', 'disable', 'delete', 'grant', 'revoke',
- 'sync', 'downgrade', 'upgrade', 'version_control', 'version',
- 'goto']
-
-
-# Messages
-OBJECT_NOT_SPECIFIED = 'No object type specified for first argument'
-ACTION_NOT_SPECIFIED = 'No action specified for second argument'
-ID_NOT_SPECIFIED = 'No ID specified for third argument'
-SUPPORTED_OBJECTS = "Supported objects: %s" % (", ".join(OBJECTS))
-SUPPORTED_ACTIONS = "Supported actions: %s" % (", ".join(ACTIONS))
-ACTION_NOT_SUPPORTED = 'Action not supported for %s'
-
-
-class RaisingOptionParser(optparse.OptionParser):
- def error(self, msg):
- self.print_usage(sys.stderr)
- raise optparse.OptParseError(msg)
-
-
-def parse_args(args=None):
- usage = """
- Usage: keystone-manage [options] type action [id [attributes]]
- type : %s
- action : %s
- id : name or id
- attributes : depending on type...
- users : password, tenant
- tokens : user, tenant, expiration
-
- role list [tenant] will list roles granted on that tenant
- database [sync | downgrade | upgrade | version_control | version]
-
- options
- -c | --config-file : config file to use
- -d | --debug : debug mode
-
- Example: keystone-manage user add Admin P@ssw0rd
- """ % (", ".join(OBJECTS), ", ".join(ACTIONS))
-
- # Initialize a parser for our configuration paramaters
- parser = RaisingOptionParser(usage, version='%%prog %s'
- % version.version())
- config.add_common_options(parser)
- config.add_log_options(parser)
-
- # Parse command-line and load config
- (options, args) = config.parse_options(parser, args)
-
- if not args or args[0] != 'database':
- # Use the legacy code to find the config file
- config_file = config.find_config_file(options, sys.argv[1:])
- # Now init the CONF for the backends
- CONF(config_files=[config_file])
-
- db.configure_backends()
- return args
-
-
-def get_options(args=None):
- # Initialize a parser for our configuration paramaters
- parser = RaisingOptionParser()
- config.add_common_options(parser)
- config.add_log_options(parser)
-
- # Parse command-line and load config
- (options, args) = config.parse_options(parser, list(args))
-
- _config_file, conf = config.load_paste_config('admin', options, args)
- conf.global_conf.update(conf.local_conf)
-
- return conf.global_conf
-
-
-# pylint: disable=R0912,R0915
-def process(*args):
- # Check arguments
- if len(args) == 0:
- raise optparse.OptParseError(OBJECT_NOT_SPECIFIED)
- else:
- object_type = args[0]
- if object_type not in OBJECTS:
- raise optparse.OptParseError(SUPPORTED_OBJECTS)
-
- if len(args) == 1:
- raise optparse.OptParseError(ACTION_NOT_SPECIFIED)
- else:
- action = args[1]
- if action not in ACTIONS:
- raise optparse.OptParseError(SUPPORTED_ACTIONS)
-
- if action not in ['list', 'sync', 'version_control', 'version']:
- if len(args) == 2:
- raise optparse.OptParseError(ID_NOT_SPECIFIED)
- else:
- object_id = args[2]
-
- # Helper functions
- def require_args(args, min, msg):
- """Ensure there are at least `min` arguments"""
- if len(args) < min:
- raise optparse.OptParseError(msg)
-
- def optional_arg(args, index):
- return ((len(args) > index) and str(args[index]).strip()) or None
-
- if object_type == 'database':
- options = get_options(args)
-
- # Execute command
- if (object_type, action) == ('user', 'add'):
- require_args(args, 4, 'No password specified for fourth argument')
- if api.add_user(name=object_id, password=args[3],
- tenant=optional_arg(args, 4)):
- print ("SUCCESS: User %s created." % object_id)
-
- elif (object_type, action) == ('user', 'list'):
- print (Table('Users', ['id', 'name', 'enabled', 'tenant'],
- api.list_users()))
-
- elif (object_type, action) == ('user', 'disable'):
- if api.disable_user(name=object_id):
- print ("SUCCESS: User %s disabled." % object_id)
-
- elif object_type == 'user':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('users'))
-
- elif (object_type, action) == ('tenant', 'add'):
- if api.add_tenant(name=object_id):
- print ("SUCCESS: Tenant %s created." % object_id)
-
- elif (object_type, action) == ('tenant', 'list'):
- print Table('Tenants', ['id', 'name', 'enabled'], api.list_tenants())
-
- elif (object_type, action) == ('tenant', 'disable'):
- if api.disable_tenant(name=object_id):
- print ("SUCCESS: Tenant %s disabled." % object_id)
-
- elif object_type == 'tenant':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('tenants'))
-
- elif (object_type, action) == ('role', 'add'):
- if api.add_role(name=object_id, service_name=optional_arg(args, 3)):
- print ("SUCCESS: Role %s created successfully." % object_id)
-
- elif (object_type, action) == ('role', 'list'):
- tenant = optional_arg(args, 2)
- if tenant:
- # print with users
- print (Table('Role assignments for tenant %s' %
- tenant, ['User', 'Role'],
- api.list_roles(tenant=tenant)))
- else:
- # print without tenants
- print (Table('Roles', ['id', 'name', 'service_id', 'description'],
- api.list_roles()))
-
- elif (object_type, action) == ('role', 'grant'):
- require_args(args, 4, "Missing arguments: role grant 'role' 'user' "
- "'tenant (optional)'")
- tenant = optional_arg(args, 4)
- if api.grant_role(object_id, args[3], tenant):
- print ("SUCCESS: Granted %s the %s role on %s." %
- (args[3], object_id, tenant))
-
- elif object_type == 'role':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('roles'))
-
- elif (object_type, action) == ('endpointTemplates', 'add'):
- require_args(args, 9, "Missing arguments: endpointTemplates add "
- "'region' 'service_name' 'publicURL' 'adminURL' 'internalURL' "
- "'enabled' 'global'")
- version_id = optional_arg(args, 9)
- version_list = optional_arg(args, 10)
- version_info = optional_arg(args, 11)
- if api.add_endpoint_template(region=args[2], service=args[3],
- public_url=args[4], admin_url=args[5], internal_url=args[6],
- enabled=args[7], is_global=args[8],
- version_id=version_id, version_list=version_list,
- version_info=version_info):
- print ("SUCCESS: Created EndpointTemplates for %s "
- "pointing to %s." % (args[3], args[4]))
-
- elif (object_type, action) == ('endpointTemplates', 'list'):
- tenant = optional_arg(args, 2)
- if tenant:
- print Table('Endpoints for tenant %s' % tenant,
- ['id', 'service', 'region', 'Public URL'],
- api.list_tenant_endpoints(tenant))
- else:
- print Table('All EndpointTemplates', ['id', 'service', 'type',
- 'region', 'enabled', 'is_global', 'Public URL',
- 'Admin URL'],
- api.list_endpoint_templates())
-
- elif (object_type, action) == ('endpoint', 'add'):
- require_args(args, 4, "Missing arguments: endPoint add tenant "
- "endPointTemplate")
- if api.add_endpoint(tenant=args[2], endpoint_template=args[3]):
- print ("SUCCESS: Endpoint %s added to tenant %s." %
- (args[3], args[2]))
-
- elif object_type == 'endpoint':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('endpoints'))
-
- elif (object_type, action) == ('token', 'add'):
- require_args(args, 6, 'Creating a token requires a token id, user, '
- 'tenant, and expiration')
- if api.add_token(token=object_id, user=args[3], tenant=args[4],
- expires=args[5]):
- print ("SUCCESS: Token %s created." % object_id)
-
- elif (object_type, action) == ('token', 'list'):
- print Table('Tokens', ('token', 'user', 'expiration', 'tenant'),
- api.list_tokens())
-
- elif (object_type, action) == ('token', 'delete'):
- if api.delete_token(token=object_id):
- print ('SUCCESS: Token %s deleted.' % (object_id,))
-
- elif object_type == 'token':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('tokens'))
-
- elif (object_type, action) == ('service', 'add'):
- require_args(args, 4, "Missing arguments: service add <name> " \
- "[type] [desc] [owner_id]"
- "type")
- type = optional_arg(args, 3)
- desc = optional_arg(args, 4)
- owner_id = optional_arg(args, 5)
-
- if api.add_service(name=object_id, type=type, desc=desc,
- owner_id=owner_id):
- print ("SUCCESS: Service %s created successfully."
- % (object_id,))
-
- elif (object_type, action) == ('service', 'list'):
- print (Table('Services', ('id', 'name', 'type', 'owner_id',
- 'description'), api.list_services()))
-
- elif object_type == 'service':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('services'))
-
- elif (object_type, action) == ('credentials', 'add'):
- require_args(args, 6, 'Creating a credentials requires a type, key, '
- 'secret, and tenant_id (id is user_id)')
- if api.add_credentials(user=object_id, type=args[3], key=args[4],
- secrete=args[5], tenant=optional_arg(args, 6)):
- print ("SUCCESS: Credentials %s created." %
- (object_id,))
-
- elif object_type == 'credentials':
- raise optparse.OptParseError(ACTION_NOT_SUPPORTED % ('credentials'))
-
- elif (object_type, action) == ('database', 'sync'):
- require_args(args, 1, 'Syncing database requires a version #')
- backend_names = options.get('backends', None)
- if backend_names:
- if 'keystone.backends.sqlalchemy' in backend_names.split(','):
- do_db_sync(options['keystone.backends.sqlalchemy'],
- args)
- else:
- raise optparse.OptParseError(
- 'SQL alchemy backend not specified in config')
-
- elif (object_type, action) == ('database', 'upgrade'):
- require_args(args, 1, 'Upgrading database requires a version #')
- backend_names = options.get('backends', None)
- if backend_names:
- if 'keystone.backends.sqlalchemy' in backend_names.split(','):
- do_db_upgrade(options['keystone.backends.sqlalchemy'],
- args)
- else:
- raise optparse.OptParseError(
- 'SQL alchemy backend not specified in config')
-
- elif (object_type, action) == ('database', 'downgrade'):
- require_args(args, 1, 'Downgrading database requires a version #')
- backend_names = options.get('backends', None)
- if backend_names:
- if 'keystone.backends.sqlalchemy' in backend_names.split(','):
- do_db_downgrade(options['keystone.backends.sqlalchemy'],
- args)
- else:
- raise optparse.OptParseError(
- 'SQL alchemy backend not specified in config')
-
- elif (object_type, action) == ('database', 'version_control'):
- backend_names = options.get('backends', None)
- if backend_names:
- if 'keystone.backends.sqlalchemy' in backend_names.split(','):
- do_db_version_control(options['keystone.backends.sqlalchemy'])
- else:
- raise optparse.OptParseError(
- 'SQL alchemy backend not specified in config')
-
- elif (object_type, action) == ('database', 'version'):
- backend_names = options.get('backends', None)
- if backend_names:
- if 'keystone.backends.sqlalchemy' in backend_names.split(','):
- do_db_version(options['keystone.backends.sqlalchemy'])
- else:
- raise optparse.OptParseError(
- 'SQL alchemy backend not specified in config')
-
- elif (object_type, action) == ('database', 'goto'):
- require_args(args, 1, 'Jumping database versions requires a '
- 'version #')
- backend_names = options.get('backends', None)
- if backend_names:
- if 'keystone.backends.sqlalchemy' in backend_names.split(','):
- do_db_goto_version(options['keystone.backends.sqlalchemy'],
- target_version=args[2])
- else:
- raise optparse.OptParseError(
- 'SQL alchemy backend not specified in config')
-
- else:
- # Command recognized but not handled: should never reach this
- raise NotImplementedError()
-
-
-#
-# Database Migration commands (from Glance-manage)
-#
-def do_db_version(options):
- """Print database's current migration level"""
- print (migration.db_version(options['sql_connection']))
-
-
-def do_db_goto_version(options, target_version):
- """Override the database's current migration level"""
- if migration.db_goto_version(options['sql_connection'], target_version):
- msg = ('Jumped to version=%s (without performing intermediate '
- 'migrations)') % target_version
- print (msg)
-
-
-def do_db_upgrade(options, args):
- """Upgrade the database's migration level"""
- try:
- db_version = args[2]
- except IndexError:
- db_version = None
-
- print ("Upgrading database to version %s" % db_version)
- migration.upgrade(options['sql_connection'], version=db_version)
-
-
-def do_db_downgrade(options, args):
- """Downgrade the database's migration level"""
- try:
- db_version = args[2]
- except IndexError:
- raise Exception("downgrade requires a version argument")
-
- migration.downgrade(options['sql_connection'], version=db_version)
-
-
-def do_db_version_control(options):
- """Place a database under migration control"""
- migration.version_control(options['sql_connection'])
- print ("Database now under version control")
-
-
-def do_db_sync(options, args):
- """Place a database under migration control and upgrade"""
- try:
- db_version = args[2]
- except IndexError:
- db_version = None
- migration.db_sync(options['sql_connection'], version=db_version)
-
-
-class Table:
- """Prints data in table for console output
-
- Syntax print Table("This is the title",
- ["Header1","Header2","H3"],
- [[1,2,3],["Hi","everybody","How are you??"],[None,True,[1,2]]])
-
- """
- def __init__(self, title=None, headers=None, rows=None):
- self.title = title
- self.headers = headers if headers is not None else []
- self.rows = rows if rows is not None else []
- self.nrows = len(self.rows)
- self.fieldlen = []
-
- ncols = len(headers)
-
- for h in range(ncols):
- max = 0
- for row in rows:
- if len(str(row[h])) > max:
- max = len(str(row[h]))
- self.fieldlen.append(max)
-
- for i in range(len(headers)):
- if len(str(headers[i])) > self.fieldlen[i]:
- self.fieldlen[i] = len(str(headers[i]))
-
- self.width = sum(self.fieldlen) + (ncols - 1) * 3 + 4
-
- def __str__(self):
- hbar = "-" * self.width
- if self.title:
- title = "| " + self.title + " " * \
- (self.width - 3 - (len(self.title))) + "|"
- out = [hbar, title, hbar]
- else:
- out = []
- header = ""
- for i in range(len(self.headers)):
- header += "| %s" % (str(self.headers[i])) + " " * \
- (self.fieldlen[i] - len(str(self.headers[i]))) + " "
- header += "|"
- out.append(header)
- out.append(hbar)
- for i in self.rows:
- line = ""
- for j in range(len(i)):
- line += "| %s" % (str(i[j])) + " " * \
- (self.fieldlen[j] - len(str(i[j]))) + " "
- out.append(line + "|")
-
- out.append(hbar)
- return "\r\n".join(out)
-
-
-def main(args=None):
- try:
- process(*parse_args(args))
- except (optparse.OptParseError, fault.DatabaseMigrationError) as exc:
- print >> sys.stderr, exc
- sys.exit(2)
- except Exception as exc:
- logstr = str(exc)
- loginfo = None
- if len(exc.args) > 1:
- logstr = exc.args[0]
- loginfo = exc.args[1]
-
- errmsg = "ERROR: %s" % logstr
- if loginfo:
- errmsg += ": %s" % loginfo
-
- print errmsg
- logger.error(logstr, exc_info=loginfo)
- raise
-
-
-if __name__ == '__main__':
- try:
- main()
- except StandardError:
- sys.exit(1)
diff --git a/keystone/manage/api.py b/keystone/manage/api.py
deleted file mode 100644
index de5d2d56..00000000
--- a/keystone/manage/api.py
+++ /dev/null
@@ -1,210 +0,0 @@
-import datetime
-
-import keystone.backends.api as db_api
-import keystone.backends.models as db_models
-import keystone.models as models
-
-
-def add_user(name, password, tenant=None):
- if tenant:
- tenant = db_api.TENANT.get_by_name(tenant).id
-
- obj = models.User()
- obj.name = name
- obj.password = password
- obj.enabled = True
- obj.tenant_id = tenant
- return db_api.USER.create(obj)
-
-
-def disable_user(name):
- user = db_api.USER.get_by_name(name)
- if user is None:
- raise IndexError("User %s not found" % name)
- user.enabled = False
- return db_api.USER.update(user.id, user)
-
-
-def list_users():
- objects = db_api.USER.get_all()
- if objects is None:
- raise IndexError("No users found")
- return [[o.id, o.name, o.enabled, o.tenant_id] for o in objects]
-
-
-def add_tenant(name):
- obj = models.Tenant()
- obj.name = name
- obj.enabled = True
- db_api.TENANT.create(obj)
-
-
-def list_tenants():
- objects = db_api.TENANT.get_all()
- if objects is None:
- raise IndexError("Tenants not found")
- return [[o.id, o.name, o.enabled] for o in objects]
-
-
-def disable_tenant(name):
- obj = db_api.TENANT.get_by_name(name)
- if obj is None:
- raise IndexError("Tenant %s not found" % name)
- obj.enabled = False
- return db_api.TENANT.update(obj.id, obj)
-
-
-def add_role(name, service_name=None):
- obj = models.Role()
- obj.name = name
-
- names = name.split(":")
- if len(names) == 2:
- service_name = names[0] or service_name
- if service_name:
- # we have a role with service prefix, fill in the service ID
- service = db_api.SERVICE.get_by_name(name=service_name)
- obj.service_id = service.id
- return db_api.ROLE.create(obj)
-
-
-def list_role_assignments(tenant):
- objects = db_api.TENANT.get_role_assignments(tenant)
- if objects is None:
- raise IndexError("Assignments not found")
- return [[o.user.name, o.role.name] for o in objects]
-
-
-def list_roles(tenant=None):
- if tenant:
- tenant = db_api.TENANT.get_by_name(tenant).id
- return list_role_assignments(tenant)
- else:
- objects = db_api.ROLE.get_all()
- if objects is None:
- raise IndexError("Roles not found")
- return [[o.id, o.name, o.service_id, o.description] for o in objects]
-
-
-def grant_role(role, user, tenant=None):
- """Grants `role` to `user` (and optionally, on `tenant`)"""
- role = db_api.ROLE.get_by_name(name=role).id
- user = db_api.USER.get_by_name(name=user).id
-
- if tenant:
- tenant = db_api.TENANT.get_by_name(name=tenant).id
-
- obj = db_models.UserRoleAssociation()
- obj.role_id = role
- obj.user_id = user
- obj.tenant_id = tenant
-
- return db_api.USER.user_role_add(obj)
-
-
-def add_endpoint_template(region, service, public_url, admin_url, internal_url,
- enabled, is_global, version_id, version_list, version_info):
- db_service = db_api.SERVICE.get_by_name(service)
- if db_service is None:
- raise IndexError("Service %s not found" % service)
- obj = db_models.EndpointTemplates()
- obj.region = region
- obj.service_id = db_service.id
- obj.public_url = public_url
- obj.admin_url = admin_url
- obj.internal_url = internal_url
- obj.enabled = enabled
- obj.is_global = is_global
- obj.version_id = version_id
- obj.version_list = version_list
- obj.version_info = version_info
- return db_api.ENDPOINT_TEMPLATE.create(obj)
-
-
-def list_tenant_endpoints(tenant):
- objects = db_api.ENDPOINT_TEMPLATE.endpoint_get_by_tenant(tenant)
- if objects is None:
- raise IndexError("URLs not found")
- return [[db_api.SERVICE.get(o.service_id).name,
- o.region, o.public_url] for o in objects]
-
-
-def list_endpoint_templates():
- objects = db_api.ENDPOINT_TEMPLATE.get_all()
- if objects is None:
- raise IndexError("URLs not found")
- return [[o.id,
- db_api.SERVICE.get(o.service_id).name,
- db_api.SERVICE.get(o.service_id).type,
- o.region, o.enabled, o.is_global,
- o.public_url, o.admin_url] for o in objects]
-
-
-def add_endpoint(tenant, endpoint_template):
- tenant = db_api.TENANT.get_by_name(name=tenant).id
- endpoint_template = db_api.ENDPOINT_TEMPLATE.get(id=endpoint_template).id
-
- obj = db_models.Endpoints()
- obj.tenant_id = tenant
- obj.endpoint_template_id = endpoint_template
- db_api.ENDPOINT_TEMPLATE.endpoint_add(obj)
- return obj
-
-
-def add_token(token, user, tenant, expires):
- user = db_api.USER.get_by_name(name=user).id
- if tenant:
- tenant = db_api.TENANT.get_by_name(name=tenant).id
-
- obj = models.Token()
- obj.id = token
- obj.user_id = user
- obj.tenant_id = tenant
- obj.expires = datetime.datetime.strptime(expires.replace("-", ""),
- "%Y%m%dT%H:%M")
- return db_api.TOKEN.create(obj)
-
-
-def list_tokens():
- objects = db_api.TOKEN.get_all()
- if objects is None:
- raise IndexError("Tokens not found")
- return [[o.id, o.user_id, o.expires, o.tenant_id] for o in objects]
-
-
-def delete_token(token):
- obj = db_api.TOKEN.get(token)
- if obj is None:
- raise IndexError("Token %s not found" % (token,))
- return db_api.TOKEN.delete(token)
-
-
-def add_service(name, type, desc, owner_id):
- obj = models.Service()
- obj.name = name
- obj.type = type
- obj.description = desc
- obj.owner_id = owner_id
- return db_api.SERVICE.create(obj)
-
-
-def list_services():
- objects = db_api.SERVICE.get_all()
- if objects is None:
- raise IndexError("Services not found")
- return [[o.id, o.name, o.type, o.owner_id, o.description] for o in objects]
-
-
-def add_credentials(user, type, key, secrete, tenant=None):
- user = db_api.USER.get_by_name(user).id
-
- if tenant:
- tenant = db_api.TENANT.get_by_name(tenant).id
-
- obj = models.Credentials()
- obj.user_id = user
- obj.type = type
- obj.key = key
- obj.secret = secrete
- obj.tenant_id = tenant
- return db_api.CREDENTIALS.create(obj)
diff --git a/keystone/manage2/__init__.py b/keystone/manage2/__init__.py
deleted file mode 100644
index 4336730b..00000000
--- a/keystone/manage2/__init__.py
+++ /dev/null
@@ -1,107 +0,0 @@
-"""OpenStack Identity (Keystone) Management"""
-
-
-import argparse
-import optparse
-import os
-import pkgutil
-import sys
-
-from keystone.common import config as legacy_config
-from keystone import config
-from keystone.manage2 import commands
-
-CONF = config.CONF
-
-# builds a complete path to the commands package
-PACKAGE_PATH = os.path.dirname(commands.__file__)
-
-# builds a list of modules in the commands package
-MODULES = [tupl for tupl in pkgutil.iter_modules([PACKAGE_PATH])]
-
-
-def load_module(module_name):
- """Imports a module given the module name"""
- try:
- module_loader, name, _is_package = [md for md in MODULES
- if md[1] == module_name][0]
- except IndexError:
- raise ValueError("No module found named '%s'" % module_name)
-
- loader = module_loader.find_module(name)
- module = loader.load_module(name)
- return module
-
-
-# pylint: disable=W0612
-def init_config():
- """Uses legacy config module to parse out legacy settings and provide
- them to the new cfg.py parser.
-
- This is a hack until we find a better way to have cfg.py ignore
- unknown arguments
- """
-
- class SilentOptParser(optparse.OptionParser):
- """ Class used to prevent OptionParser from exiting when it detects
- invalid options coming in """
- def exit(self, status=0, msg=None):
- pass
-
- def error(self, msg):
- pass
-
- # Initialize a parser for our configuration paramaters
- parser = SilentOptParser()
- legacy_config.add_common_options(parser)
- legacy_config.add_log_options(parser)
-
- # Parse command-line and load config
- (options, args) = legacy_config.parse_options(parser)
- (legacy_args, unknown_args) = parser.parse_args()
-
- cfgfile = getattr(legacy_args, 'config_file', None)
- if cfgfile:
- known_args = ['--config-file', cfgfile]
- else:
- known_args = []
-
- # Use the legacy code to find the config file
- config_file = legacy_config.find_config_file(options, known_args)
-
- # Now init the CONF for the backends using only known args
- old_args = sys.argv[:]
- sys.argv = known_args
- try:
- CONF(config_files=[config_file])
- except StandardError:
- raise
- finally:
- sys.argv = old_args
-
-
-def main():
- # discover command modules
- module_names = [name for _, name, _ in MODULES]
-
- # build an argparser for keystone manage itself
- parser = argparse.ArgumentParser(description=__doc__)
- subparsers = parser.add_subparsers(dest='command',
- help='Management commands')
-
- # append each command as a subparser
- for module_name in module_names:
- module = load_module(module_name)
- subparser = subparsers.add_parser(module_name,
- help=module.Command.__doc__)
-
- module.Command.append_parser(subparser)
-
- # actually parse the command line args or print help
- args = parser.parse_args()
-
- # configure and run command
- init_config()
- module = load_module(args.command)
- cmd = module.Command()
- exit(cmd.run(args))
diff --git a/keystone/manage2/base.py b/keystone/manage2/base.py
deleted file mode 100644
index bfd5babd..00000000
--- a/keystone/manage2/base.py
+++ /dev/null
@@ -1,111 +0,0 @@
-import argparse
-
-from keystone import config
-from keystone.manage2 import common
-
-
-class BaseCommand(object):
- """Provides a common pattern for keystone-manage commands"""
-
- # pylint: disable=W0613
- def __init__(self, *args, **kwargs):
- self.parser = argparse.ArgumentParser(prog=self.__module__,
- description=self.__doc__)
- self.append_parser(self.parser)
-
- def true_or_false(self, args, positive, negative):
- """Evaluates a complementary pair of args to determine True/False.
-
- Fails if both args were provided.
-
- """
-
- if getattr(args, positive) and getattr(args, negative):
- self.parser.error("Unable to apply both: --%s and --%s" % (
- tuple([x.replace('_', '-') for x in (positive, negative)])))
-
- return getattr(args, positive) and not getattr(args, negative)
-
- @classmethod
- def append_parser(cls, parser):
- """Appends this command's arguments to an argparser
-
- :param parser: argparse.ArgumentParser
- """
- args = getattr(cls, '_args', {})
-
- for name in args.keys():
- try:
- parser.add_argument(name, **args[name])
- except TypeError:
- print "Unable to add argument (%s) %s" % (name, args[name])
- raise
-
- def run(self, args):
- """Handles argparse args and prints command results to stdout
-
- :param args: argparse Namespace
- """
- raise NotImplementedError()
-
-
-# pylint: disable=W0223
-class BaseSqlalchemyCommand(BaseCommand):
- """Common functionality for database management commands"""
-
- def __init__(self, *args, **kwargs):
- super(BaseSqlalchemyCommand, self).__init__(*args, **kwargs)
-
- @staticmethod
- def _get_connection_string():
- sqla = config.CONF['keystone.backends.sqlalchemy']
- return sqla.sql_connection
-
-
-# pylint: disable=E1101,W0223
-class BaseBackendCommand(BaseCommand):
- """Common functionality for commands requiring backend access"""
-
- def __init__(self, managers=None, *args, **kwargs):
- super(BaseBackendCommand, self).__init__(*args, **kwargs)
-
- # we may need to initialize our own managers
- managers = managers or common.init_managers()
-
- # managers become available as self.attributes
- for name, manager in managers.iteritems():
- setattr(self, name, manager)
-
- @staticmethod
- def _get(obj_name, manager, id=None):
- """Get an object from a manager, or fail if not found"""
- if id is not None:
- obj = manager.get(id)
-
- if obj is None:
- raise KeyError("%s ID not found: %s" % (obj_name, id))
-
- return obj
-
- def get_user(self, id):
- return BaseBackendCommand._get("User", self.user_manager, id)
-
- def get_tenant(self, id):
- return BaseBackendCommand._get("Tenant", self.tenant_manager, id)
-
- def get_token(self, id):
- return BaseBackendCommand._get("Token", self.token_manager, id)
-
- def get_credential(self, id):
- return BaseBackendCommand._get("Credential", self.credential_manager,
- id)
-
- def get_role(self, id):
- return BaseBackendCommand._get("Role", self.role_manager, id)
-
- def get_service(self, id):
- return BaseBackendCommand._get("Service", self.service_manager, id)
-
- def get_endpoint_template(self, id):
- return BaseBackendCommand._get("Endpoint Template",
- self.endpoint_template_manager, id)
diff --git a/keystone/manage2/commands/__init__.py b/keystone/manage2/commands/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/manage2/commands/__init__.py
+++ /dev/null
diff --git a/keystone/manage2/commands/create_credential.py b/keystone/manage2/commands/create_credential.py
deleted file mode 100644
index d65bb597..00000000
--- a/keystone/manage2/commands/create_credential.py
+++ /dev/null
@@ -1,43 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-from keystone.backends import models
-
-
-@common.arg('--user-id',
- required=True,
- help='identifies the user who can authenticate with this credential')
-@common.arg('--tenant-id',
- required=False,
- help='identifies the tenant upon which the crednetial is valid')
-@common.arg('--type',
- required=True,
- help="credential type (e.g. 'EC2')")
-@common.arg('--key',
- required=True)
-@common.arg('--secret',
- required=True)
-class Command(base.BaseBackendCommand, mixins.DateTimeMixin):
- """Creates a new credential."""
-
- # pylint: disable=E1101,R0913
- def create_credential(self, user_id, credential_type, key, secret,
- tenant_id=None):
- self.get_user(user_id)
- self.get_tenant(tenant_id)
-
- obj = models.Credentials()
- obj.user_id = user_id
- obj.tenant_id = tenant_id
- obj.type = credential_type
- obj.key = key
- obj.secret = secret
-
- return self.credential_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- credential = self.create_credential(user_id=args.user_id,
- tenant_id=args.tenant_id, credential_type=args.type,
- key=args.key, secret=args.secret)
- print credential.id
diff --git a/keystone/manage2/commands/create_endpoint_template.py b/keystone/manage2/commands/create_endpoint_template.py
deleted file mode 100644
index dfb58294..00000000
--- a/keystone/manage2/commands/create_endpoint_template.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from keystone import models
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-
-
-@common.arg('--region',
- required=True,
- help='identifies the region where the endpoint exists')
-@common.arg('--service-id',
- required=True,
- help='references the service that owns the endpoint, by ID')
-@common.arg('--public-url',
- required=True,
- help='url to access the endpoint over a public network (e.g. the '
- 'internet)')
-@common.arg('--admin-url',
- required=True,
- help='url to access service administrator api')
-@common.arg('--internal-url',
- required=True,
- help='url to access the endpoint over a high bandwidth, low latency, '
- 'unmetered network (e.g. LAN)')
-@common.arg('--global',
- action='store_true',
- required=False,
- default=False,
- help='indicates whether the endpoint should be mapped to tenants '
- '(tenant-specific) or not (global)')
-@common.arg('--disabled',
- action='store_true',
- required=False,
- default=False,
- help="create the endpoint in a disabled state (endpoints are enabled by "
- "default)")
-class Command(base.BaseBackendCommand, mixins.DateTimeMixin):
- """Creates a new endpoint template."""
-
- # pylint: disable=E1101,R0913
- def create_endpoint_template(self, region, service_id, public_url,
- admin_url, internal_url, is_global=False, is_enabled=True):
- self.get_service(service_id)
-
- obj = models.EndpointTemplate()
- obj.region = region
- obj.service_id = service_id
- obj.public_url = public_url
- obj.admin_url = admin_url
- obj.internal_url = internal_url
- obj.is_global = is_global
- obj.enabled = is_enabled
-
- return self.endpoint_template_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- endpoint_template = self.create_endpoint_template(region=args.region,
- service_id=args.service_id, public_url=args.public_url,
- admin_url=args.admin_url, internal_url=args.internal_url,
- is_global=getattr(args, 'global'),
- is_enabled=(not args.disabled))
- print endpoint_template.id
diff --git a/keystone/manage2/commands/create_role.py b/keystone/manage2/commands/create_role.py
deleted file mode 100644
index 0460da69..00000000
--- a/keystone/manage2/commands/create_role.py
+++ /dev/null
@@ -1,36 +0,0 @@
-from keystone import models
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--name',
- required=True,
- help='a unique role name')
-@common.arg('--description',
- required=False,
- help='describe the role')
-@common.arg('--service-id',
- required=False,
- help='service which owns the role')
-class Command(base.BaseBackendCommand):
- """Creates a new role.
-
- Optionally, specify a service to own the role.
- """
-
- # pylint: disable=E1101
- def create_role(self, name, description=None, service_id=None):
- self.get_service(service_id)
-
- obj = models.Role()
- obj.name = name
- obj.description = description
- obj.service_id = service_id
-
- return self.role_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- role = self.create_role(name=args.name,
- description=args.description, service_id=args.service_id)
- print role.id
diff --git a/keystone/manage2/commands/create_service.py b/keystone/manage2/commands/create_service.py
deleted file mode 100644
index 5bbbdb41..00000000
--- a/keystone/manage2/commands/create_service.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from keystone.manage2 import common
-from keystone.manage2 import base
-from keystone.backends import models
-
-
-@common.arg('--name',
- required=True,
- help='unique service name')
-@common.arg('--type',
- required=True,
- help='service type (e.g. identity, compute, object-storage, etc)')
-@common.arg('--description',
- required=False,
- help='describe the service')
-@common.arg('--owner-id',
- required=False,
- help='user who owns the service')
-class Command(base.BaseBackendCommand):
- """Creates a new service.
-
- Optionally, specify a user to own the service.
- """
-
- # pylint: disable=E1101,R0913
- def create_service(self, name, service_type, description=None,
- owner_id=None):
- self.get_user(owner_id)
-
- obj = models.Service()
- obj.name = name
- obj.type = service_type
- obj.owner_id = owner_id
- obj.desc = description
-
- return self.service_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- service = self.create_service(name=args.name,
- service_type=args.type, description=args.description,
- owner_id=args.owner_id)
- print service.id
diff --git a/keystone/manage2/commands/create_tenant.py b/keystone/manage2/commands/create_tenant.py
deleted file mode 100644
index 3fed3089..00000000
--- a/keystone/manage2/commands/create_tenant.py
+++ /dev/null
@@ -1,38 +0,0 @@
-from keystone.manage2 import common
-from keystone.manage2 import base
-from keystone.backends import models
-
-
-@common.arg('--id',
- required=False,
- help='a unique identifier used in URLs')
-@common.arg('--name',
- required=True,
- help='a unique name')
-@common.arg('--disabled',
- action='store_true',
- required=False,
- default=False,
- help="create the tenant in a disabled state (tenants are enabled by "
- "default)")
-class Command(base.BaseBackendCommand):
- """Creates a new tenant, enabled by default.
-
- The tenant is enabled by default, but can optionally be disabled upon
- creation.
- """
-
- # pylint: disable=E1101
- def create_tenant(self, name, id=None, enabled=True):
- obj = models.Tenant()
- obj.id = id
- obj.name = name
- obj.enabled = enabled
-
- return self.tenant_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- tenant = self.create_tenant(id=args.id, name=args.name,
- enabled=(not args.disabled))
- print tenant.id
diff --git a/keystone/manage2/commands/create_token.py b/keystone/manage2/commands/create_token.py
deleted file mode 100644
index 14778b34..00000000
--- a/keystone/manage2/commands/create_token.py
+++ /dev/null
@@ -1,59 +0,0 @@
-import uuid
-
-from keystone.backends import models
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-
-
-@common.arg('--id',
- required=False,
- help='a unique token ID')
-@common.arg('--user-id',
- required=True,
- help='identifies the user who can authenticate with this token')
-@common.arg('--tenant-id',
- required=False,
- help='identifies the tenant upon which the token is valid')
-@common.arg('--expires',
- required=False,
- help='identifies the POSIX date/time until which the token is valid '
- '(e.g. 1999-01-31T23:59)')
-class Command(base.BaseBackendCommand, mixins.DateTimeMixin):
- """Creates a new token.
-
- If a token ID is not provided, one will be generated automatically.
-
- If a tenant ID is not provided, the token will be unscoped.
-
- If an expiration datetime is not provided, the token will expires 24
- hours after creation.
- """
-
- # pylint: disable=E1101,R0913
- def create_token(self, user_id, token_id=None, tenant_id=None,
- expires=None):
- self.get_user(user_id)
- self.get_tenant(tenant_id)
-
- obj = models.Token()
- obj.user_id = user_id
- obj.tenant_id = tenant_id
-
- if token_id is not None:
- obj.id = token_id
- else:
- obj.id = uuid.uuid4().hex
-
- if expires is not None:
- obj.expires = self.str_to_datetime(expires)
- else:
- obj.expires = Command.get_datetime_tomorrow()
-
- return self.token_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- token = self.create_token(token_id=args.id, user_id=args.user_id,
- tenant_id=args.tenant_id, expires=args.expires)
- print token.id
diff --git a/keystone/manage2/commands/create_user.py b/keystone/manage2/commands/create_user.py
deleted file mode 100644
index efe5b131..00000000
--- a/keystone/manage2/commands/create_user.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.backends import models
-
-
-@common.arg('--id',
- required=False,
- help='a unique identifier used in URLs')
-@common.arg('--name',
- required=True,
- help='a unique username used for authentication')
-@common.arg('--email',
- required=False,
- help='a unique email address')
-@common.arg('--password',
- required=True,
- help='used for authentication')
-@common.arg('--tenant-id',
- required=False,
- help='default tenant ID')
-@common.arg('--disabled',
- action='store_true',
- required=False,
- default=False,
- help="create the user in a disabled state (users are enabled by "
- "default)")
-class Command(base.BaseBackendCommand):
- """Creates a new user, enabled by default.
-
- Optionally, specify a default tenant for the user.
- The user is enabled by default, but can be disabled upon creation as
- well.
- """
-
- # pylint: disable=E1101,R0913
- def create_user(self, name, password, id=None, email=None, tenant_id=None,
- enabled=True):
- self.get_tenant(tenant_id)
-
- obj = models.User()
- obj.id = id
- obj.name = name
- obj.password = password
- obj.email = email
- obj.enabled = enabled
- obj.tenant_id = tenant_id
-
- return self.user_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- user = self.create_user(id=args.id, name=args.name,
- password=args.password, email=args.email,
- tenant_id=args.tenant_id, enabled=(not args.disabled))
- print user.id
diff --git a/keystone/manage2/commands/delete_credential.py b/keystone/manage2/commands/delete_credential.py
deleted file mode 100644
index 50f0c41b..00000000
--- a/keystone/manage2/commands/delete_credential.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the credential to be deleted by ID')
-class Command(base.BaseBackendCommand):
- """Deletes the specified credential."""
-
- # pylint: disable=E1101
- def delete_credential(self, id):
- credential = self.get_credential(id)
- self.credential_manager.delete(credential.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_credential(id=args.where_id)
diff --git a/keystone/manage2/commands/delete_endpoint_template.py b/keystone/manage2/commands/delete_endpoint_template.py
deleted file mode 100644
index b39bed1e..00000000
--- a/keystone/manage2/commands/delete_endpoint_template.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the endpoint template to be deleted by ID')
-class Command(base.BaseBackendCommand):
- """Deletes the specified endpoint_template."""
-
- # pylint: disable=E1101
- def delete_endpoint_template(self, id):
- endpoint_template = self.get_endpoint_template(id)
- self.endpoint_template_manager.delete(endpoint_template.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_endpoint_template(id=args.where_id)
diff --git a/keystone/manage2/commands/delete_role.py b/keystone/manage2/commands/delete_role.py
deleted file mode 100644
index d841efb9..00000000
--- a/keystone/manage2/commands/delete_role.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the role to be deleted by ID')
-class Command(base.BaseBackendCommand):
- """Deletes the specified role."""
-
- # pylint: disable=E1101
- def delete_role(self, id):
- role = self.get_role(id)
- self.role_manager.delete(role.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_role(id=args.where_id)
diff --git a/keystone/manage2/commands/delete_service.py b/keystone/manage2/commands/delete_service.py
deleted file mode 100644
index 8119659f..00000000
--- a/keystone/manage2/commands/delete_service.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the service to be deleted by ID')
-class Command(base.BaseBackendCommand):
- """Deletes the specified service."""
-
- # pylint: disable=E1101
- def delete_service(self, id):
- service = self.get_service(id)
- self.service_manager.delete(service.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_service(id=args.where_id)
diff --git a/keystone/manage2/commands/delete_tenant.py b/keystone/manage2/commands/delete_tenant.py
deleted file mode 100644
index 2adbf904..00000000
--- a/keystone/manage2/commands/delete_tenant.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the tenant to be deleted')
-class Command(base.BaseBackendCommand):
- """Deletes the specified tenant.
-
- This command is irreversible! To simply disable a tenant,
- use `update_tenant --disable`."""
-
- # pylint: disable=E1101
- def delete_tenant(self, id):
- tenant = self.get_tenant(id)
- self.tenant_manager.delete(tenant.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_tenant(id=args.where_id)
diff --git a/keystone/manage2/commands/delete_token.py b/keystone/manage2/commands/delete_token.py
deleted file mode 100644
index 544855c8..00000000
--- a/keystone/manage2/commands/delete_token.py
+++ /dev/null
@@ -1,18 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the token to be deleted by ID')
-class Command(base.BaseBackendCommand):
- """Deletes the specified token."""
-
- # pylint: disable=E1101
- def delete_token(self, id):
- token = self.get_token(id)
- self.token_manager.delete(token.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_token(id=args.where_id)
diff --git a/keystone/manage2/commands/delete_user.py b/keystone/manage2/commands/delete_user.py
deleted file mode 100644
index 701df76f..00000000
--- a/keystone/manage2/commands/delete_user.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identify the user to be deleted by ID')
-class Command(base.BaseBackendCommand):
- """Deletes the specified user.
-
- This command is irreversible! To simply disable a user,
- use `update_user --disable`."""
-
- # pylint: disable=E1101
- def delete_user(self, id):
- user = self.get_user(id)
- self.user_manager.delete(user.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_user(id=args.where_id)
diff --git a/keystone/manage2/commands/downgrade_database.py b/keystone/manage2/commands/downgrade_database.py
deleted file mode 100644
index 3bfbcc20..00000000
--- a/keystone/manage2/commands/downgrade_database.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from keystone.backends.sqlalchemy import migration
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--version',
- required=True,
- help='specify the desired database version')
-class Command(base.BaseSqlalchemyCommand):
- """Downgrades the database to the specified version"""
-
- @staticmethod
- def downgrade_database(version):
- """Downgrade database to the specified version"""
- migration.downgrade(Command._get_connection_string(), version=version)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.downgrade_database(version=args.version)
diff --git a/keystone/manage2/commands/goto_database.py b/keystone/manage2/commands/goto_database.py
deleted file mode 100644
index d419c1c7..00000000
--- a/keystone/manage2/commands/goto_database.py
+++ /dev/null
@@ -1,26 +0,0 @@
-from keystone.backends.sqlalchemy import migration
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--version',
- required=True,
- help='specify the desired database version')
-class Command(base.BaseSqlalchemyCommand):
- """Jumps to the specified database version without running migrations.
-
- Useful for initializing your version control at a version other than zero
- (e.g. you have an existing post-diablo database).
-
- """
-
- @staticmethod
- def goto_database_version(version):
- """Override database's current migration level"""
- if not migration.db_goto_version(Command._get_connection_string(),
- version):
- raise Exception("Unable to jump to specified version")
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.goto_database_version(version=args.version)
diff --git a/keystone/manage2/commands/grant_role.py b/keystone/manage2/commands/grant_role.py
deleted file mode 100644
index 770d9887..00000000
--- a/keystone/manage2/commands/grant_role.py
+++ /dev/null
@@ -1,45 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.backends import models
-
-
-@common.arg('--user-id',
- required=True,
- help='identify the user to grant the role to by ID')
-@common.arg('--role-id',
- required=True,
- help='identify the role to be granted by ID')
-@common.arg('--tenant-id',
- required=False,
- help='identify the tenant for the granted role is valid (the role is '
- 'global if a tenant is not specified)')
-class Command(base.BaseBackendCommand):
- """Grants a role to a user, and optionally, for a specific tenant.
-
- If a tenant is not specified, the role is granted globally."""
-
- # pylint: disable=E1101,R0913
- def grant_role(self, user_id, role_id, tenant_id=None):
- self.get_user(user_id)
- self.get_role(role_id)
- self.get_tenant(tenant_id)
-
- # this is a bit of a hack to validate that the grant doesn't exist
- grant = self.grant_manager.rolegrant_get_by_ids(user_id, role_id,
- tenant_id)
- if grant is not None:
- raise KeyError('Grant already exists for User ID %s, '
- 'Role ID %s and Tenant ID %s' % (user_id, role_id,
- tenant_id))
-
- obj = models.UserRoleAssociation()
- obj.user_id = user_id
- obj.role_id = role_id
- obj.tenant_id = tenant_id
-
- self.user_manager.user_role_add(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.grant_role(user_id=args.user_id, role_id=args.role_id,
- tenant_id=args.tenant_id)
diff --git a/keystone/manage2/commands/list_credentials.py b/keystone/manage2/commands/list_credentials.py
deleted file mode 100644
index 4bc8a5b2..00000000
--- a/keystone/manage2/commands/list_credentials.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin,
- mixins.DateTimeMixin):
- """Lists all credentials in the system."""
-
- # pylint: disable=E1101
- def get_credentials(self):
- return self.credential_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(["ID", "User ID", "Tenant ID",
- "Type", "Key", "Secret"])
-
- for obj in self.get_credentials():
- row = [obj.id, obj.user_id, obj.tenant_id,
- obj.type, obj.key, obj.secret]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_endpoint_templates.py b/keystone/manage2/commands/list_endpoint_templates.py
deleted file mode 100644
index fbfc5341..00000000
--- a/keystone/manage2/commands/list_endpoint_templates.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists all endpoint templates in the system."""
-
- # pylint: disable=E1101
- def get_endpoint_templates(self):
- return self.endpoint_template_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(['ID', 'Service ID', 'Region', 'Enabled',
- 'Global', 'Public URL', 'Admin URL', 'Internal URL'])
-
- for obj in self.get_endpoint_templates():
- row = [obj.id, obj.service_id, obj.region, obj.enabled,
- obj.is_global, obj.public_url, obj.admin_url,
- obj.internal_url]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_endpoints.py b/keystone/manage2/commands/list_endpoints.py
deleted file mode 100644
index dfebb410..00000000
--- a/keystone/manage2/commands/list_endpoints.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists all roles in the system."""
-
- # pylint: disable=E1101
- def get_roles(self):
- return self.endpoint_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(["Endpoint Template ID", "Tenant ID"])
-
- for obj in self.get_roles():
- row = [obj.endpoint_template_id, obj.tenant_id]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_role_grants.py b/keystone/manage2/commands/list_role_grants.py
deleted file mode 100644
index cd69ed33..00000000
--- a/keystone/manage2/commands/list_role_grants.py
+++ /dev/null
@@ -1,50 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-
-
-@common.arg('--where-user-id',
- required=False,
- help='lists roles granted to a specific user')
-@common.arg('--where-role-id',
- required=False,
- help='lists users and tenants a role has been granted to')
-@common.arg('--where-tenant-id',
- required=False,
- help='lists roles granted on a specific tenant')
-@common.arg('--where-global',
- action='store_true',
- required=False,
- default=False,
- help="lists roles that have been granted globally")
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists the users and tenants a role has been granted to."""
-
- # pylint: disable=E1101,R0913
- def list_role_grants(self, role_id=None, user_id=None, tenant_id=None,
- is_global=False):
- self.get_user(user_id)
- self.get_role(role_id)
- self.get_tenant(tenant_id)
-
- if is_global:
- tenant_id = False
-
- return self.grant_manager.list_role_grants(user_id=user_id,
- role_id=role_id, tenant_id=tenant_id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.true_or_false(args, 'where_tenant_id', 'where_global')
-
- table = self.build_table(["Role ID", "User ID", "Tenant ID",
- "Global"])
-
- for obj in self.list_role_grants(role_id=args.where_role_id,
- user_id=args.where_user_id, tenant_id=args.where_tenant_id,
- is_global=args.where_global):
- row = [obj.role_id, obj.user_id, obj.tenant_id,
- obj.tenant_id is None]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_roles.py b/keystone/manage2/commands/list_roles.py
deleted file mode 100644
index 9e381fc7..00000000
--- a/keystone/manage2/commands/list_roles.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists all roles in the system."""
-
- # pylint: disable=E1101
- def get_roles(self):
- return self.role_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(["ID", "Name", "Service ID", "Description"])
-
- for obj in self.get_roles():
- row = [obj.id, obj.name, obj.service_id, obj.desc]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_services.py b/keystone/manage2/commands/list_services.py
deleted file mode 100644
index 0496c50b..00000000
--- a/keystone/manage2/commands/list_services.py
+++ /dev/null
@@ -1,21 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists all services in the system."""
-
- # pylint: disable=E1101
- def get_services(self):
- return self.service_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(["ID", "Name", "Type", "Owner ID",
- "Description"])
-
- for obj in self.get_services():
- row = [obj.id, obj.name, obj.type, obj.owner_id, obj.desc]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_tenants.py b/keystone/manage2/commands/list_tenants.py
deleted file mode 100644
index 81a15ca4..00000000
--- a/keystone/manage2/commands/list_tenants.py
+++ /dev/null
@@ -1,22 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists all tenants in the system."""
-
- # pylint: disable=E1101
- def get_tenants(self):
- return self.tenant_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
-
- table = self.build_table(["ID", "Name", "Enabled"])
-
- # populate the table
- for tenant in self.get_tenants():
- row = [tenant.id, tenant.name, tenant.enabled]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_tokens.py b/keystone/manage2/commands/list_tokens.py
deleted file mode 100644
index 9bdc3063..00000000
--- a/keystone/manage2/commands/list_tokens.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin,
- mixins.DateTimeMixin):
- """Lists all tokens in the system."""
-
- # pylint: disable=E1101
- def get_tokens(self):
- return self.token_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(["ID", "User ID", "Tenant ID",
- "Expiration"])
-
- for obj in self.get_tokens():
- row = [obj.id, obj.user_id, obj.tenant_id,
- self.datetime_to_str(obj.expires)]
- table.add_row(row)
-
- self.print_table(table)
diff --git a/keystone/manage2/commands/list_users.py b/keystone/manage2/commands/list_users.py
deleted file mode 100644
index a23202dc..00000000
--- a/keystone/manage2/commands/list_users.py
+++ /dev/null
@@ -1,23 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import mixins
-
-
-class Command(base.BaseBackendCommand, mixins.ListMixin):
- """Lists all users in the system."""
-
- # pylint: disable=E1101
- def get_users(self):
- return self.user_manager.get_all()
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- table = self.build_table(["ID", "Name", "Email", "Default Tenant ID",
- "Enabled"])
-
- for user in self.get_users():
- row = [user.id, user.name, user.email, user.tenant_id,
- user.enabled]
- table.add_row(row)
-
- # TODO(dolph): sort order and subsets could become CLI options
- self.print_table(table)
diff --git a/keystone/manage2/commands/map_endpoint.py b/keystone/manage2/commands/map_endpoint.py
deleted file mode 100644
index ab63ec9d..00000000
--- a/keystone/manage2/commands/map_endpoint.py
+++ /dev/null
@@ -1,37 +0,0 @@
-from keystone import models
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--tenant-id',
- required=True,
- help='identify the tenant to be mapped by ID')
-@common.arg('--endpoint-template-id',
- required=True,
- help='identify the endpoint to be mapped by ID')
-class Command(base.BaseBackendCommand):
- """Maps a non-global endpoint to a tenant.
-
- If a mapping exists between a tenant and an endpoint template, then
- the endpoint will appear in the tenant's service catalog, customized
- for the tenant.
-
- Global endpoints are already available to all tenants and therefore don't
- need to be mapped.
- """
-
- # pylint: disable=E1101,R0913
- def create_endpoint(self, endpoint_template_id, tenant_id):
- self.get_endpoint_template(endpoint_template_id)
- self.get_tenant(tenant_id)
-
- obj = models.Endpoint()
- obj.endpoint_template_id = endpoint_template_id
- obj.tenant_id = tenant_id
-
- self.endpoint_manager.create(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.create_endpoint(endpoint_template_id=args.endpoint_template_id,
- tenant_id=args.tenant_id)
diff --git a/keystone/manage2/commands/revoke_role.py b/keystone/manage2/commands/revoke_role.py
deleted file mode 100644
index 6b403d7d..00000000
--- a/keystone/manage2/commands/revoke_role.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--user-id',
- required=True,
- help='identify the user to revoke the role from by ID')
-@common.arg('--role-id',
- required=True,
- help='identify the role to be revoked by ID')
-@common.arg('--tenant-id',
- required=False,
- help='identify the tenant for the role to be revoked from by ID (the '
- 'role is assumed to be global if a tenant is not specified)')
-class Command(base.BaseBackendCommand):
- """Revoke a role from a user, and optionally, from a specific tenant.
-
- If a tenant is not specified, then the role is assumed to be global,
- and revoked as a global role.
- """
-
- # pylint: disable=E1101,R0913
- def revoke_role(self, user_id, role_id, tenant_id=None):
- self.get_user(user_id)
- self.get_role(role_id)
- self.get_tenant(tenant_id)
-
- grant = self.grant_manager.rolegrant_get_by_ids(user_id, role_id,
- tenant_id)
-
- if grant is None:
- raise KeyError('Grant not found for User ID %s, Role ID %s and '
- 'Tenant ID %s' % (user_id, role_id, tenant_id))
-
- self.grant_manager.rolegrant_delete(grant.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.revoke_role(user_id=args.user_id, role_id=args.role_id,
- tenant_id=args.tenant_id)
diff --git a/keystone/manage2/commands/sync_database.py b/keystone/manage2/commands/sync_database.py
deleted file mode 100644
index 62092d50..00000000
--- a/keystone/manage2/commands/sync_database.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from keystone.backends.sqlalchemy import migration
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--version',
- required=False,
- help='specify the desired database version')
-class Command(base.BaseSqlalchemyCommand):
- """Upgrades the database to the latest schema."""
-
- @staticmethod
- def sync_database(version=None):
- """Place database under migration control & automatically upgrade"""
- migration.db_sync(Command._get_connection_string(), version=version)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.sync_database(version=args.version)
diff --git a/keystone/manage2/commands/unmap_endpoint.py b/keystone/manage2/commands/unmap_endpoint.py
deleted file mode 100644
index 991e597e..00000000
--- a/keystone/manage2/commands/unmap_endpoint.py
+++ /dev/null
@@ -1,28 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--tenant-id',
- required=True,
- help='identify the tenant to be unmapped by ID')
-@common.arg('--endpoint-template-id',
- required=True,
- help='identify the endpoint template to be unmapped by ID')
-class Command(base.BaseBackendCommand):
- """Unmap an endpoint template from a tenant."""
-
- # pylint: disable=E1101,R0913
- def delete_endpoint(self, endpoint_template_id, tenant_id):
- obj = self.endpoint_manager.get_by_ids(endpoint_template_id, tenant_id)
-
- if obj is None:
- raise KeyError("Endpoint mapping not found for "
- "endpoint_template_id=%s, tenant_id=%s" % (
- endpoint_template_id, tenant_id))
-
- self.endpoint_manager.delete(obj.id)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.delete_endpoint(endpoint_template_id=args.endpoint_template_id,
- tenant_id=args.tenant_id)
diff --git a/keystone/manage2/commands/update_credential.py b/keystone/manage2/commands/update_credential.py
deleted file mode 100644
index eb15ef03..00000000
--- a/keystone/manage2/commands/update_credential.py
+++ /dev/null
@@ -1,55 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the credential to update by ID')
-@common.arg('--user-id',
- required=False,
- help='change the user the credential applies to, by ID')
-@common.arg('--tenant-id',
- required=False,
- help='change the tenant this credential applies to, by ID')
-@common.arg('--type',
- required=True,
- help="change the credential type (e.g. 'EC2')")
-@common.arg('--key',
- required=True,
- help="change the credential key")
-@common.arg('--secret',
- required=True,
- help="change the credential secret")
-class Command(base.BaseBackendCommand, mixins.DateTimeMixin):
- """Updates the specified credential."""
-
- # pylint: disable=E1101,R0913
- def update_credential(self, id, user_id=None, tenant_id=None,
- cred_type=None, secret=None, key=None):
- obj = self.get_credential(id)
- self.get_user(user_id)
- self.get_tenant(tenant_id)
-
- if user_id is not None:
- obj.user_id = user_id
-
- if tenant_id is not None:
- obj.tenant_id = tenant_id
-
- if cred_type is not None:
- obj.type = cred_type
-
- if key is not None:
- obj.key = key
-
- if secret is not None:
- obj.secret = secret
-
- self.credential_manager.update(id, obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.update_credential(id=args.where_id, user_id=args.user_id,
- tenant_id=args.tenant_id, cred_type=args.type,
- key=args.key, secret=args.secret)
diff --git a/keystone/manage2/commands/update_endpoint_template.py b/keystone/manage2/commands/update_endpoint_template.py
deleted file mode 100644
index 3f0f6893..00000000
--- a/keystone/manage2/commands/update_endpoint_template.py
+++ /dev/null
@@ -1,88 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the endpoint template to update by ID')
-@common.arg('--region',
- required=True,
- help='identifies the region where the endpoint exists')
-@common.arg('--service-id',
- required=True,
- help='references the service that owns the endpoint, by ID')
-@common.arg('--public-url',
- required=True,
- help='url to access the endpoint over a public network (e.g. the '
- 'internet)')
-@common.arg('--admin-url',
- required=True,
- help='url to access service administrator api')
-@common.arg('--internal-url',
- required=True,
- help='url to access the endpoint over a high bandwidth, low latency, '
- 'unmetered network (e.g. LAN)')
-@common.arg('--global',
- action='store_true',
- required=False,
- default=False,
- help='indicates whether the endpoint should apply to all tenants')
-@common.arg('--non-global',
- action='store_true',
- required=False,
- default=False,
- help='indicates whether the endpoint should be mapped to specific tenants')
-@common.arg('--enable',
- action='store_true',
- required=False,
- default=False,
- help="enable the endpoint template")
-@common.arg('--disable',
- action='store_true',
- required=False,
- default=False,
- help="disable the endpoint template")
-class Command(base.BaseBackendCommand, mixins.DateTimeMixin):
- """Updates an existing endpoint template."""
-
- # pylint: disable=E1101,R0913
- def update_endpoint_template(self, id, region, service_id, public_url,
- admin_url, internal_url, is_global=False, is_enabled=True):
- obj = self.get_endpoint_template(id)
-
- self.get_service(service_id)
-
- if region is not None:
- obj.region = region
-
- if service_id is not None:
- obj.service_id = service_id
-
- if public_url is not None:
- obj.public_url = public_url
-
- if admin_url is not None:
- obj.admin_url = admin_url
-
- if internal_url is not None:
- obj.internal_url = internal_url
-
- if is_global is not None:
- obj.is_global = is_global
-
- if is_enabled is not None:
- obj.enabled = is_enabled
-
- self.endpoint_template_manager.update(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- is_global = self.true_or_false(args, 'global', 'non_global')
- enabled = self.true_or_false(args, 'enable', 'disable')
-
- self.update_endpoint_template(id=args.where_id,
- region=args.region, service_id=args.service_id,
- public_url=args.public_url, admin_url=args.admin_url,
- internal_url=args.internal_url, is_global=is_global,
- is_enabled=enabled)
diff --git a/keystone/manage2/commands/update_role.py b/keystone/manage2/commands/update_role.py
deleted file mode 100644
index 2f459661..00000000
--- a/keystone/manage2/commands/update_role.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the role to update by ID')
-@common.arg('--name',
- required=False,
- help='a unique role name')
-@common.arg('--description',
- required=False,
- help='describe the role')
-@common.arg('--service-id',
- required=False,
- help='service which owns the role')
-class Command(base.BaseBackendCommand):
- """Updates the specified role."""
-
- # pylint: disable=E1101,R0913
- def update_role(self, id, name=None, description=None, service_id=None):
- obj = self.get_role(id)
-
- if name is not None:
- obj.name = name
-
- if description is not None:
- obj.description = description
-
- if service_id is not None:
- service = self.get_service(service_id)
- obj.service_id = service.id
-
- self.role_manager.update(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.update_role(id=args.where_id, name=args.name,
- description=args.description,
- service_id=args.service_id)
diff --git a/keystone/manage2/commands/update_service.py b/keystone/manage2/commands/update_service.py
deleted file mode 100644
index 7c7c3dac..00000000
--- a/keystone/manage2/commands/update_service.py
+++ /dev/null
@@ -1,47 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the service to update by ID')
-@common.arg('--name',
- required=False,
- help='unique service name')
-@common.arg('--type',
- required=False,
- help='service type (e.g. identity, compute, object-storage, etc)')
-@common.arg('--description',
- required=False,
- help='describe the service')
-@common.arg('--owner-id',
- required=False,
- help='user who owns the service')
-class Command(base.BaseBackendCommand):
- """Updates the specified service."""
-
- # pylint: disable=E1101,R0913
- def update_service(self, id, name=None, service_type=None,
- description=None, owner_id=None):
- obj = self.get_service(id)
-
- if name is not None:
- obj.name = name
-
- if service_type is not None:
- obj.type = service_type
-
- if description is not None:
- obj.description = description
-
- if owner_id is not None:
- owner = self.get_user(owner_id)
- obj.owner_id = owner.id
-
- self.service_manager.update(obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.update_service(id=args.where_id, name=args.name,
- service_type=args.type,
- description=args.description, owner_id=args.owner_id)
diff --git a/keystone/manage2/commands/update_tenant.py b/keystone/manage2/commands/update_tenant.py
deleted file mode 100644
index b2f844f1..00000000
--- a/keystone/manage2/commands/update_tenant.py
+++ /dev/null
@@ -1,40 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the tenant to update by ID')
-@common.arg('--name',
- required=False,
- help="change the tenant's name")
-@common.arg('--enable',
- action='store_true',
- required=False,
- default=False,
- help="enable the tenant")
-@common.arg('--disable',
- action='store_true',
- required=False,
- default=False,
- help="disable the tenant")
-class Command(base.BaseBackendCommand):
- """Updates the specified tenant."""
-
- # pylint: disable=E1101
- def update_tenant(self, id, name=None, enabled=None):
- tenant = self.get_tenant(id)
-
- if name is not None:
- tenant.name = name
-
- if enabled is not None:
- tenant.enabled = enabled
-
- self.tenant_manager.update(tenant)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- enabled = self.true_or_false(args, 'enable', 'disable')
-
- self.update_tenant(id=args.where_id, name=args.name, enabled=enabled)
diff --git a/keystone/manage2/commands/update_token.py b/keystone/manage2/commands/update_token.py
deleted file mode 100644
index f2c78328..00000000
--- a/keystone/manage2/commands/update_token.py
+++ /dev/null
@@ -1,42 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2 import mixins
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the token to update by ID')
-@common.arg('--user-id',
- required=False,
- help='change the user the token applies to, by ID')
-@common.arg('--tenant-id',
- required=False,
- help='change the tenant this token applies to, by ID')
-@common.arg('--expires',
- required=False,
- help="change the token's expiration date")
-class Command(base.BaseBackendCommand, mixins.DateTimeMixin):
- """Updates the specified token."""
-
- # pylint: disable=E1101,R0913
- def update_token(self, id, user_id=None, tenant_id=None,
- expires=None):
- obj = self.get_token(id)
- self.get_user(user_id)
- self.get_tenant(tenant_id)
-
- if user_id is not None:
- obj.user_id = user_id
-
- if tenant_id is not None:
- obj.tenant_id = tenant_id
-
- if expires is not None:
- obj.expires = self.str_to_datetime(expires)
-
- self.token_manager.update(id, obj)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.update_token(id=args.where_id, user_id=args.user_id,
- tenant_id=args.tenant_id, expires=args.expires)
diff --git a/keystone/manage2/commands/update_user.py b/keystone/manage2/commands/update_user.py
deleted file mode 100644
index dafce642..00000000
--- a/keystone/manage2/commands/update_user.py
+++ /dev/null
@@ -1,62 +0,0 @@
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--where-id',
- required=True,
- help='identifies the user to update by ID')
-@common.arg('--name',
- required=False,
- help="change the user's name")
-@common.arg('--password',
- required=False,
- help="change the user's password")
-@common.arg('--email',
- required=False,
- help="change the user's email address")
-@common.arg('--tenant_id',
- required=False,
- help="change the user's default tenant")
-@common.arg('--enable',
- action='store_true',
- required=False,
- default=False,
- help="enable the user")
-@common.arg('--disable',
- action='store_true',
- required=False,
- default=False,
- help="disable the user")
-class Command(base.BaseBackendCommand):
- """Updates the specified user."""
-
- # pylint: disable=E1101,R0913
- def update_user(self, id, name=None, password=None, email=None,
- tenant_id=None, enabled=None):
- user = self.get_user(id)
-
- if name is not None:
- user.name = name
-
- if password is not None:
- user.password = password
-
- if email is not None:
- user.email = email
-
- if tenant_id is not None:
- tenant = self.get_tenant(tenant_id)
- user.tenant = tenant.id
-
- if enabled is not None:
- user.enabled = enabled
-
- self.user_manager.update(user)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- enabled = self.true_or_false(args, 'enable', 'disable')
-
- self.update_user(id=args.where_id, name=args.name,
- password=args.password, email=args.email,
- tenant_id=args.tenant_id, enabled=enabled)
diff --git a/keystone/manage2/commands/upgrade_database.py b/keystone/manage2/commands/upgrade_database.py
deleted file mode 100644
index 94884442..00000000
--- a/keystone/manage2/commands/upgrade_database.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from keystone.backends.sqlalchemy import migration
-from keystone.manage2 import base
-from keystone.manage2 import common
-
-
-@common.arg('--version',
- required=True,
- help='specify the desired database version')
-class Command(base.BaseSqlalchemyCommand):
- """Upgrades the database to the specified version."""
-
- @staticmethod
- def upgrade_database(version):
- """Upgrade database to the specified version"""
- migration.upgrade(Command._get_connection_string(), version=version)
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.upgrade_database(version=args.version)
diff --git a/keystone/manage2/commands/version.py b/keystone/manage2/commands/version.py
deleted file mode 100644
index 8e97346f..00000000
--- a/keystone/manage2/commands/version.py
+++ /dev/null
@@ -1,53 +0,0 @@
-from keystone.backends.sqlalchemy import migration
-from keystone import version
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.logic.types import fault
-
-
-@common.arg('--api', action='store_true',
- default=False,
- help='only print the API version')
-@common.arg('--implementation', action='store_true',
- default=False,
- help='only print the implementation version')
-@common.arg('--database', action='store_true',
- default=False,
- help='only print the database version')
-class Command(base.BaseSqlalchemyCommand):
- """Returns keystone version data.
-
- Provides the latest API version, implementation version, database version,
- or all of the above, if none is specified.
- """
-
- @staticmethod
- def get_api_version():
- """Returns a complete API version string"""
- return ' '.join([version.API_VERSION, version.API_VERSION_STATUS])
-
- @staticmethod
- def get_implementation_version():
- """Returns a complete implementation version string"""
- return version.version()
-
- @staticmethod
- def get_database_version():
- """Returns database's current migration level"""
- return migration.db_version(Command._get_connection_string())
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- show_all = not (args.api or args.implementation or args.database)
-
- if args.api or show_all:
- print 'API v%s' % Command.get_api_version()
- if args.implementation or show_all:
- print 'Implementation v%s' % Command.get_implementation_version()
- if args.database or show_all:
- try:
- version_str = 'v%s' % (self.get_database_version())
- except fault.DatabaseMigrationError:
- version_str = 'not under version control'
-
- print 'Database %s' % (version_str)
diff --git a/keystone/manage2/commands/version_control_database.py b/keystone/manage2/commands/version_control_database.py
deleted file mode 100644
index f69e206c..00000000
--- a/keystone/manage2/commands/version_control_database.py
+++ /dev/null
@@ -1,15 +0,0 @@
-from keystone.backends.sqlalchemy import migration
-from keystone.manage2 import base
-
-
-class Command(base.BaseSqlalchemyCommand):
- """Places an existing database under version control."""
-
- @staticmethod
- def version_control_database():
- """Place database under migration control"""
- migration.version_control(Command._get_connection_string())
-
- def run(self, args):
- """Process argparse args, and print results to stdout"""
- self.version_control_database()
diff --git a/keystone/manage2/common.py b/keystone/manage2/common.py
deleted file mode 100644
index 55624109..00000000
--- a/keystone/manage2/common.py
+++ /dev/null
@@ -1,64 +0,0 @@
-import optparse
-import sys
-
-from keystone import backends
-from keystone import config as new_config
-from keystone import version
-from keystone.common import config
-from keystone.managers.credential import Manager as CredentialManager
-from keystone.managers.endpoint import Manager as EndpointManager
-from keystone.managers.endpoint_template import Manager as \
- EndpointTemplateManager
-from keystone.managers.grant import Manager as GrantManager
-from keystone.managers.role import Manager as RoleManager
-from keystone.managers.service import Manager as ServiceManager
-from keystone.managers.tenant import Manager as TenantManager
-from keystone.managers.token import Manager as TokenManager
-from keystone.managers.user import Manager as UserManager
-
-
-def arg(name, **kwargs):
- """Decorate the command class with an argparse argument"""
- def _decorator(cls):
- if not hasattr(cls, '_args'):
- setattr(cls, '_args', {})
- args = getattr(cls, '_args')
- args[name] = kwargs
- return cls
- return _decorator
-
-
-def get_options():
- # Initialize a parser for our configuration paramaters
- parser = optparse.OptionParser("Usage", version='%%prog %s'
- % version.version())
- config.add_common_options(parser)
- config.add_log_options(parser)
-
- # Parse command-line and load config
- (options, args) = config.parse_options(parser, []) # pylint: disable=W0612
-
- return options
-
-
-def init_managers():
- """Initializes backend storage and return managers"""
- if new_config.CONF.backends is None:
- # Get merged config and CLI options and admin-specific settings
- options = get_options()
- config_file = config.find_config_file(options, sys.argv[1:])
- new_config.CONF(config_files=[config_file])
-
- backends.configure_backends()
-
- managers = {}
- managers['credential_manager'] = CredentialManager()
- managers['token_manager'] = TokenManager()
- managers['tenant_manager'] = TenantManager()
- managers['endpoint_manager'] = EndpointManager()
- managers['endpoint_template_manager'] = EndpointTemplateManager()
- managers['user_manager'] = UserManager()
- managers['role_manager'] = RoleManager()
- managers['grant_manager'] = GrantManager()
- managers['service_manager'] = ServiceManager()
- return managers
diff --git a/keystone/manage2/mixins.py b/keystone/manage2/mixins.py
deleted file mode 100644
index 67d3b4fd..00000000
--- a/keystone/manage2/mixins.py
+++ /dev/null
@@ -1,42 +0,0 @@
-import datetime
-import prettytable
-
-
-class ListMixin(object):
- """Implements common patterns for list_* commands"""
-
- @staticmethod
- def build_table(fields):
- table = prettytable.PrettyTable(fields)
-
- # set default alignment
- for field in fields:
- table.set_field_align(field, "l")
-
- return table
-
- @staticmethod
- def print_table(table):
- if "Name" in table.fields:
- table.printt(sortby="Name")
- else:
- table.printt()
-
-
-class DateTimeMixin(object):
- datetime_format = '%Y-%m-%dT%H:%M'
-
- def datetime_to_str(self, dt):
- """Return a string representing the given datetime"""
- return dt.strftime(self.datetime_format)
-
- def str_to_datetime(self, string):
- """Return a datetime representing the given string"""
- return datetime.datetime.strptime(string, self.datetime_format)
-
- @staticmethod
- def get_datetime_tomorrow():
- """Returns a datetime representing 24 hours from now"""
- today = datetime.datetime.utcnow()
- tomorrow = today + datetime.timedelta(days=1)
- return tomorrow
diff --git a/keystone/managers/__init__.py b/keystone/managers/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/managers/__init__.py
+++ /dev/null
diff --git a/keystone/managers/credential.py b/keystone/managers/credential.py
deleted file mode 100644
index 0fc8388a..00000000
--- a/keystone/managers/credential.py
+++ /dev/null
@@ -1,46 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Credential manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.CREDENTIALS
-
- def create(self, token):
- return self.driver.create(token)
-
- def update(self, id, credential):
- return self.driver.update(id, credential)
-
- def get(self, credential_id):
- return self.driver.get(credential_id)
-
- def get_all(self):
- return self.driver.get_all()
-
- def get_by_access(self, access):
- return self.driver.get_by_access(access)
-
- def delete(self, credential_id):
- return self.driver.delete(credential_id)
diff --git a/keystone/managers/endpoint.py b/keystone/managers/endpoint.py
deleted file mode 100644
index 06401a0d..00000000
--- a/keystone/managers/endpoint.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Endpoint manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.ENDPOINT_TEMPLATE
-
- def endpoint_get_by_endpoint_template(self, endpoint_template_id):
- """ Get all endpoints by endpoint template """
- return self.driver.endpoint_get_by_endpoint_template(
- endpoint_template_id)
-
- def delete(self, endpoint_id):
- """ Delete Endpoint """
- self.driver.endpoint_delete(endpoint_id)
-
- def endpoint_get_by_tenant_get_page(self, tenant_id, marker, limit):
- """ Get endpoints by tenant """
- return self.driver.endpoint_get_by_tenant_get_page(
- tenant_id, marker, limit)
-
- def endpoint_get_by_tenant_get_page_markers(self, tenant_id, marker,
- limit):
- return self.driver.endpoint_get_by_tenant_get_page_markers(
- tenant_id, marker, limit)
-
- def create(self, endpoint):
- """ Create a new Endpoint """
- return self.driver.endpoint_add(endpoint)
-
- def get(self, endpoint_id):
- """ Returns Endpoint by ID """
- return self.driver.endpoint_get(endpoint_id)
-
- # pylint: disable=E1103
- def get_by_ids(self, endpoint_template_id, tenant_id):
- """ Returns Endpoint by ID """
- return self.driver.endpoint_get_by_ids(endpoint_template_id, tenant_id)
-
- # pylint: disable=E1103
- def get_all(self):
- """ Returns all Endpoint Templates """
- return self.driver.endpoint_get_all()
diff --git a/keystone/managers/endpoint_template.py b/keystone/managers/endpoint_template.py
deleted file mode 100644
index 9be49e72..00000000
--- a/keystone/managers/endpoint_template.py
+++ /dev/null
@@ -1,69 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" EndpointTemplate manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.ENDPOINT_TEMPLATE
-
- def create(self, obj):
- """ Create a new Endpoint Template """
- return self.driver.create(obj)
-
- def get_all(self):
- """ Returns all endpoint templates """
- return self.driver.get_all()
-
- def get(self, endpoint_template_id):
- """ Returns Endpoint Template by ID """
- return self.driver.get(endpoint_template_id)
-
- def get_page(self, marker, limit):
- """ Get one page of endpoint template list """
- return self.driver.get_page(marker, limit)
-
- def get_page_markers(self, marker, limit):
- """ Calculate pagination markers for endpoint template list """
- return self.driver.get_page_markers(marker, limit)
-
- def get_by_service(self, service_id):
- """ Returns Endpoint Templates by service """
- return self.driver.get_by_service(service_id)
-
- def get_by_service_get_page(self, service_id, marker, limit):
- """ Get one page of endpoint templates by service"""
- return self.driver.get_by_service_get_page(service_id, marker, limit)
-
- def get_by_service_get_page_markers(self, service_id, marker, limit):
- """ Calculate pagination markers for endpoint templates by service """
- return self.driver.get_by_service_get_page_markers(service_id, marker,
- limit)
-
- def update(self, endpoint_template):
- """ Update Endpoint Template """
- return self.driver.update(endpoint_template['id'], endpoint_template)
-
- def delete(self, endpoint_template_id):
- """ Delete Endpoint Template """
- self.driver.delete(endpoint_template_id)
diff --git a/keystone/managers/grant.py b/keystone/managers/grant.py
deleted file mode 100644
index 41104ce6..00000000
--- a/keystone/managers/grant.py
+++ /dev/null
@@ -1,59 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Role-Grant manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.ROLE
-
- #
- # Role-Grant Methods
- #
- def rolegrant_get_page(self, user_id, tenant_id, marker, limit):
- """ Get one page of role grant list """
- return self.driver.rolegrant_get_page(user_id, tenant_id, marker,
- limit)
-
- def rolegrant_get_page_markers(self, user_id, tenant_id, marker, limit):
- """ Calculate pagination markers for role grants list """
- return self.driver.rolegrant_get_page_markers(user_id, tenant_id,
- marker, limit)
-
- def list_global_roles_for_user(self, user_id):
- return self.driver.list_global_roles_for_user(user_id)
-
- def list_tenant_roles_for_user(self, user_id, tenant_id):
- return self.driver.list_tenant_roles_for_user(user_id, tenant_id)
-
- def rolegrant_list_by_role(self, role_id):
- return self.driver.rolegrant_list_by_role(role_id)
-
- def rolegrant_get_by_ids(self, user_id, role_id, tenant_id):
- return self.driver.rolegrant_get_by_ids(user_id, role_id, tenant_id)
-
- def rolegrant_delete(self, grant_id):
- return self.driver.rolegrant_delete(grant_id)
-
- def list_role_grants(self, role_id, user_id, tenant_id):
- return self.driver.list_role_grants(role_id, user_id, tenant_id)
diff --git a/keystone/managers/role.py b/keystone/managers/role.py
deleted file mode 100644
index 0c3782e5..00000000
--- a/keystone/managers/role.py
+++ /dev/null
@@ -1,74 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Role manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.ROLE
-
- def create(self, role):
- """ Create a new role """
- return self.driver.create(role)
-
- def get(self, role_id):
- """ Returns role by ID """
- return self.driver.get(role_id)
-
- def get_by_name(self, name):
- """ Returns role by name """
- return self.driver.get_by_name(name=name)
-
- def get_all(self):
- """ Returns all roles """
- return self.driver.get_all()
-
- def get_page(self, marker, limit):
- """ Get one page of roles list """
- return self.driver.get_page(marker, limit)
-
- def get_page_markers(self, marker, limit):
- """ Calculate pagination markers for roles list """
- return self.driver.get_page_markers(marker, limit)
-
- def get_by_service(self, service_id):
- """ Returns role by service """
- return self.driver.get_by_service(service_id)
-
- def get_by_service_get_page(self, service_id, marker, limit):
- """ Get one page of roles by service"""
- return self.driver.get_by_service_get_page(service_id, marker, limit)
-
- def get_by_service_get_page_markers(self, service_id, marker, limit):
- """ Calculate pagination markers for roles by service """
- return self.driver.get_by_service_get_page_markers(service_id, marker,
- limit)
-
- # pylint: disable=E1103
- def update(self, role):
- """ Update role """
- return self.driver.update(role['id'], role)
-
- def delete(self, role_id):
- """ Delete role """
- self.driver.delete(role_id)
diff --git a/keystone/managers/service.py b/keystone/managers/service.py
deleted file mode 100644
index c3063be1..00000000
--- a/keystone/managers/service.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Service manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.SERVICE
-
- def create(self, service):
- """ Create a new service """
- return self.driver.create(service)
-
- def get(self, service_id):
- """ Returns service by ID """
- return self.driver.get(service_id)
-
- def get_by_name(self, name):
- """ Returns service by name """
- return self.driver.get_by_name(name=name)
-
- def get_all(self):
- """ Returns all services """
- return self.driver.get_all()
-
- def get_page(self, marker, limit):
- """ Get one page of services list """
- return self.driver.get_page(marker, limit)
-
- def get_page_markers(self, marker, limit):
- """ Calculate pagination markers for services list """
- return self.driver.get_page_markers(marker, limit)
-
- def get_by_name_and_type(self, name, service_type):
- """ Returns service by name and type """
- return self.driver.get_by_name_and_type(name, service_type)
-
- # pylint: disable=E1103
- def update(self, service):
- """ Update service """
- return self.driver.update(service['id'], service)
-
- def delete(self, service_id):
- """ Delete service """
- self.driver.delete(service_id)
diff --git a/keystone/managers/tenant.py b/keystone/managers/tenant.py
deleted file mode 100644
index d69c089f..00000000
--- a/keystone/managers/tenant.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Tenant manager module
-
-TODO: move functionality into here. Ex:
-
- def get_tenant(self, context, tenant_id):
- '''Return info for a tenant if it is valid.'''
- return self.driver.get(tenant_id)
-"""
-
-import logging
-
-import keystone.backends.api as api
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.TENANT
-
- def create(self, tenant):
- return self.driver.create(tenant)
-
- def get(self, tenant_id):
- """ Returns tenant by ID """
- return self.driver.get(tenant_id)
-
- def get_by_name(self, name):
- """ Returns tenant by name """
- return self.driver.get_by_name(name=name)
-
- def get_all(self):
- """ Returns all tenants """
- return self.driver.get_all()
-
- def get_page(self, marker, limit):
- """ Get one page of tenants """
- return self.driver.get_page(marker, limit)
-
- def get_page_markers(self, marker, limit):
- """ Calculate pagination markers for tenant list """
- return self.driver.get_page_markers(marker, limit)
-
- def list_for_user_get_page(self, user_id, marker, limit):
- return self.driver.list_for_user_get_page(user_id, marker, limit)
-
- def list_for_user_get_page_markers(self, user_id, marker, limit):
- return self.driver.list_for_user_get_page_markers(user_id, marker,
- limit)
-
- def update(self, tenant):
- """ Update tenant """
- return self.driver.update(tenant['id'], tenant)
-
- def delete(self, tenant_id):
- self.driver.delete(tenant_id)
-
- def get_all_endpoints(self, tenant_id):
- return self.driver.get_all_endpoints(tenant_id)
diff --git a/keystone/managers/token.py b/keystone/managers/token.py
deleted file mode 100644
index 9f21b35a..00000000
--- a/keystone/managers/token.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Token manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-LOG = logging.getLogger(__name__)
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.TOKEN
-
- def create(self, token):
- return self.driver.create(token)
-
- # pylint: disable=E1103
- def update(self, id, token):
- return self.driver.update(id, token)
-
- def get(self, token_id):
- """ Returns token by ID """
- return self.driver.get(token_id)
-
- def get_all(self):
- """ Returns all tokens """
- return self.driver.get_all()
-
- def find(self, user_id, tenant_id=None):
- """ Finds token by user ID and, optionally, tenant ID
-
- :param user_id: user id as a string
- :param tenant_id: tenant id as a string (optional)
- :returns: Token object or None
- :raises: RuntimeError is user_id is None
- """
- if user_id is None:
- raise RuntimeError("User ID is required when looking up tokens")
- if tenant_id:
- return self.driver.get_for_user_by_tenant(user_id, tenant_id)
- else:
- return self.driver.get_for_user(user_id)
-
- def delete(self, token_id):
- self.driver.delete(token_id)
diff --git a/keystone/managers/user.py b/keystone/managers/user.py
deleted file mode 100644
index 6ed049d0..00000000
--- a/keystone/managers/user.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" User manager module """
-
-import logging
-
-import keystone.backends.api as api
-
-LOG = logging.getLogger(__name__)
-
-
-class Manager(object):
- def __init__(self):
- self.driver = api.USER
-
- def create(self, user):
- """ Create user from dict or model, assign id if not there """
- return self.driver.create(user)
-
- def get(self, user_id):
- """ Returns user by ID """
- return self.driver.get(user_id)
-
- def get_by_name(self, name):
- """ Returns user by name """
- return self.driver.get_by_name(name=name)
-
- def get_by_email(self, email):
- """ Returns user by email """
- return self.driver.get_by_email(email=email)
-
- def get_all(self):
- """ Returns all users """
- return self.driver.get_all()
-
- def users_get_page(self, marker, limit):
- """ Get one page of users list """
- return self.driver.users_get_page(marker, limit)
-
- def users_get_page_markers(self, marker, limit):
- """ Calculate pagination markers for users list """
- return self.driver.users_get_page_markers(marker, limit)
-
- def get_by_tenant(self, user_id, tenant_id):
- """ Get user if associated with tenant, else None """
- return self.driver.get_by_tenant(user_id, tenant_id)
-
- def users_get_by_tenant_get_page(self, tenant_id, role_id, marker, limit):
- """ Get one page of users list for a tenant """
- return self.driver.users_get_by_tenant_get_page(
- tenant_id, role_id, marker, limit)
-
- def users_get_by_tenant_get_page_markers(self, tenant_id, role_id,
- marker, limit):
- """ Calculate pagination markers for users list on a tenant """
- return self.driver.users_get_by_tenant_get_page_markers(
- tenant_id, role_id, marker, limit)
-
- def update(self, user):
- """ Update user """
- return self.driver.update(user['id'], user)
-
- def delete(self, user_id):
- self.driver.delete(user_id)
-
- def check_password(self, user_id, password):
- return self.driver.check_password(user_id, password)
-
- def user_role_add(self, values):
- self.driver.user_role_add(values)
diff --git a/keystone/middleware/__init__.py b/keystone/middleware/__init__.py
index e69de29b..e2e9a993 100644
--- a/keystone/middleware/__init__.py
+++ b/keystone/middleware/__init__.py
@@ -0,0 +1 @@
+from keystone.middleware.core import *
diff --git a/keystone/middleware/auth_basic.py b/keystone/middleware/auth_basic.py
deleted file mode 100644
index 3a5ce416..00000000
--- a/keystone/middleware/auth_basic.py
+++ /dev/null
@@ -1,190 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-BASIC AUTH MIDDLEWARE - STUB
-
-This WSGI component should perform multiple jobs:
-
-* validate incoming basic claims
-* perform all basic auth interactions with clients
-* collect and forward identity information from the authentication process
- such as user name, groups, etc...
-
-This is an Auth component as per: http://wiki.openstack.org/openstack-authn
-
-"""
-
-import eventlet
-from eventlet import wsgi
-import os
-import logging
-from paste.deploy import loadapp
-import urlparse
-from webob.exc import Request, Response
-from webob.exc import HTTPUnauthorized
-
-from keystone.common.bufferedhttp import http_connect_raw as http_connect
-
-PROTOCOL_NAME = "Basic Authentication"
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-def _decorate_request_headers(header, value, proxy_headers, env):
- proxy_headers[header] = value
- env["HTTP_%s" % header] = value
-
-
-class AuthProtocol(object):
- """Auth Middleware that handles authenticating client calls"""
-
- def __init__(self, app, conf):
- logger.info("Starting the %s component", PROTOCOL_NAME)
-
- self.conf = conf
- self.app = app
- #if app is set, then we are in a WSGI pipeline and requests get passed
- # on to app. If it is not set, this component should forward requests
-
- # where to find the OpenStack service (if not in local WSGI chain)
- # these settings are only used if this component is acting as a proxy
- # and the OpenSTack service is running remotely
- self.service_protocol = conf.get('service_protocol', 'https')
- self.service_host = conf.get('service_host')
- self.service_port = int(conf.get('service_port'))
- self.service_url = '%s://%s:%s' % (self.service_protocol,
- self.service_host,
- self.service_port)
- # used to verify this component with the OpenStack service or PAPIAuth
- self.service_pass = conf.get('service_pass')
-
- # delay_auth_decision means we still allow unauthenticated requests
- # through and we let the downstream service make the final decision
- self.delay_auth_decision = int(conf.get('delay_auth_decision', 0))
-
- def __call__(self, env, start_response):
- def custom_start_response(status, headers):
- if self.delay_auth_decision:
- headers.append(('WWW-Authenticate',
- "Basic realm='Use guest/guest'"))
- return start_response(status, headers)
-
- #Prep headers to proxy request to remote service
- proxy_headers = env.copy()
- user = ''
-
- #Look for authentication
- if 'HTTP_AUTHORIZATION' not in env:
- #No credentials were provided
- if self.delay_auth_decision:
- _decorate_request_headers("X_IDENTITY_STATUS", "Invalid",
- proxy_headers, env)
- else:
- # If the user isn't authenticated, we reject the request and
- # return 401 indicating we need Basic Auth credentials.
- ret = HTTPUnauthorized("Authentication required",
- [('WWW-Authenticate',
- 'Basic realm="Use guest/guest"')])
- return ret(env, start_response)
- else:
- # Claims were provided - validate them
- import base64
- auth_header = env['HTTP_AUTHORIZATION']
- _auth_type, encoded_creds = auth_header.split(None, 1)
- user, password = base64.b64decode(encoded_creds).split(':', 1)
- if not self.validateCreds(user, password):
- #Claims were rejected
- if not self.delay_auth_decision:
- # Reject request (or ask for valid claims)
- ret = HTTPUnauthorized("Authentication required",
- [('WWW-Authenticate',
- 'Basic realm="Use guest/guest"')])
- return ret(env, start_response)
- else:
- # Claims are valid, forward request
- _decorate_request_headers("X_IDENTITY_STATUS", "Invalid",
- proxy_headers, env)
-
- # TODO(Ziad): add additional details we may need,
- # like tenant and group info
- _decorate_request_headers('X_AUTHORIZATION', "Proxy %s" % user,
- proxy_headers, env)
- _decorate_request_headers("X_IDENTITY_STATUS", "Confirmed",
- proxy_headers, env)
- _decorate_request_headers('X_TENANT', 'blank',
- proxy_headers, env)
- #Auth processed, headers added now decide how to pass on the call
- if self.app:
- # Pass to downstream WSGI component
- env['HTTP_AUTHORIZATION'] = "Basic %s" % self.service_pass
- return self.app(env, custom_start_response)
-
- proxy_headers['AUTHORIZATION'] = "Basic %s" % self.service_pass
- # We are forwarding to a remote service (no downstream WSGI app)
- req = Request(proxy_headers)
- parsed = urlparse(req.url)
- conn = http_connect(self.service_host, self.service_port, \
- req.method, parsed.path, \
- proxy_headers, \
- ssl=(self.service_protocol == 'https'))
- resp = conn.getresponse()
- data = resp.read()
- #TODO(ziad): use a more sophisticated proxy
- # we are rewriting the headers now
- return Response(status=resp.status, body=data)(env, start_response)
-
- def validateCreds(self, username, password):
- #stub for password validation.
- # import ConfigParser
- # import hashlib
- #usersConfig = ConfigParser.ConfigParser()
- #usersConfig.readfp(open('/etc/openstack/users.ini'))
- #password = hashlib.sha1(password).hexdigest()
- #for un, pwd in usersConfig.items('users'):
- #TODO(Ziad): add intelligent credential validation (instead of hard
- # coded)
- if username == 'guest' and password == 'guest':
- return True
- return False
-
-
-def filter_factory(global_conf, ** local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- return AuthProtocol(app, conf)
- return auth_filter
-
-
-def app_factory(global_conf, ** local_conf):
- conf = global_conf.copy()
- conf.update(local_conf)
- return AuthProtocol(None, conf)
-
-if __name__ == "__main__":
- app = loadapp("config:" + \
- os.path.join(os.path.abspath(os.path.dirname(__file__)),
- os.pardir,
- os.pardir,
- "examples/paste/auth_basic.ini"),
- global_conf={"log_name": "auth_basic.log"})
- wsgi.server(eventlet.listen(('', 8090)), app)
diff --git a/keystone/middleware/auth_openid.py b/keystone/middleware/auth_openid.py
deleted file mode 100644
index 3debe2a4..00000000
--- a/keystone/middleware/auth_openid.py
+++ /dev/null
@@ -1,125 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-"""
-OPENID AUTH MIDDLEWARE - STUB
-
-This WSGI component should perform multiple jobs:
-- validate incoming openid claims
-- perform all openid interactions with clients
-- collect and forward identity information from the openid authentication
- such as user name, groups, etc...
-
-This is an Auth component as per: http://wiki.openstack.org/openstack-authn
-"""
-
-import logging
-import eventlet
-from eventlet import wsgi
-import os
-from paste.deploy import loadapp
-import urlparse
-from webob.exc import Request, Response
-
-from keystone.common.bufferedhttp import http_connect_raw as http_connect
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-PROTOCOL_NAME = "OpenID Authentication"
-
-
-class AuthProtocol(object):
- """Auth Middleware that handles authenticating client calls"""
-
- def __init__(self, app, conf):
- logger.info("Starting the %s component", PROTOCOL_NAME)
-
- self.conf = conf
- self.app = app
- #if app is set, then we are in a WSGI pipeline and requests get passed
- # on to app. If it is not set, this component should forward requests
-
- # where to find the OpenStack service (if not in local WSGI chain)
- # these settings are only used if this component is acting as a proxy
- # and the OpenSTack service is running remotely
- self.service_protocol = conf.get('service_protocol', 'http')
- self.service_host = conf.get('service_host', '127.0.0.1')
- self.service_port = int(conf.get('service_port', 8090))
- self.service_url = '%s://%s:%s' % (self.service_protocol,
- self.service_host,
- self.service_port)
- # used to verify this component with the OpenStack service or PAPIAuth
- self.service_pass = conf.get('service_pass', 'dTpw')
-
- # delay_auth_decision means we still allow unauthenticated requests
- # through and we let the downstream service make the final decision
- self.delay_auth_decision = int(conf.get('delay_auth_decision', 0))
-
- def __call__(self, env, start_response):
- def custom_start_response(status, headers):
- if self.delay_auth_decision:
- headers.append(('WWW-Authenticate', "Basic realm='API Realm'"))
- return start_response(status, headers)
-
- #TODO(Rasib): PERFORM OPENID AUTH
-
- #Auth processed, headers added now decide how to pass on the call
- if self.app:
- # Pass to downstream WSGI component
- env['HTTP_AUTHORIZATION'] = "Basic %s" % self.service_pass
- return self.app(env, custom_start_response)
-
- proxy_headers = []
- proxy_headers['AUTHORIZATION'] = "Basic %s" % self.service_pass
- # We are forwarding to a remote service (no downstream WSGI app)
- req = Request(proxy_headers)
- parsed = urlparse(req.url)
- conn = http_connect(self.service_host, self.service_port, \
- req.method, parsed.path, \
- proxy_headers, \
- ssl=(self.service_protocol == 'https'))
- resp = conn.getresponse()
- data = resp.read()
- #TODO(ziad): use a more sophisticated proxy
- # we are rewriting the headers now
- return Response(status=resp.status, body=data)(env, start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- return AuthProtocol(app, conf)
- return auth_filter
-
-
-def app_factory(global_conf, **local_conf):
- conf = global_conf.copy()
- conf.update(local_conf)
- return AuthProtocol(None, conf)
-
-if __name__ == "__main__":
- app = loadapp("config:" + \
- os.path.join(os.path.abspath(os.path.dirname(__file__)),
- os.pardir,
- os.pardir,
- "examples/paste/auth_openid.ini"),
- global_conf={"log_name": "auth_openid.log"})
- wsgi.server(eventlet.listen(('', 8090)), app)
diff --git a/keystone/middleware/auth_token.py b/keystone/middleware/auth_token.py
index 8cde88a6..4a0d501a 100644..100755
--- a/keystone/middleware/auth_token.py
+++ b/keystone/middleware/auth_token.py
@@ -1,6 +1,5 @@
-#!/usr/bin/env python
# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
+
# Copyright (c) 2010-2011 OpenStack, LLC.
#
# Licensed under the Apache License, Version 2.0 (the "License");
@@ -19,17 +18,18 @@
"""
TOKEN-BASED AUTH MIDDLEWARE
-This WSGI component:
+This WSGI component performs multiple jobs:
-* Verifies that incoming client requests have valid tokens by validating
+* it verifies that incoming client requests have valid tokens by verifying
tokens with the auth service.
-* Rejects unauthenticated requests UNLESS it is in 'delay_auth_decision'
+* it will reject unauthenticated requests UNLESS it is in 'delay_auth_decision'
mode, which means the final decision is delegated to the downstream WSGI
component (usually the OpenStack service)
-* Collects and forwards identity information based on a valid token
- such as user name, tenant, etc
+* it will collect and forward identity information from a valid token
+ such as user name etc...
+
+Refer to: http://wiki.openstack.org/openstack-authn
-Refer to: http://keystone.openstack.org/middleware_architecture.html
HEADERS
-------
@@ -41,11 +41,11 @@ Coming in from initial call from client or customer
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
HTTP_X_AUTH_TOKEN
- The client token being passed in.
+ the client token being passed in
HTTP_X_STORAGE_TOKEN
- The client token being passed in (legacy Rackspace use) to support
- swift/cloud files
+ the client token being passed in (legacy Rackspace use) to support
+ cloud files
Used for communication between components
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
@@ -60,93 +60,35 @@ What we add to the request for use by the OpenStack service
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
HTTP_X_AUTHORIZATION
- The client identity being passed in
-
-HTTP_X_IDENTITY_STATUS
- 'Confirmed' or 'Invalid'
- The underlying service will only see a value of 'Invalid' if the Middleware
- is configured to run in 'delay_auth_decision' mode
-
-HTTP_X_TENANT
- *Deprecated* in favor of HTTP_X_TENANT_ID and HTTP_X_TENANT_NAME
- Keystone-assigned unique identifier, deprecated
-
-HTTP_X_TENANT_ID
- Identity service managed unique identifier, string
-
-HTTP_X_TENANT_NAME
- Unique tenant identifier, string
-
-HTTP_X_USER
- *Deprecated* in favor of HTTP_X_USER_ID and HTTP_X_USER_NAME
- Unique user name, string
-
-HTTP_X_USER_ID
- Identity-service managed unique identifier, string
-
-HTTP_X_USER_NAME
- Unique user identifier, string
-
-HTTP_X_ROLE
- *Deprecated* in favor of HTTP_X_ROLES
- This is being renamed, and the new header contains the same data.
-
-HTTP_X_ROLES
- Comma delimited list of case-sensitive Roles
+ the client identity being passed in
"""
-
-from datetime import datetime
-from dateutil import parser
-import errno
-import eventlet
-from eventlet import wsgi
import httplib
import json
-# memcache is imported in __init__ if memcache caching is configured
-import logging
import os
-from paste.deploy import loadapp
-import time
-import urllib
+
+import eventlet
+from eventlet import wsgi
+from paste import deploy
from urlparse import urlparse
+import webob
+import webob.exc
from webob.exc import HTTPUnauthorized
-from webob.exc import Request, Response
from keystone.common.bufferedhttp import http_connect_raw as http_connect
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-PROTOCOL_NAME = "Token Authentication"
-# The time format of the 'expires' property of a token
-EXPIRE_TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.%f"
-MAX_CACHE_TIME = 86400
-
-
-class ValidationFailed(Exception):
- pass
-
-
-class TokenExpired(Exception):
- pass
-
-
-class KeystoneUnreachable(Exception):
- pass
+PROTOCOL_NAME = 'Token Authentication'
class AuthProtocol(object):
"""Auth Middleware that handles authenticating client calls"""
- # pylint: disable=W0613
def _init_protocol_common(self, app, conf):
- """ Common initialization code
-
- When we eventually superclass this, this will be the superclass
- initialization code that applies to all protocols
- """
- logger.info("Starting the %s component", PROTOCOL_NAME)
+ """ Common initialization code"""
+ print 'Starting the %s component' % PROTOCOL_NAME
+ self.conf = conf
+ self.app = app
#if app is set, then we are in a WSGI pipeline and requests get passed
# on to app. If it is not set, this component should forward requests
@@ -155,18 +97,10 @@ class AuthProtocol(object):
# and the OpenSTack service is running remotely
self.service_protocol = conf.get('service_protocol', 'https')
self.service_host = conf.get('service_host')
- service_port = conf.get('service_port')
- service_ids = conf.get('service_ids')
- self.service_id_querystring = ''
- if service_ids:
- self.service_id_querystring = '?HP-IDM-serviceId=%s' % \
- (urllib.quote(service_ids))
- if service_port:
- self.service_port = int(service_port)
+ self.service_port = int(conf.get('service_port'))
self.service_url = '%s://%s:%s' % (self.service_protocol,
self.service_host,
self.service_port)
- self.service_timeout = conf.get('service_timeout', 30)
# used to verify this component with the OpenStack service or PAPIAuth
self.service_pass = conf.get('service_pass')
@@ -181,94 +115,27 @@ class AuthProtocol(object):
self.auth_host = conf.get('auth_host')
self.auth_port = int(conf.get('auth_port'))
self.auth_protocol = conf.get('auth_protocol', 'https')
- self.auth_timeout = float(conf.get('auth_timeout', 30))
# where to tell clients to find the auth service (default to url
# constructed based on endpoint we have for the service to use)
self.auth_location = conf.get('auth_uri',
- "%s://%s:%s" % (self.auth_protocol,
+ '%s://%s:%s' % (self.auth_protocol,
self.auth_host,
self.auth_port))
- logger.debug("Authentication Service:%s", self.auth_location)
# Credentials used to verify this component with the Auth service since
# validating tokens is a privileged call
self.admin_token = conf.get('admin_token')
- self.admin_user = conf.get('admin_user', None)
- self.admin_password = conf.get('admin_password', None)
- # Certificate file and key file used to authenticate with Keystone
- # server
- self.cert_file = conf.get('certfile', None)
- self.key_file = conf.get('keyfile', None)
- # Caching
- self.cache = conf.get('cache', None)
- self.memcache_hosts = conf.get('memcache_hosts', None)
- if self.memcache_hosts:
- if self.cache is None:
- self.cache = "keystone.cache"
- self.tested_for_osksvalidate = False
- self.last_test_for_osksvalidate = None
- self.osksvalidate = self._supports_osksvalidate()
def __init__(self, app, conf):
""" Common initialization code """
+
#TODO(ziad): maybe we refactor this into a superclass
- # Defining instance variables here for improving pylint score
- # NOTE(salvatore-orlando): the following vars are assigned values
- # either in init_protocol or init_protocol_common. We should not
- # worry about them being initialized to None
- self.conf = conf
- self.app = app
- self.admin_password = None
- self.admin_token = None
- self.admin_user = None
- self.auth_api_version = None
- self.auth_host = None
- self.auth_location = None
- self.auth_port = None
- self.auth_protocol = None
- self.auth_timeout = None
- self.cert_file = None
- self.key_file = None
- self.delay_auth_decision = None
- self.service_pass = None
- self.service_host = None
- self.service_port = None
- self.service_protocol = None
- self.service_timeout = None
- self.service_url = None
- self.service_id_querystring = None
- self.osksvalidate = None
- self.tested_for_osksvalidate = None
- self.last_test_for_osksvalidate = None
- self.cache = None
- self.memcache_hosts = None
self._init_protocol_common(app, conf) # Applies to all protocols
self._init_protocol(conf) # Specific to this protocol
def __call__(self, env, start_response):
""" Handle incoming request. Authenticate. And send downstream. """
- logger.debug("entering AuthProtocol.__call__")
- # Initialize caching client
- if self.memcache_hosts:
- # This will only be used if the configuration calls for memcache
- import memcache
-
- if env.get(self.cache, None) is None:
- memcache_client = memcache.Client([self.memcache_hosts])
- env[self.cache] = memcache_client
-
- # Check if we're set up to use OS-KSVALIDATE periodically if not on
- if self.tested_for_osksvalidate != True:
- if self.last_test_for_osksvalidate is None or \
- (time.time() - self.last_test_for_osksvalidate) > 60:
- # Try test again every 60 seconds if failed
- # this also handles if middleware was started before
- # the keystone server
- try:
- self.osksvalidate = self._supports_osksvalidate()
- except (httplib.HTTPException, StandardError):
- pass
#Prep headers to forward request to local or remote downstream service
proxy_headers = env.copy()
@@ -278,410 +145,230 @@ class AuthProtocol(object):
del proxy_headers[header]
#Look for authentication claims
- token = self._get_claims(env)
- if not token:
- logger.debug("No claims provided")
+ claims = self._get_claims(env)
+ if not claims:
+ #No claim(s) provided
if self.delay_auth_decision:
#Configured to allow downstream service to make final decision.
#So mark status as Invalid and forward the request downstream
- logger.debug("delay_auth_decision is %s, so sending request "
- "down the pipeline" % self.delay_auth_decision)
- self._decorate_request("X_IDENTITY_STATUS",
- "Invalid", env, proxy_headers)
+ self._decorate_request('X_IDENTITY_STATUS',
+ 'Invalid', env, proxy_headers)
else:
#Respond to client as appropriate for this auth protocol
return self._reject_request(env, start_response)
else:
# this request is presenting claims. Let's validate them
- try:
- claims = self._verify_claims(env, token)
- except (ValidationFailed, TokenExpired):
+ valid = self._validate_claims(claims)
+ if not valid:
# Keystone rejected claim
if self.delay_auth_decision:
# Downstream service will receive call still and decide
- self._decorate_request("X_IDENTITY_STATUS",
- "Invalid", env, proxy_headers)
+ self._decorate_request('X_IDENTITY_STATUS',
+ 'Invalid', env, proxy_headers)
else:
#Respond to client as appropriate for this auth protocol
return self._reject_claims(env, start_response)
else:
- self._decorate_request("X_IDENTITY_STATUS",
- "Confirmed", env, proxy_headers)
+ self._decorate_request('X_IDENTITY_STATUS',
+ 'Confirmed', env, proxy_headers)
+
+ #Collect information about valid claims
+ if valid:
+ claims = self._expound_claims(claims)
# Store authentication data
if claims:
- self._decorate_request('X_AUTHORIZATION', "Proxy %s" %
- claims['user']['name'], env, proxy_headers)
-
- self._decorate_request('X_TENANT_ID',
- claims['tenant']['id'], env, proxy_headers)
- self._decorate_request('X_TENANT_NAME',
- claims['tenant']['name'], env, proxy_headers)
-
- self._decorate_request('X_USER_ID',
- claims['user']['id'], env, proxy_headers)
- self._decorate_request('X_USER_NAME',
- claims['user']['name'], env, proxy_headers)
-
- roles = ','.join(claims['roles'])
- self._decorate_request('X_ROLES',
- roles, env, proxy_headers)
+ self._decorate_request('X_AUTHORIZATION', 'Proxy %s' %
+ claims['user'], env, proxy_headers)
- # Deprecated in favor of X_TENANT_ID and _NAME
+ # For legacy compatibility before we had ID and Name
self._decorate_request('X_TENANT',
- claims['tenant']['id'], env, proxy_headers)
+ claims['tenant'], env, proxy_headers)
- # Deprecated in favor of X_USER_ID and _NAME
- # TODO(zns): documentation says this should be the username
- # the user logged in with. We've been returning the id...
- self._decorate_request('X_USER',
- claims['user']['id'], env, proxy_headers)
+ # Services should use these
+ self._decorate_request('X_TENANT_NAME',
+ claims.get('tenant_name', claims['tenant']),
+ env, proxy_headers)
+ self._decorate_request('X_TENANT_ID',
+ claims['tenant'], env, proxy_headers)
- # Deprecated in favor of X_ROLES
- self._decorate_request('X_ROLE',
- roles, env, proxy_headers)
+ self._decorate_request('X_USER',
+ claims['user'], env, proxy_headers)
+ if 'roles' in claims and len(claims['roles']) > 0:
+ if claims['roles'] != None:
+ roles = ''
+ for role in claims['roles']:
+ if len(roles) > 0:
+ roles += ','
+ roles += role
+ self._decorate_request('X_ROLE',
+ roles, env, proxy_headers)
+
+ # NOTE(todd): unused
+ self.expanded = True
#Send request downstream
return self._forward_request(env, start_response, proxy_headers)
- @staticmethod
- def _convert_date(date):
- """ Convert datetime to unix timestamp for caching """
- return time.mktime(parser.parse(date).utctimetuple())
-
- # pylint: disable=W0613
- @staticmethod
- def _protect_claims(token, claims):
- """ encrypt or mac claims if necessary """
- return claims
+ # NOTE(todd): unused
+ def get_admin_auth_token(self, username, password):
+ """
+ This function gets an admin auth token to be used by this service to
+ validate a user's token. Validate_token is a priviledged call so
+ it needs to be authenticated by a service that is calling it
+ """
+ headers = {'Content-type': 'application/json',
+ 'Accept': 'application/json'}
+ params = {'passwordCredentials': {'username': username,
+ 'password': password,
+ 'tenantId': '1'}}
+ conn = httplib.HTTPConnection('%s:%s' \
+ % (self.auth_host, self.auth_port))
+ conn.request('POST', '/v2.0/tokens', json.dumps(params), \
+ headers=headers)
+ response = conn.getresponse()
+ data = response.read()
+ return data
- # pylint: disable=W0613
- @staticmethod
- def _unprotect_claims(token, pclaims):
- """ decrypt or demac claims if necessary """
- return pclaims
-
- def _cache_put(self, env, token, claims, valid):
- """ Put a claim into the cache """
- cache = self._cache(env)
- if cache and claims:
- key = 'tokens/%s' % (token)
- if "timeout" in cache.set.func_code.co_varnames:
- # swift cache
- expires = self._convert_date(claims['expires'])
- claims = self._protect_claims(token, claims)
- cache.set(key, (claims, expires, valid),
- timeout=expires - time.time())
- else:
- # normal memcache client
- expires = self._convert_date(claims['expires'])
- timeout = expires - time.time()
- if timeout > MAX_CACHE_TIME or not valid:
- # Limit cache to one day (and cache bad tokens for a day)
- timeout = MAX_CACHE_TIME
- claims = self._protect_claims(token, claims)
- cache.set(key, (claims, expires, valid), time=timeout)
-
- def _cache_get(self, env, token):
- """ Return claim and relevant information (expiration and validity)
- from cache """
- cache = self._cache(env)
- if cache:
- key = 'tokens/%s' % (token)
- cached_claims = cache.get(key)
- if cached_claims:
- claims, expires, valid = cached_claims
- if valid:
- if "timeout" in cache.set.func_code.co_varnames:
- if expires > time.time():
- claims = self._unprotect_claims(token, claims)
- else:
- if expires > time.time():
- claims = self._unprotect_claims(token, claims)
- return (claims, expires, valid)
- return None
-
- def _cache(self, env):
- """ Return a cache to use for token caching, or none """
- if self.cache is not None:
- return env.get(self.cache, None)
- return None
-
- @staticmethod
- def _get_claims(env):
+ def _get_claims(self, env):
"""Get claims from request"""
- logger.debug("Looking for authentication claims in _get_claims")
claims = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
return claims
def _reject_request(self, env, start_response):
"""Redirect client to auth server"""
- logger.debug("Rejecting request - authentication required")
- return HTTPUnauthorized("Authentication required",
- [("WWW-Authenticate",
+ return webob.exc.HTTPUnauthorized('Authentication required',
+ [('WWW-Authenticate',
"Keystone uri='%s'" % self.auth_location)])(env,
start_response)
- @staticmethod
- def _reject_claims(env, start_response):
+ def _reject_claims(self, env, start_response):
"""Client sent bad claims"""
- logger.debug("Rejecting request - bad claim or token")
- return HTTPUnauthorized()(env,
+ return webob.exc.HTTPUnauthorized()(env,
start_response)
- def _build_token_uri(self):
- return '/v2.0/tokens/%s' % self.service_id_querystring
-
- def _get_admin_auth_token(self, username, password):
- """
- This function gets an admin auth token to be used by this service to
- validate a user's token. Validate_token is a priviledged call so
- it needs to be authenticated by a service that is calling it
- """
- headers = {
- "Content-type": "application/json",
- "Accept": "application/json"}
- params = {
- "auth": {
- "passwordCredentials": {
- "username": username,
- "password": password,
- }
- }
- }
- if self.auth_protocol == "http":
- conn = httplib.HTTPConnection(self.auth_host, self.auth_port)
- else:
- conn = httplib.HTTPSConnection(self.auth_host, self.auth_port,
- cert_file=self.cert_file)
- conn.request("POST", self._build_token_uri(), json.dumps(params),
- headers=headers)
- response = conn.getresponse()
- data = response.read()
- return data
-
- def _verify_claims(self, env, claims, retry=True):
- """Verify claims and extract identity information, if applicable."""
-
- cached_claims = self._cache_get(env, claims)
- if cached_claims:
- logger.debug("Found cached claims")
- claims, expires, valid = cached_claims
- if not valid:
- logger.debug("Claims not valid (according to cache)")
- raise ValidationFailed()
- if expires <= time.time():
- logger.debug("Claims (token) expired (according to cache)")
- raise TokenExpired()
- return claims
+ def _validate_claims(self, claims):
+ """Validate claims, and provide identity information isf applicable """
# Step 1: We need to auth with the keystone service, so get an
# admin token
- if not self.admin_token:
- auth = self._get_admin_auth_token(self.admin_user,
- self.admin_password)
- self.admin_token = json.loads(auth)["access"]["token"]["id"]
+ #TODO(ziad): Need to properly implement this, where to store creds
+ # for now using token from ini
+ #auth = self.get_admin_auth_token('admin', 'secrete', '1')
+ #admin_token = json.loads(auth)['auth']['token']['id']
# Step 2: validate the user's token with the auth service
# since this is a priviledged op,m we need to auth ourselves
# by using an admin token
- headers = {"Content-type": "application/json",
- "Accept": "application/json",
- "X-Auth-Token": self.admin_token}
- if self.osksvalidate:
- headers['X-Subject-Token'] = claims
- path = '/v2.0/OS-KSVALIDATE/token/validate/%s' % \
- self.service_id_querystring
- logger.debug("Connecting to %s://%s:%s to check claims using the"
- "OS-KSVALIDATE extension" % (self.auth_protocol,
- self.auth_host, self.auth_port))
- else:
- path = '/v2.0/tokens/%s%s' % (claims, self.service_id_querystring)
- logger.debug("Connecting to %s://%s:%s to check claims" % (
- self.auth_protocol, self.auth_host, self.auth_port))
+ headers = {'Content-type': 'application/json',
+ 'Accept': 'application/json',
+ 'X-Auth-Token': self.admin_token}
+ ##TODO(ziad):we need to figure out how to auth to keystone
+ #since validate_token is a priviledged call
+ #Khaled's version uses creds to get a token
+ # 'X-Auth-Token': admin_token}
+ # we're using a test token from the ini file for now
+ conn = http_connect(self.auth_host, self.auth_port, 'GET',
+ '/v2.0/tokens/%s' % claims, headers=headers)
+ resp = conn.getresponse()
+ # data = resp.read()
+ conn.close()
- try:
- conn = http_connect(self.auth_host, self.auth_port, 'GET',
- path,
- headers=headers,
- ssl=(self.auth_protocol == 'https'),
- key_file=self.key_file,
- cert_file=self.cert_file,
- timeout=self.auth_timeout)
- resp = conn.getresponse()
- data = resp.read()
- except EnvironmentError as exc:
- if exc.errno == errno.ECONNREFUSED:
- logger.error("Keystone server not responding on %s://%s:%s "
- "to check claims" % (self.auth_protocol,
- self.auth_host,
- self.auth_port))
- raise KeystoneUnreachable("Unable to connect to authentication"
- " server")
- else:
- logger.exception(exc)
- raise
+ if not str(resp.status).startswith('20'):
+ # Keystone rejected claim
+ return False
+ else:
+ #TODO(Ziad): there is an optimization we can do here. We have just
+ #received data from Keystone that we can use instead of making
+ #another call in _expound_claims
+ return True
+
+ def _expound_claims(self, claims):
+ # Valid token. Get user data and put it in to the call
+ # so the downstream service can use it
+ headers = {'Content-type': 'application/json',
+ 'Accept': 'application/json',
+ 'X-Auth-Token': self.admin_token}
+ ##TODO(ziad):we need to figure out how to auth to keystone
+ #since validate_token is a priviledged call
+ #Khaled's version uses creds to get a token
+ # 'X-Auth-Token': admin_token}
+ # we're using a test token from the ini file for now
+ conn = http_connect(self.auth_host, self.auth_port, 'GET',
+ '/v2.0/tokens/%s' % claims, headers=headers)
+ resp = conn.getresponse()
+ data = resp.read()
+ conn.close()
- logger.debug("Response received: %s" % resp.status)
if not str(resp.status).startswith('20'):
- # Cache it if there is a cache available
- if self.cache:
- logger.debug("Caching that results were invalid")
- self._cache_put(env, claims,
- claims={'expires':
- datetime.strftime(time.time(),
- EXPIRE_TIME_FORMAT)},
- valid=False)
- if retry:
- self.admin_token = None
- return self._verify_claims(env, claims, False)
- else:
- # Keystone rejected claim
- logger.debug("Failing the validation")
- raise ValidationFailed()
+ raise LookupError('Unable to locate claims: %s' % resp.status)
token_info = json.loads(data)
+ roles = []
+ role_refs = token_info['access']['user']['roles']
+ if role_refs != None:
+ for role_ref in role_refs:
+ # Nova looks for the non case-sensitive role 'Admin'
+ # to determine admin-ness
+ roles.append(role_ref['name'])
- roles = [role['name'] for role in token_info[
- "access"]["user"]["roles"]]
-
- # in diablo, there were two ways to get tenant data
- tenant = token_info['access']['token'].get('tenant')
- if tenant:
- # post diablo
- tenant_id = tenant['id']
- tenant_name = tenant['name']
- else:
- # diablo only
- tenant_id = token_info['access']['user'].get('tenantId')
+ try:
+ tenant = token_info['access']['token']['tenant']['id']
+ tenant_name = token_info['access']['token']['tenant']['name']
+ except:
+ tenant = None
+ tenant_name = None
+ if not tenant:
+ tenant = token_info['access']['user'].get('tenantId')
tenant_name = token_info['access']['user'].get('tenantName')
- logger.debug("Tenant identified: id=%s, name=%s" % (tenant_id,
- tenant_name))
-
- verified_claims = {
- 'user': {
- 'id': token_info['access']['user']['id'],
- 'name': token_info['access']['user']['name'],
- },
- 'tenant': {
- 'id': tenant_id,
- 'name': tenant_name
- },
- 'roles': roles,
- 'expires': token_info['access']['token']['expires']}
- logger.debug("User identified: id=%s, name=%s" % (
- token_info['access']['user']['id'],
- token_info['access']['user']['name']))
-
- expires = self._convert_date(verified_claims['expires'])
- if expires <= time.time():
- logger.debug("Claims (token) expired: %s" % str(expires))
- # Cache it if there is a cache available (we also cached bad
- # claims)
- if self.cache:
- logger.debug("Caching expired claim (token)")
- self._cache_put(env, claims, verified_claims, valid=False)
- raise TokenExpired()
-
- # Cache it if there is a cache available
- if self.cache:
- logger.debug("Caching validated claim")
- self._cache_put(env, claims, verified_claims, valid=True)
- logger.debug("Returning successful validation")
+ verified_claims = {'user': token_info['access']['user']['username'],
+ 'tenant': tenant,
+ 'roles': roles}
+ if tenant_name:
+ verified_claims['tenantName'] = tenant_name
return verified_claims
- @staticmethod
- def _decorate_request(index, value, env, proxy_headers):
+ def _decorate_request(self, index, value, env, proxy_headers):
"""Add headers to request"""
- logger.debug("Decorating request with HTTP_%s=%s" % (index, value))
proxy_headers[index] = value
- env["HTTP_%s" % index] = value
+ env['HTTP_%s' % index] = value
def _forward_request(self, env, start_response, proxy_headers):
"""Token/Auth processed & claims added to headers"""
self._decorate_request('AUTHORIZATION',
- "Basic %s" % self.service_pass, env, proxy_headers)
+ 'Basic %s' % self.service_pass, env, proxy_headers)
#now decide how to pass on the call
if self.app:
# Pass to downstream WSGI component
- logger.debug("Sending request to next app in WSGI pipeline")
return self.app(env, start_response)
#.custom_start_response)
else:
# We are forwarding to a remote service (no downstream WSGI app)
- logger.debug("Sending request to %s" % self.service_url)
- req = Request(proxy_headers)
+ req = webob.Request(proxy_headers)
parsed = urlparse(req.url)
- # pylint: disable=E1101
conn = http_connect(self.service_host,
self.service_port,
req.method,
parsed.path,
proxy_headers,
- ssl=(self.service_protocol == 'https'),
- timeout=self.service_timeout)
+ ssl=(self.service_protocol == 'https'))
resp = conn.getresponse()
data = resp.read()
- logger.debug("Response was %s" % resp.status)
#TODO(ziad): use a more sophisticated proxy
# we are rewriting the headers now
- if resp.status in (401, 305):
+ if resp.status == 401 or resp.status == 305:
# Add our own headers to the list
- headers = [("WWW_AUTHENTICATE",
+ headers = [('WWW_AUTHENTICATE',
"Keystone uri='%s'" % self.auth_location)]
- return Response(status=resp.status, body=data,
- headerlist=headers)(env,
- start_response)
+ return webob.Response(status=resp.status,
+ body=data,
+ headerlist=headers)(env, start_response)
else:
- return Response(status=resp.status, body=data)(env,
- start_response)
-
- def _supports_osksvalidate(self):
- """Check if target Keystone server supports OS-KSVALIDATE."""
- if self.tested_for_osksvalidate:
- return self.osksvalidate
-
- headers = {"Accept": "application/json"}
- logger.debug("Connecting to %s://%s:%s to check extensions" % (
- self.auth_protocol, self.auth_host, self.auth_port))
- try:
- self.last_test_for_osksvalidate = time.time()
- conn = http_connect(self.auth_host, self.auth_port, 'GET',
- '/v2.0/extensions/',
- headers=headers,
- ssl=(self.auth_protocol == 'https'),
- key_file=self.key_file,
- cert_file=self.cert_file,
- timeout=self.auth_timeout)
- resp = conn.getresponse()
- data = resp.read()
-
- logger.debug("Response received: %s" % resp.status)
- if not str(resp.status).startswith('20'):
- logger.debug("Failed to detect extensions. "
- "Falling back to core API")
- return False
- except EnvironmentError as exc:
- if exc.errno == errno.ECONNREFUSED:
- logger.warning("Keystone server not responding. Extension "
- "detection will be retried later.")
- else:
- logger.exception("Unexpected error trying to detect "
- "extensions.")
- logger.debug("Falling back to core API behavior (using tokens in "
- "URL)")
- return False
- except httplib.HTTPException as exc:
- logger.exception("Error trying to detect extensions.")
- logger.debug("Falling back to core API behavior (using tokens in "
- "URL)")
- return False
-
- self.tested_for_osksvalidate = True
- return "OS-KSVALIDATE" in data
+ return webob.Response(status=resp.status,
+ body=data)(env, start_response)
def filter_factory(global_conf, **local_conf):
@@ -689,8 +376,8 @@ def filter_factory(global_conf, **local_conf):
conf = global_conf.copy()
conf.update(local_conf)
- def auth_filter(filteredapp):
- return AuthProtocol(filteredapp, conf)
+ def auth_filter(app):
+ return AuthProtocol(app, conf)
return auth_filter
@@ -699,20 +386,11 @@ def app_factory(global_conf, **local_conf):
conf.update(local_conf)
return AuthProtocol(None, conf)
-
-def main():
- """Called when the middleware is started up separately (as in a remote
- proxy configuration)
- """
- config_file = os.path.join(os.path.abspath(os.path.dirname(__file__)),
+if __name__ == '__main__':
+ app = deploy.loadapp('config:' + \
+ os.path.join(os.path.abspath(os.path.dirname(__file__)),
os.pardir,
os.pardir,
- "examples/paste/auth_token.ini")
- logger.debug("Initializing with config file: %s" % config_file)
- wsgiapp = loadapp("config:%s" % config_file,
- global_conf={"log_name": "auth_token.log"})
- wsgi.server(eventlet.listen(('', 8090)), wsgiapp)
-
-
-if __name__ == "__main__":
- main()
+ 'examples/paste/auth_token.ini'),
+ global_conf={'log_name': 'auth_token.log'})
+ wsgi.server(eventlet.listen(('', 8090)), app)
diff --git a/keystone/middleware/core.py b/keystone/middleware/core.py
new file mode 100644
index 00000000..09b86bbf
--- /dev/null
+++ b/keystone/middleware/core.py
@@ -0,0 +1,112 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import json
+
+import webob.exc
+
+from keystone import config
+from keystone.common import wsgi
+
+
+CONF = config.CONF
+
+
+# Header used to transmit the auth token
+AUTH_TOKEN_HEADER = 'X-Auth-Token'
+
+
+# Environment variable used to pass the request context
+CONTEXT_ENV = 'openstack.context'
+
+
+# Environment variable used to pass the request params
+PARAMS_ENV = 'openstack.params'
+
+
+class TokenAuthMiddleware(wsgi.Middleware):
+ def process_request(self, request):
+ token = request.headers.get(AUTH_TOKEN_HEADER)
+ context = request.environ.get(CONTEXT_ENV, {})
+ context['token_id'] = token
+ request.environ[CONTEXT_ENV] = context
+
+
+class AdminTokenAuthMiddleware(wsgi.Middleware):
+ """A trivial filter that checks for a pre-defined admin token.
+
+ Sets 'is_admin' to true in the context, expected to be checked by
+ methods that are admin-only.
+
+ """
+
+ def process_request(self, request):
+ token = request.headers.get(AUTH_TOKEN_HEADER)
+ context = request.environ.get(CONTEXT_ENV, {})
+ context['is_admin'] = (token == CONF.admin_token)
+ request.environ[CONTEXT_ENV] = context
+
+
+class PostParamsMiddleware(wsgi.Middleware):
+ """Middleware to allow method arguments to be passed as POST parameters.
+
+ Filters out the parameters `self`, `context` and anything beginning with
+ an underscore.
+
+ """
+
+ def process_request(self, request):
+ params_parsed = request.params
+ params = {}
+ for k, v in params_parsed.iteritems():
+ if k in ('self', 'context'):
+ continue
+ if k.startswith('_'):
+ continue
+ params[k] = v
+
+ request.environ[PARAMS_ENV] = params
+
+
+class JsonBodyMiddleware(wsgi.Middleware):
+ """Middleware to allow method arguments to be passed as serialized JSON.
+
+ Accepting arguments as JSON is useful for accepting data that may be more
+ complex than simple primitives.
+
+ In this case we accept it as urlencoded data under the key 'json' as in
+ json=<urlencoded_json> but this could be extended to accept raw JSON
+ in the POST body.
+
+ Filters out the parameters `self`, `context` and anything beginning with
+ an underscore.
+
+ """
+ def process_request(self, request):
+ # Ignore unrecognized content types. Empty string indicates
+ # the client did not explicitly set the header
+ if not request.content_type in ('application/json', ''):
+ return
+
+ params_json = request.body
+ if not params_json:
+ return
+
+ params_parsed = {}
+ try:
+ params_parsed = json.loads(params_json)
+ except ValueError:
+ msg = "Malformed json in request body"
+ raise webob.exc.HTTPBadRequest(explanation=msg)
+ finally:
+ if not params_parsed:
+ params_parsed = {}
+
+ params = {}
+ for k, v in params_parsed.iteritems():
+ if k in ('self', 'context'):
+ continue
+ if k.startswith('_'):
+ continue
+ params[k] = v
+
+ request.environ[PARAMS_ENV] = params
diff --git a/keystone/middleware/crypt.py b/keystone/middleware/crypt.py
deleted file mode 100644
index bb25620d..00000000
--- a/keystone/middleware/crypt.py
+++ /dev/null
@@ -1,74 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Routines for URL-safe encrypting/decrypting
-
-Keep this file in sync with all copies:
-- glance/common/crypt.py
-- keystone/middleware/crypt.py
-- keystone/common/crypt.py
-
-"""
-
-import base64
-
-from Crypto.Cipher import AES
-from Crypto import Random
-from Crypto.Random import random
-
-
-def urlsafe_encrypt(key, plaintext, blocksize=16):
- """
- Encrypts plaintext. Resulting ciphertext will contain URL-safe characters
- :param key: AES secret key
- :param plaintext: Input text to be encrypted
- :param blocksize: Non-zero integer multiple of AES blocksize in bytes (16)
-
- :returns : Resulting ciphertext
- """
- def pad(text):
- """
- Pads text to be encrypted
- """
- pad_length = (blocksize - len(text) % blocksize)
- sr = random.StrongRandom()
- pad = ''.join(chr(sr.randint(1, 0xFF)) for i in range(pad_length - 1))
- # We use chr(0) as a delimiter between text and padding
- return text + chr(0) + pad
-
- # random initial 16 bytes for CBC
- init_vector = Random.get_random_bytes(16)
- cypher = AES.new(key, AES.MODE_CBC, init_vector)
- padded = cypher.encrypt(pad(str(plaintext)))
- return base64.urlsafe_b64encode(init_vector + padded)
-
-
-def urlsafe_decrypt(key, ciphertext):
- """
- Decrypts URL-safe base64 encoded ciphertext
- :param key: AES secret key
- :param ciphertext: The encrypted text to decrypt
-
- :returns : Resulting plaintext
- """
- # Cast from unicode
- ciphertext = base64.urlsafe_b64decode(str(ciphertext))
- cypher = AES.new(key, AES.MODE_CBC, ciphertext[:16])
- padded = cypher.decrypt(ciphertext[16:])
- return padded[:padded.rfind(chr(0))]
diff --git a/keystone/middleware/ec2_token.py b/keystone/middleware/ec2_token.py
new file mode 100644
index 00000000..cc3094a3
--- /dev/null
+++ b/keystone/middleware/ec2_token.py
@@ -0,0 +1,92 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright 2010 United States Government as represented by the
+# Administrator of the National Aeronautics and Space Administration.
+# All Rights Reserved.
+#
+# 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.
+"""
+Starting point for routing EC2 requests.
+
+"""
+
+from urlparse import urlparse
+
+from eventlet.green import httplib
+import webob.dec
+import webob.exc
+
+from nova import flags
+from nova import utils
+from nova import wsgi
+
+
+FLAGS = flags.FLAGS
+flags.DEFINE_string('keystone_ec2_url',
+ 'http://localhost:5000/v2.0/ec2tokens',
+ 'URL to get token from ec2 request.')
+
+
+class EC2Token(wsgi.Middleware):
+ """Authenticate an EC2 request with keystone and convert to token."""
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ # Read request signature and access id.
+ try:
+ signature = req.params['Signature']
+ access = req.params['AWSAccessKeyId']
+ except KeyError:
+ raise webob.exc.HTTPBadRequest()
+
+ # Make a copy of args for authentication and signature verification.
+ auth_params = dict(req.params)
+ # Not part of authentication args
+ auth_params.pop('Signature')
+
+ # Authenticate the request.
+ creds = {'ec2Credentials': {'access': access,
+ 'signature': signature,
+ 'host': req.host,
+ 'verb': req.method,
+ 'path': req.path,
+ 'params': auth_params,
+ }}
+ creds_json = utils.dumps(creds)
+ headers = {'Content-Type': 'application/json'}
+
+ # Disable 'has no x member' pylint error
+ # for httplib and urlparse
+ # pylint: disable-msg=E1101
+ o = urlparse(FLAGS.keystone_ec2_url)
+ if o.scheme == 'http':
+ conn = httplib.HTTPConnection(o.netloc)
+ else:
+ conn = httplib.HTTPSConnection(o.netloc)
+ conn.request('POST', o.path, body=creds_json, headers=headers)
+ response = conn.getresponse().read()
+ conn.close()
+
+ # NOTE(vish): We could save a call to keystone by
+ # having keystone return token, tenant,
+ # user, and roles from this call.
+
+ result = utils.loads(response)
+ try:
+ token_id = result['access']['token']['id']
+ except (AttributeError, KeyError):
+ raise webob.exc.HTTPBadRequest()
+
+ # Authenticated!
+ req.headers['X-Auth-Token'] = token_id
+ return self.application
diff --git a/keystone/middleware/glance_auth_token.py b/keystone/middleware/glance_auth_token.py
index cc689bc8..6bef1390 100644
--- a/keystone/middleware/glance_auth_token.py
+++ b/keystone/middleware/glance_auth_token.py
@@ -30,12 +30,9 @@ middleware.
Example: examples/paste/glance-api.conf,
examples/paste/glance-registry.conf
"""
-import logging
from glance.common import context
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
class KeystoneContextMiddleware(context.ContextMiddleware):
"""Glance keystone integration middleware."""
@@ -47,8 +44,6 @@ class KeystoneContextMiddleware(context.ContextMiddleware):
"""
# Only accept the authentication information if the identity
# has been confirmed--presumably by upstream
- logger.debug('X_IDENTITY_STATUS=%s' %
- req.headers.get('X_IDENTITY_STATUS'))
if req.headers.get('X_IDENTITY_STATUS', 'Invalid') != 'Confirmed':
# Use the default empty context
req.context = self.make_context(read_only=True)
@@ -57,7 +52,7 @@ class KeystoneContextMiddleware(context.ContextMiddleware):
# OK, let's extract the information we need
auth_tok = req.headers.get('X_AUTH_TOKEN',
req.headers.get('X_STORAGE_TOKEN'))
- user = req.headers.get('X_USER_ID') or req.headers.get('X_USER')
+ user = req.headers.get('X_USER')
tenant = req.headers.get('X_TENANT')
roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
is_admin = 'Admin' in roles
@@ -74,11 +69,10 @@ def filter_factory(global_conf, **local_conf):
"""
Factory method for paste.deploy
"""
- context_opts = context.cfg.ConfigOpts()
conf = global_conf.copy()
conf.update(local_conf)
def filter(app):
- return KeystoneContextMiddleware(app, context_opts, **conf)
+ return KeystoneContextMiddleware(app, conf)
return filter
diff --git a/keystone/middleware/nova_auth_token.py b/keystone/middleware/nova_auth_token.py
new file mode 100644
index 00000000..ad6bcbb8
--- /dev/null
+++ b/keystone/middleware/nova_auth_token.py
@@ -0,0 +1,104 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2010-2011 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.
+
+
+"""
+NOVA LAZY PROVISIONING AUTH MIDDLEWARE
+
+This WSGI component allows keystone act as an identity service for nova by
+lazy provisioning nova projects/users as authenticated by auth_token.
+
+Use by applying after auth_token in the nova paste config.
+Example: docs/nova-api-paste.ini
+"""
+
+from nova import auth
+from nova import context
+from nova import flags
+from nova import utils
+from nova import wsgi
+from nova import exception
+import webob.dec
+import webob.exc
+
+
+FLAGS = flags.FLAGS
+
+
+class KeystoneAuthShim(wsgi.Middleware):
+ """Lazy provisioning nova project/users from keystone tenant/user"""
+
+ def __init__(self, application, db_driver=None):
+ if not db_driver:
+ db_driver = FLAGS.db_driver
+ self.db = utils.import_object(db_driver)
+ self.auth = auth.manager.AuthManager()
+ super(KeystoneAuthShim, self).__init__(application)
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ # find or create user
+ try:
+ user_id = req.headers['X_USER']
+ except:
+ return webob.exc.HTTPUnauthorized()
+ try:
+ user_ref = self.auth.get_user(user_id)
+ except:
+ user_ref = self.auth.create_user(user_id)
+
+ # get the roles
+ roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
+
+ # set user admin-ness to keystone admin-ness
+ # FIXME: keystone-admin-role value from keystone.conf is not
+ # used neither here nor in glance_auth_token!
+ roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
+ is_admin = 'Admin' in roles
+ if user_ref.is_admin() != is_admin:
+ self.auth.modify_user(user_ref, admin=is_admin)
+
+ # create a project for tenant
+ if 'X_TENANT_ID' in req.headers:
+ # This is the new header since Keystone went to ID/Name
+ project_id = req.headers['X_TENANT_ID']
+ else:
+ # This is for legacy compatibility
+ project_id = req.headers['X_TENANT']
+
+ if project_id:
+ try:
+ project_ref = self.auth.get_project(project_id)
+ except:
+ project_ref = self.auth.create_project(project_id, user_id)
+ # ensure user is a member of project
+ if not self.auth.is_project_member(user_id, project_id):
+ self.auth.add_to_project(user_id, project_id)
+ else:
+ project_ref = None
+
+ # Get the auth token
+ auth_token = req.headers.get('X_AUTH_TOKEN',
+ req.headers.get('X_STORAGE_TOKEN'))
+
+ # Build a context, including the auth_token...
+ ctx = context.RequestContext(user_id, project_id,
+ is_admin=('Admin' in roles),
+ auth_token=auth_token)
+
+ req.environ['nova.context'] = ctx
+ return self.application
diff --git a/keystone/middleware/nova_keystone_context.py b/keystone/middleware/nova_keystone_context.py
new file mode 100644
index 00000000..5c41bc87
--- /dev/null
+++ b/keystone/middleware/nova_keystone_context.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 2011 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.
+"""
+Nova Auth Middleware.
+
+"""
+
+import webob.dec
+import webob.exc
+
+from nova import context
+from nova import flags
+from nova import wsgi
+
+
+FLAGS = flags.FLAGS
+flags.DECLARE('use_forwarded_for', 'nova.api.auth')
+
+
+class NovaKeystoneContext(wsgi.Middleware):
+ """Make a request context from keystone headers"""
+
+ @webob.dec.wsgify(RequestClass=wsgi.Request)
+ def __call__(self, req):
+ try:
+ user_id = req.headers['X_USER']
+ except KeyError:
+ return webob.exc.HTTPUnauthorized()
+ # get the roles
+ roles = [r.strip() for r in req.headers.get('X_ROLE', '').split(',')]
+
+ if 'X_TENANT_ID' in req.headers:
+ # This is the new header since Keystone went to ID/Name
+ project_id = req.headers['X_TENANT_ID']
+ else:
+ # This is for legacy compatibility
+ project_id = req.headers['X_TENANT']
+
+ # Get the auth token
+ auth_token = req.headers.get('X_AUTH_TOKEN',
+ req.headers.get('X_STORAGE_TOKEN'))
+
+ # Build a context, including the auth_token...
+ remote_address = getattr(req, 'remote_address', '127.0.0.1')
+ remote_address = req.remote_addr
+ if FLAGS.use_forwarded_for:
+ remote_address = req.headers.get('X-Forwarded-For', remote_address)
+ ctx = context.RequestContext(user_id,
+ project_id,
+ roles=roles,
+ auth_token=auth_token,
+ strategy='keystone',
+ remote_address=remote_address)
+
+ req.environ['nova.context'] = ctx
+ return self.application
diff --git a/keystone/middleware/quantum_auth_token.py b/keystone/middleware/quantum_auth_token.py
deleted file mode 100755
index 6d027c41..00000000
--- a/keystone/middleware/quantum_auth_token.py
+++ /dev/null
@@ -1,461 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010-2011 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.
-
-
-"""
-TOKEN-BASED AUTH MIDDLEWARE
-
-This WSGI component performs multiple jobs:
-
-- it verifies that incoming client requests have valid tokens by verifying
- tokens with the auth service.
-- it will reject unauthenticated requests UNLESS it is in 'delay_auth_decision'
- mode, which means the final decision is delegated to the downstream WSGI
- component (usually the OpenStack service)
-- it will collect and forward identity information from a valid token
- such as user name, groups, etc...
-
-Refer to: http://wiki.openstack.org/openstack-authn
-
-This WSGI component has been derived from Keystone's auth_token
-middleware module. It contains some specialization for Quantum.
-
-HEADERS
-=======
-
-Headers starting with ``HTTP_`` is a standard http header
-Headers starting with ``HTTP_X`` is an extended http header
-
-Coming in from initial call from client or customer
----------------------------------------------------
-
-HTTP_X_AUTH_TOKEN
- The client token being passed in
-
-HTTP_X_STORAGE_TOKEN
- The client token being passed in (legacy Rackspace use) to support
- cloud files
-
-Used for communication between components
------------------------------------------
-
-www-Authenticate
- Only used if this component is being used remotely
-
-HTTP_AUTHORIZATION
- Basic auth password used to validate the connection
-
-What we add to the request for use by the OpenStack service
------------------------------------------------------------
-
-HTTP_X_AUTHORIZATION
- The client identity being passed in
-
-"""
-
-import httplib
-import json
-import logging
-import urllib
-from urlparse import urlparse
-from webob.exc import HTTPUnauthorized, Request, Response
-
-from keystone.common.bufferedhttp import http_connect_raw as http_connect
-
-PROTOCOL_NAME = "Quantum Token Authentication"
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-# pylint: disable=R0902
-class AuthProtocol(object):
- """Auth Middleware that handles authenticating client calls"""
-
- def _init_protocol_common(self, app, conf):
- """ Common initialization code"""
- logger.info("Starting the %s component", PROTOCOL_NAME)
-
- self.conf = conf
- self.app = app
- #if app is set, then we are in a WSGI pipeline and requests get passed
- # on to app. If it is not set, this component should forward requests
-
- # where to find the Quantum service (if not in local WSGI chain)
- # these settings are only used if this component is acting as a proxy
- # and the OpenSTack service is running remotely
- if not self.app:
- self.service_protocol = conf.get('quantum_protocol', 'https')
- self.service_host = conf.get('quantum_host')
- self.service_port = int(conf.get('quantum_port'))
- self.service_url = '%s://%s:%s' % (self.service_protocol,
- self.service_host,
- self.service_port)
-
- # delay_auth_decision means we still allow unauthenticated requests
- # through and we let the downstream service make the final decision
- self.delay_auth_decision = int(conf.get('delay_auth_decision', 0))
-
- def _init_protocol(self, _app, conf):
- """ Protocol specific initialization """
-
- # where to find the auth service (we use this to validate tokens)
- self.auth_host = conf.get('auth_host')
- self.auth_port = int(conf.get('auth_port'))
- self.auth_protocol = conf.get('auth_protocol', 'http')
- self.cert_file = conf.get('certfile', None)
- self.key_file = conf.get('keyfile', None)
- self.auth_timeout = conf.get('auth_timeout', 30)
- self.auth_api_version = conf.get('auth_version', '2.0')
- self.auth_location = "%s://%s:%s" % (self.auth_protocol,
- self.auth_host,
- self.auth_port)
- self.auth_uri = conf.get('auth_uri', self.auth_location)
- logger.debug("Authentication Service:%s", self.auth_location)
- # Credentials used to verify this component with the Auth service
- # since validating tokens is a privileged call
- self.admin_user = conf.get('admin_user')
- self.admin_password = conf.get('admin_password')
- self.admin_token = conf.get('admin_token')
- # bind to one or more service instances
- service_ids = conf.get('service_ids')
- self.serviceId_qs = ''
- if service_ids:
- self.serviceId_qs = '?HP-IDM-serviceId=%s' % \
- (urllib.quote(service_ids))
-
- def _build_token_uri(self, claims=None):
- claim_str = "/%s" % claims if claims else ""
- return "/v%s/tokens%s%s" % (self.auth_api_version, claim_str,
- self.serviceId_qs or '')
-
- def __init__(self, app, conf):
- """ Common initialization code """
- # Defining instance variables here for improving pylint score
- # NOTE(salvatore-orlando): the following vars are assigned values
- # either in init_protocol or init_protocol_common. We should not
- # worry about them being initialized to None
- self.admin_password = None
- self.admin_token = None
- self.admin_user = None
- self.auth_api_version = None
- self.auth_host = None
- self.auth_location = None
- self.auth_uri = None
- self.auth_port = None
- self.auth_protocol = None
- self.auth_timeout = None
- self.cert_file = None
- self.key_file = None
- self.service_host = None
- self.service_port = None
- self.service_protocol = None
- self.service_url = None
- self.proxy_headers = None
- self.start_response = None
- self.app = None
- self.conf = None
- self.env = None
- self.delay_auth_decision = None
- self.expanded = None
- self.claims = None
-
- self._init_protocol_common(app, conf) # Applies to all protocols
- self._init_protocol(app, conf) # Specific to this protocol
-
- # pylint: disable=R0912
- def __call__(self, env, start_response):
- """ Handle incoming request. Authenticate. And send downstream. """
- logger.debug("entering AuthProtocol.__call__")
- logger.debug("start response:%s", start_response)
- self.start_response = start_response
- self.env = env
-
- #Prep headers to forward request to local or remote downstream service
- self.proxy_headers = env.copy()
- for header in self.proxy_headers.iterkeys():
- if header[0:5] == 'HTTP_':
- self.proxy_headers[header[5:]] = self.proxy_headers[header]
- del self.proxy_headers[header]
-
- #Look for authentication claims
- logger.debug("Looking for authentication claims")
- self.claims = self._get_claims(env)
- if not self.claims:
- #No claim(s) provided
- logger.debug("No claims provided")
- if self.delay_auth_decision:
- #Configured to allow downstream service to make final decision.
- #So mark status as Invalid and forward the request downstream
- self._decorate_request("X_IDENTITY_STATUS", "Invalid")
- else:
- #Respond to client as appropriate for this auth protocol
- return self._reject_request()
- else:
- # this request is presenting claims. Let's validate them
- logger.debug("Claims found. Validating.")
- valid = self._validate_claims(self.claims)
- if not valid:
- # Keystone rejected claim
- if self.delay_auth_decision:
- # Downstream service will receive call still and decide
- self._decorate_request("X_IDENTITY_STATUS", "Invalid")
- else:
- #Respond to client as appropriate for this auth protocol
- return self._reject_claims()
- else:
- self._decorate_request("X_IDENTITY_STATUS", "Confirmed")
-
- #Collect information about valid claims
- if valid:
- logger.debug("Validation successful")
- claims = self._expound_claims()
-
- # Store authentication data
- if claims:
- # TODO(Ziad): add additional details we may need,
- # like tenant and group info
- self._decorate_request('X_AUTHORIZATION', "Proxy %s" %
- claims['user'])
-
- self._decorate_request('X_TENANT_ID',
- claims['tenant']['id'],)
- self._decorate_request('X_TENANT_NAME',
- claims['tenant']['name'])
-
- self._decorate_request('X_USER_ID',
- claims['user']['id'])
- self._decorate_request('X_USER_NAME',
- claims['user']['name'])
-
- self._decorate_request('X_TENANT', claims['tenant']['id'])
- self._decorate_request('X_USER', claims['user']['id'])
-
- if 'group' in claims:
- self._decorate_request('X_GROUP', claims['group'])
- if 'roles' in claims and len(claims['roles']) > 0:
- if claims['roles'] is not None:
- roles = ''
- for role in claims['roles']:
- if len(roles) > 0:
- roles += ','
- roles += role
- self._decorate_request('X_ROLE', roles)
-
- # NOTE(todd): unused
- self.expanded = True
- logger.debug("About to forward request")
- #Send request downstream
- return self._forward_request()
-
- # NOTE(salvatore-orlando): this function is now used again
- def get_admin_auth_token(self, username, password):
- """
- This function gets an admin auth token to be used by this service to
- validate a user's token. Validate_token is a priviledged call so
- it needs to be authenticated by a service that is calling it
- """
- headers = {
- "Content-type": "application/json",
- "Accept": "application/json"}
- params = {
- "auth":
- {
- "passwordCredentials":
- {
- "username": username,
- "password": password
- }
- }
- }
- if self.auth_protocol == "http":
- conn = httplib.HTTPConnection(self.auth_host, self.auth_port)
- else:
- conn = httplib.HTTPSConnection(self.auth_host, self.auth_port,
- cert_file=self.cert_file)
- conn.request("POST", self._build_token_uri(), json.dumps(params), \
- headers=headers)
- response = conn.getresponse()
- data = response.read()
- return data
-
- @staticmethod
- def _get_claims(env):
- """Get claims from request"""
- claims = env.get('HTTP_X_AUTH_TOKEN', env.get('HTTP_X_STORAGE_TOKEN'))
- return claims
-
- def _reject_request(self):
- """Redirect client to auth server"""
- return HTTPUnauthorized("Authentication required",
- [("WWW-Authenticate",
- "Keystone uri='%s'" % self.auth_uri)])(self.env,
- self.start_response)
-
- def _reject_claims(self):
- """Client sent bad claims"""
- return HTTPUnauthorized()(self.env, self.start_response)
-
- def _validate_claims(self, claims, retry=False):
- """Validate claims, and provide identity information if applicable """
-
- # Step 1: We need to auth with the keystone service, so get an
- # admin token
- # TODO(ziad): Need to properly implement this, where to store creds
- # for now using token from ini
- # NOTE(salvatore-orlando): Temporarily restoring auth token retrieval,
- # with credentials in configuration file
- if not self.admin_token:
- auth = self.get_admin_auth_token(self.admin_user,
- self.admin_password)
- self.admin_token = json.loads(auth)["access"]["token"]["id"]
-
- # Step 2: validate the user's token with the auth service
- # since this is a priviledged op,m we need to auth ourselves
- # by using an admin token
- headers = {"Content-type": "application/json",
- "Accept": "application/json",
- "X-Auth-Token": self.admin_token}
- conn = http_connect(self.auth_host, self.auth_port, 'GET',
- self._build_token_uri(claims), headers=headers,
- ssl=(self.auth_protocol == 'https'),
- key_file=self.key_file, cert_file=self.cert_file,
- timeout=self.auth_timeout)
- resp = conn.getresponse()
- # pylint: disable=E1103
- conn.close()
-
- if not str(resp.status).startswith('20'):
- # Keystone rejected claim
- # In case a 404 error it might just be that the token has expired
- # Therefore try and get a new token
- # of course assuming admin credentials have been specified
- # Note(salvatore-orlando): the 404 here is not really
- # what should be returned
- if self.admin_user and self.admin_password and \
- not retry and str(resp.status) == '404':
- logger.warn("Unable to validate token." +
- "Admin token possibly expired.")
- self.admin_token = None
- return self._validate_claims(claims, True)
- return False
- else:
- #TODO(Ziad): there is an optimization we can do here. We have just
- #received data from Keystone that we can use instead of making
- #another call in _expound_claims
- logger.info("Claims successfully validated")
- return True
-
- def _expound_claims(self):
- # Valid token. Get user data and put it in to the call
- # so the downstream service can use it
- headers = {"Content-type": "application/json",
- "Accept": "application/json",
- "X-Auth-Token": self.admin_token}
- conn = http_connect(self.auth_host, self.auth_port, 'GET',
- self._build_token_uri(self.claims),
- headers=headers,
- ssl=(self.auth_protocol == 'https'),
- key_file=self.key_file, cert_file=self.cert_file,
- timeout=self.auth_timeout)
- resp = conn.getresponse()
- data = resp.read()
- # pylint: disable=E1103
- conn.close()
-
- if not str(resp.status).startswith('20'):
- raise LookupError('Unable to locate claims: %s' % resp.status)
-
- token_info = json.loads(data)
- #TODO(Ziad): make this more robust
- #first_group = token_info['auth']['user']['groups']['group'][0]
- roles = []
- rolegrants = token_info["access"]["user"]["roles"]
- if rolegrants is not None:
- roles = [rolegrant["id"] for rolegrant in rolegrants]
-
- token_info = json.loads(data)
-
- roles = [role['name'] for role in token_info[
- "access"]["user"]["roles"]]
-
- # in diablo, there were two ways to get tenant data
- tenant = token_info['access']['token'].get('tenant')
- if tenant:
- # post diablo
- tenant_id = tenant['id']
- tenant_name = tenant['name']
- else:
- # diablo only
- tenant_id = token_info['access']['user'].get('tenantId')
- tenant_name = token_info['access']['user'].get('tenantName')
-
- verified_claims = {
- 'user': {
- 'id': token_info['access']['user']['id'],
- 'name': token_info['access']['user']['name'],
- },
- 'tenant': {
- 'id': tenant_id,
- 'name': tenant_name
- },
- 'roles': roles}
-
- return verified_claims
-
- def _decorate_request(self, index, value):
- """Add headers to request"""
- self.proxy_headers[index] = value
- self.env["HTTP_%s" % index] = value
-
- def _forward_request(self):
- """Token/Auth processed & claims added to headers"""
- #now decide how to pass on the call
- if self.app:
- # Pass to downstream WSGI component
- return self.app(self.env, self.start_response)
- #.custom_start_response)
- else:
- # We are forwarding to a remote service (no downstream WSGI app)
- req = Request(self.proxy_headers)
- # pylint: disable=E1101
- parsed = urlparse(req.url)
- conn = http_connect(self.service_host,
- self.service_port,
- req.method,
- parsed.path,
- self.proxy_headers,
- ssl=(self.service_protocol == 'https'))
- resp = conn.getresponse()
- data = resp.read()
- return Response(status=resp.status, body=data)(self.proxy_headers,
- self.start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(application):
- return AuthProtocol(application, conf)
- return auth_filter
-
-
-def app_factory(global_conf, **local_conf):
- conf = global_conf.copy()
- conf.update(local_conf)
- return AuthProtocol(None, conf)
diff --git a/keystone/middleware/remoteauth.py b/keystone/middleware/remoteauth.py
deleted file mode 100644
index 07ba7032..00000000
--- a/keystone/middleware/remoteauth.py
+++ /dev/null
@@ -1,128 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010 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.
-
-
-"""
-Auth Middleware that handles auth for a service
-
-This module can be installed as a filter in front of your service to validate
-that requests are coming from a trusted component that has handled
-authenticating the call. If a call comes from an untrusted source, it will
-redirect it back to be properly authenticated. This is done by sending our a
-305 proxy redirect response with the URL for the auth service.
-
-The auth service settings are specified in the INI file (keystone.ini). The ini
-file is passed in as the WSGI config file when starting the service. For this
-proof of concept, the ini file is in echo/echo/echo.ini.
-
-In the current implementation use a basic auth password to verify that the
-request is coming from a valid auth component or service
-
-Refer to: http://wiki.openstack.org/openstack-authn
-
-
-HEADERS
--------
-
-* HTTP\_ is a standard http header
-* HTTP_X is an extended http header
-
-Coming in from initial call
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-HTTP_X_AUTH_TOKEN
- the client token being passed in
-
-HTTP_X_STORAGE_TOKEN
- the client token being passed in (legacy Rackspace use) to support
- cloud files
-
-Used for communication between components
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-www-authenticate
- only used if this component is being used remotely
-
-HTTP_AUTHORIZATION
- basic auth password used to validate the connection
-
-What we add to the request for use by the OpenStack service
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-HTTP_X_AUTHORIZATION
- the client identity being passed in
-
-
-"""
-import logging
-from webob.exc import HTTPUseProxy, HTTPUnauthorized
-
-PROTOCOL_NAME = "Remote Proxy Authentication"
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class RemoteAuth(object):
-
- # app is the downstream WSGI component, usually the OpenStack service
- #
- # if app is not provided, the assumption is this filter is being run
- # from a separate server.
-
- def __init__(self, app, conf):
- logger.info("Starting the %s component", PROTOCOL_NAME)
- # app is the next app in WSGI chain - eventually the OpenStack service
- self.app = app
- self.conf = conf
- # where to redirect untrusted requests to
- self.proxy_location = conf.get('proxy_location')
- # secret that will tell us a request is coming from a trusted auth
- # component
- self.remote_auth_pass = conf.get('remote_auth_pass')
-
- def __call__(self, env, start_response):
- # Validate the request is trusted
- # Authenticate the Auth component itself.
- headers = [('www-authenticate', 'Basic realm="API Auth"')]
- if 'HTTP_AUTHORIZATION' not in env:
- logger.debug("Unauthenticated: redirecting to %s" %
- self.proxy_location)
- # Redirect to proxy (auth component) and show that basic auth is
- # required
- return HTTPUseProxy(location=self.proxy_location,
- headers=headers)(env, start_response)
- else:
- auth_type, encoded_creds = env['HTTP_AUTHORIZATION'].split(None, 1)
- if encoded_creds != self.remote_auth_pass:
- logger.warn('Bad proxy credentials received')
- return HTTPUnauthorized(headers=headers)(env, start_response)
-
- # Make sure that the user has been authenticated by the Auth Service
- if 'HTTP_X_AUTHORIZATION' not in env:
- return HTTPUnauthorized()(env, start_response)
-
- return self.app(env, start_response)
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy."""
- conf = global_conf.copy()
- conf.update(local_conf)
-
- def auth_filter(app):
- return RemoteAuth(app, conf)
- return auth_filter
diff --git a/keystone/middleware/s3_token.py b/keystone/middleware/s3_token.py
index 31114b7c..202e2c27 100644
--- a/keystone/middleware/s3_token.py
+++ b/keystone/middleware/s3_token.py
@@ -20,33 +20,27 @@
# This source code is based ./auth_token.py and ./ec2_token.py.
# See them for their copyright.
-"""
-Starting point for routing S3 requests.
-
-"""
+"""Starting point for routing S3 requests."""
import httplib
import json
-from webob.dec import wsgify
-from urlparse import urlparse
+
+import webob
+
+from swift.common import utils as swift_utils
+
PROTOCOL_NAME = "S3 Token Authentication"
class S3Token(object):
- """Auth Middleware that handles S3 authenticating client calls"""
-
- def _init_protocol_common(self, app, conf):
- """ Common initialization code"""
- print "Starting the %s component" % PROTOCOL_NAME
+ """Auth Middleware that handles S3 authenticating client calls."""
- self.conf = conf
+ def __init__(self, app, conf):
+ """Common initialization code."""
self.app = app
- #if app is set, then we are in a WSGI pipeline and requests get passed
- # on to app. If it is not set, this component should forward requests
-
- def _init_protocol(self, conf):
- """ Protocol specific initialization """
+ self.logger = swift_utils.get_logger(conf, log_route='s3_token')
+ self.logger.debug('Starting the %s component' % PROTOCOL_NAME)
# where to find the auth service (we use this to validate tokens)
self.auth_host = conf.get('auth_host')
@@ -56,68 +50,38 @@ class S3Token(object):
# where to tell clients to find the auth service (default to url
# constructed based on endpoint we have for the service to use)
self.auth_location = conf.get('auth_uri',
- "%s://%s:%s" % (self.auth_protocol,
- self.auth_host,
- self.auth_port))
+ '%s://%s:%s' % (self.auth_protocol,
+ self.auth_host,
+ self.auth_port))
# Credentials used to verify this component with the Auth service since
# validating tokens is a privileged call
self.admin_token = conf.get('admin_token')
- def __init__(self, app, conf):
- """ Common initialization code """
-
- #TODO(ziad): maybe we refactor this into a superclass
- self._init_protocol_common(app, conf) # Applies to all protocols
- self._init_protocol(conf) # Specific to this protocol
- self.app = None
- self.auth_port = None
- self.auth_protocol = None
- self.auth_location = None
- self.auth_host = None
- self.admin_token = None
- self.conf = None
-
- #@webob.dec.wsgify(RequestClass=webob.exc.Request)
- # pylint: disable=R0914
- @wsgify
- def __call__(self, req):
- """ Handle incoming request. Authenticate. And send downstream. """
+ def __call__(self, environ, start_response):
+ """Handle incoming request. authenticate and send downstream."""
+ req = webob.Request(environ)
+ parts = swift_utils.split_path(req.path, 1, 4, True)
+ version, account, container, obj = parts
# Read request signature and access id.
if not 'Authorization' in req.headers:
- return self.app
- try:
- account, signature = \
- req.headers['Authorization'].split(' ')[-1].rsplit(':', 1)
- #del(req.headers['Authorization'])
- except StandardError:
- return self.app
+ return self.app(environ, start_response)
+ token = req.headers.get('X-Auth-Token',
+ req.headers.get('X-Storage-Token'))
- #try:
- # account, tenant = access.split(':')
- #except Exception:
- # account = access
+ auth_header = req.headers['Authorization']
+ access, signature = auth_header.split(' ')[-1].rsplit(':', 1)
# Authenticate the request.
- creds = {'OS-KSS3:s3Credentials': {'access': account,
- 'signature': signature,
- 'verb': req.method,
- 'path': req.path,
- 'expire': req.headers['Date'],
- }}
-
- if req.headers.get('Content-Type'):
- creds['s3Credentials']['content_type'] = \
- req.headers['Content-Type']
- if req.headers.get('Content-MD5'):
- creds['s3Credentials']['content_md5'] = req.headers['Content-MD5']
- xheaders = {}
- for key, value in req.headers.iteritems():
- if key.startswith('X-Amz'):
- xheaders[key.lower()] = value
- if xheaders:
- creds['s3Credentials']['xheaders'] = xheaders
+ creds = {'credentials': {'access': access,
+ 'token': token,
+ 'signature': signature,
+ 'host': req.host,
+ 'verb': req.method,
+ 'path': req.path,
+ 'expire': req.headers['Date'],
+ }}
creds_json = json.dumps(creds)
headers = {'Content-Type': 'application/json'}
@@ -126,29 +90,40 @@ class S3Token(object):
else:
conn = httplib.HTTPSConnection(self.auth_host, self.auth_port)
- conn.request('POST', '/v2.0/tokens', body=creds_json, headers=headers)
- response = conn.getresponse().read()
+ conn.request('POST', '/v2.0/s3tokens',
+ body=creds_json,
+ headers=headers)
+ resp = conn.getresponse()
+ if resp.status < 200 or resp.status >= 300:
+ raise Exception('Keystone reply error: status=%s reason=%s' % (
+ resp.status,
+ resp.reason))
+
+ # NOTE(vish): We could save a call to keystone by having
+ # keystone return token, tenant, user, and roles
+ # from this call.
+ #
+ # NOTE(chmou): We still have the same problem we would need to
+ # change token_auth to detect if we already
+ # identified and not doing a second query and just
+ # pass it through to swiftauth in this case.
+ # identity_info = json.loads(response)
+ output = resp.read()
conn.close()
-
- # NOTE(vish): We could save a call to keystone by
- # having keystone return token, tenant,
- # user, and roles from this call.
- result = json.loads(response)
- endpoint_path = ''
+ identity_info = json.loads(output)
try:
- token_id = str(result['access']['token']['id'])
- for endpoint in result['access']['serviceCatalog']:
- if endpoint['type'] == 'Swift Service':
- ep = urlparse(endpoint['endpoints'][0]['internalURL'])
- endpoint_path = str(ep.path) # pylint: disable=E1101
- break
- except KeyError:
- return self.app
-
- # Authenticated!
+ token_id = str(identity_info['access']['token']['id'])
+ tenant = (identity_info['access']['token']['tenant']['id'],
+ identity_info['access']['token']['tenant']['name'])
+ except (KeyError, IndexError):
+ self.logger.debug('Error getting keystone reply: %s' %
+ (str(output)))
+ raise
+
req.headers['X-Auth-Token'] = token_id
- req.headers['X-Endpoint-Path'] = endpoint_path
- return self.app
+ environ['PATH_INFO'] = environ['PATH_INFO'].replace(
+ account, 'AUTH_%s' % tenant[0])
+ return self.app(environ, start_response)
def filter_factory(global_conf, **local_conf):
diff --git a/keystone/middleware/swift_auth.py b/keystone/middleware/swift_auth.py
index 56fa0e09..d12ac162 100644
--- a/keystone/middleware/swift_auth.py
+++ b/keystone/middleware/swift_auth.py
@@ -1,4 +1,6 @@
-# Copyright (c) 2011 OpenStack, LLC.
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+# Copyright (c) 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.
@@ -13,17 +15,16 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from webob.exc import HTTPForbidden, HTTPNotFound, HTTPUnauthorized
+import webob
-from swift.common.utils import get_logger, split_path, get_remote_client
-from swift.common.middleware.acl import clean_acl, parse_acl, referrer_allowed
+from swift.common import utils as swift_utils
+from swift.common.middleware import acl as swift_acl
class SwiftAuth(object):
- """
- Keystone to Swift authorization system.
+ """Swift middleware to Keystone authorization system.
- Add to your pipeline in proxy-server.conf, such as::
+ In Swift's proxy-server.conf add the middleware to your pipeline::
[pipeline:main]
pipeline = catch_errors cache tokenauth swiftauth proxy-server
@@ -37,8 +38,8 @@ class SwiftAuth(object):
[filter:swiftauth]
use = egg:keystone#swiftauth
- keystone_swift_operator_roles = Admin, SwiftOperator
- keystone_tenant_user_admin = true
+ operator_roles = admin, SwiftOperator
+ is_admin = true
If Swift memcache is to be used for caching tokens, add the additional
property in the tokenauth filter:
@@ -51,11 +52,11 @@ class SwiftAuth(object):
This maps tenants to account in Swift.
The user whose able to give ACL / create Containers permissions
- will be the one that are inside the keystone_swift_operator_roles
+ will be the one that are inside the operator_roles
setting which by default includes the Admin and the SwiftOperator
roles.
- The option keystone_tenant_user_admin if set to true will allow the
+ The option is_admin if set to true will allow the
username that has the same name as the account name to be the owner.
Example: If we have the account called hellocorp with a user
@@ -68,23 +69,20 @@ class SwiftAuth(object):
def __init__(self, app, conf):
self.app = app
self.conf = conf
- self.logger = get_logger(conf, log_route='keystone')
+ self.logger = swift_utils.get_logger(conf, log_route='keystoneauth')
self.reseller_prefix = conf.get('reseller_prefix', 'AUTH').strip()
- self.keystone_swift_operator_roles = \
- conf.get('keystone_swift_operator_roles', 'Admin, SwiftOperator')
- self.keystone_tenant_user_admin = \
- conf.get('keystone_tenant_user_admin', "false").lower() in \
- ('true', 't', '1', 'on', 'yes', 'y')
- self.allowed_sync_hosts = [h.strip()
- for h in conf.get('allowed_sync_hosts', '127.0.0.1').split(',')
- if h.strip()]
+ self.operator_roles = conf.get('operator_roles',
+ 'admin, SwiftOperator')
+ config_is_admin = conf.get('is_admin', "false").lower()
+ self.is_admin = config_is_admin in ('true', 't', '1', 'on', 'yes', 'y')
+ cfg_synchosts = conf.get('allowed_sync_hosts', '127.0.0.1')
+ self.allowed_sync_hosts = [h.strip() for h in cfg_synchosts.split(',')
+ if h.strip()]
def __call__(self, environ, start_response):
- self.logger.debug('Initialise keystone middleware')
identity = self._keystone_identity(environ)
if not identity:
- #TODO: non authenticated access allow via refer
environ['swift.authorize'] = self.denied_response
return self.app(environ, start_response)
@@ -92,24 +90,24 @@ class SwiftAuth(object):
environ['keystone.identity'] = identity
environ['REMOTE_USER'] = identity.get('tenant')
environ['swift.authorize'] = self.authorize
- environ['swift.clean_acl'] = clean_acl
+ environ['swift.clean_acl'] = swift_acl.clean_acl
return self.app(environ, start_response)
def _keystone_identity(self, environ):
- """ Extract the identity from the Keystone auth component """
- if (environ.get('HTTP_X_IDENTITY_STATUS') != 'Confirmed'):
- return None
+ """Extract the identity from the Keystone auth component."""
+ if environ.get('HTTP_X_IDENTITY_STATUS') != 'Confirmed':
+ return
roles = []
- if ('HTTP_X_ROLES' in environ):
- roles = environ.get('HTTP_X_ROLES').split(',')
- identity = {'user': environ.get('HTTP_X_USER_NAME'),
+ if 'HTTP_X_ROLE' in environ:
+ roles = environ['HTTP_X_ROLE'].split(',')
+ identity = {'user': environ.get('HTTP_X_USER'),
'tenant': (environ.get('HTTP_X_TENANT_ID'),
environ.get('HTTP_X_TENANT_NAME')),
'roles': roles}
return identity
def _reseller_check(self, account, tenant_id):
- """ Check reseller prefix """
+ """Check reseller prefix."""
return account == '%s_%s' % (self.reseller_prefix, tenant_id)
def authorize(self, req):
@@ -118,77 +116,82 @@ class SwiftAuth(object):
tenant = env_identity.get('tenant')
try:
- version, account, container, obj = split_path(req.path, 1, 4, True)
+ part = swift_utils.split_path(req.path, 1, 4, True)
+ version, account, container, obj = part
except ValueError:
- return HTTPNotFound(request=req)
+ return webob.exc.HTTPNotFound(request=req)
if not self._reseller_check(account, tenant[0]):
- self.logger.debug('tenant mismatch')
+ log_msg = 'tenant mismatch: %s != %s' % (account, tenant[0])
+ self.logger.debug(log_msg)
return self.denied_response(req)
user_groups = env_identity.get('roles', [])
- # If user is in the swift operator group then make the owner of it.
- for _group in self.keystone_swift_operator_roles.split(','):
- _group = _group.strip()
- if _group in user_groups:
- self.logger.debug(
- "User in group: %s allow to manage this account" % \
- (_group))
+ # Check the groups the user is belonging to. If the user is
+ # part of the group defined in the config variable
+ # operator_roles (like Admin) then it will be
+ # promoted as an Admin of the account/tenant.
+ for group in self.operator_roles.split(','):
+ group = group.strip()
+ if group in user_groups:
+ log_msg = "allow user in group %s as account admin" % group
+ self.logger.debug(log_msg)
req.environ['swift_owner'] = True
- return None
+ return
# If user is of the same name of the tenant then make owner of it.
user = env_identity.get('user', '')
- if self.keystone_tenant_user_admin and user == tenant[1]:
- self.logger.debug("user: %s == %s tenant and option "\
- "keystone_tenant_user_admin is set" % \
- (user, tenant))
+ if self.is_admin and user == tenant[1]:
req.environ['swift_owner'] = True
- return None
-
- # Allow container sync
- if (req.environ.get('swift_sync_key') and
- req.environ['swift_sync_key'] ==
- req.headers.get('x-container-sync-key', None) and
- 'x-timestamp' in req.headers and
- (req.remote_addr in self.allowed_sync_hosts or
- get_remote_client(req) in self.allowed_sync_hosts)):
- self.logger.debug('allowing container-sync')
- return None
-
- # Check if Referrer allow it
- referrers, groups = parse_acl(getattr(req, 'acl', None))
- if referrer_allowed(req.referer, referrers):
+ return
+
+ # Allow container sync.
+ if (req.environ.get('swift_sync_key')
+ and req.environ['swift_sync_key'] ==
+ req.headers.get('x-container-sync-key', None)
+ and 'x-timestamp' in req.headers
+ and (req.remote_addr in self.allowed_sync_hosts
+ or swift_utils.get_remote_client(req)
+ in self.allowed_sync_hosts)):
+ log_msg = 'allowing proxy %s for container-sync' % req.remote_addr
+ self.logger.debug(log_msg)
+ return
+
+ # Check if referrer is allowed.
+ referrers, groups = swift_acl.parse_acl(getattr(req, 'acl', None))
+ if swift_acl.referrer_allowed(req.referer, referrers):
if obj or '.rlistings' in groups:
- self.logger.debug('authorizing via ACL')
- return None
+ log_msg = 'authorizing %s via referer ACL' % req.referrer
+ self.logger.debug(log_msg)
+ return
return self.denied_response(req)
# Allow ACL at individual user level (tenant:user format)
if '%s:%s' % (tenant[0], user) in groups:
- self.logger.debug('user explicitly allowed in ACL authorizing')
- return None
+ log_msg = 'user %s:%s allowed in ACL authorizing'
+ self.logger.debug(log_msg % (tenant[0], user))
+ return
# Check if we have the group in the usergroups and allow it
for user_group in user_groups:
if user_group in groups:
- self.logger.debug('user in group which is allowed in' \
- ' ACL: %s authorizing' % (user_group))
- return None
+ log_msg = 'user %s:%s allowed in ACL: %s authorizing'
+ self.logger.debug(log_msg % (tenant[0], user, user_group))
+ return
- # last but not least retun deny
return self.denied_response(req)
def denied_response(self, req):
- """
+ """Deny WSGI Response.
+
Returns a standard WSGI response callable with the status of 403 or 401
depending on whether the REMOTE_USER is set or not.
"""
if req.remote_user:
- return HTTPForbidden(request=req)
+ return webob.exc.HTTPForbidden(request=req)
else:
- return HTTPUnauthorized(request=req)
+ return webob.exc.HTTPUnauthorized(request=req)
def filter_factory(global_conf, **local_conf):
diff --git a/keystone/middleware/url.py b/keystone/middleware/url.py
deleted file mode 100644
index d75313a1..00000000
--- a/keystone/middleware/url.py
+++ /dev/null
@@ -1,41 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (c) 2010 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.
-
-"""
-DEPRECATED - moved to keystone.frontends.normalizer
-
-This file only exists to maintain compatibility with configuration files
-that load keystone.middleware.url
-"""
-
-import logging
-
-from keystone.frontends.normalizer import filter_factory\
- as new_filter_factory
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-def filter_factory(global_conf, **local_conf):
- """Returns a WSGI filter app for use with paste.deploy.
-
- In this case, we return the class that has been moved"""
- logger.warning("'%s' has been moved to 'keystone.frontends.normalizer'. "
- "Update your configuration file to reflect the change" %
- __name__)
- return new_filter_factory(global_conf, **local_conf)
diff --git a/keystone/models.py b/keystone/models.py
deleted file mode 100644
index 0f8006ce..00000000
--- a/keystone/models.py
+++ /dev/null
@@ -1,813 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-#
-# Copyright (C) 2011 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.
-
-""" Module that contains all object models
-
-The models are used to hold Keystone 'business' objects and their validation,
-serialization, and backend interaction code.
-
-The models are based off of python's dict.
-
-The uses supported are:
- # can be initialized with static properties
- tenant = Tenant(name='A1000')
-
- # handles writing to correct backend
- tenant.save()
-
- # static properties
- id = tenant.id
- tenant = None
-
- # Acts as a dict
- tenant is a dict
- tenant.dict points to the data dict (i.e. tenant["tenant"])
-
- # can be retrieved by static property
- tenant_by_name = Tenant.get(name='A1000')
-
- # can be retrieved by id default, so name not needed
- tenant_by_id = Tenant.get(id)
- assertIsEquals(tenant_by_id, tenant_by_name)
-
- # handles serialization
- print tenant_by_id
- print tenant_by_id.to_json() # Keystone latest contract
- print tenant_by_id.to_json_20() # Keystone 2.0 contract
-
- Serialization routines can take hints in this format:
- {
- "contract_attributes": ["id", "name", ...],
- "types": [("id", int), (...)]
- }
- attribute/value can be:
- contract_attributes: list of contract attributes (see initializer)
- format is a list of attributes names (ex ['id', 'name'])
- types: list of attribute/type mappings
- format is a list of name/type tuples (ex [('id', int)])
- tags: list of attributes that go into XML tags
- format is a list of attribute names(ex ['description']
- maps: list of attributes to rename
- format is from/to values (ex {'serviceId": "service_id",})
- Default hints can be stored in the class as cls.hints
-"""
-
-import json
-from lxml import etree
-
-from keystone import utils
-from keystone.utils import fault
-
-
-class AttrDict(dict):
- """Lets us do setattr and getattr since dict does not allow it"""
- pass
-
-
-class Resource(AttrDict):
- """ Base class for models
-
- Provides basic functionality that can be overridden """
-
- hints = {}
- xmlns = None
-
- def __init__(self, *args, **kw):
- """ Initialize object
- kwargs contain static properties
- """
- super(Resource, self).__init__(*args, **kw)
- # attributes that can be used as attributes. Example:
- # tenant.id - here id is a contract attribute
- super(Resource, self).__setattr__("contract_attributes", [])
- if kw:
- self.contract_attributes.extend(kw.keys())
- for name, value in kw.iteritems():
- self[name] = value
-
- #
- # model properties
- #
- # Override built-in classes to allow for user.id (as well as user["id"])
- # for attributes defined in the Keystone contract
- #
- def __repr__(self):
- return "<%s(%s)>" % (self.__class__.__name__, ', '.join(['%s=%s' %
- (attrib, self[attrib].__repr__()) for attrib in
- self.contract_attributes]))
-
- def __str__(self):
- """Returns string representation including the class name."""
- return str(self.to_dict())
-
- def __getattr__(self, name):
- """ Supports reading contract attributes (ex. tenant.id)
-
- This should only be called if the original call did not match
- an attribute (Python's rules)"""
- if name in self.contract_attributes:
- if name in self:
- return self[name]
- return None
- elif name == 'desc': # TODO(zns): deprecate this
- # We need to maintain this compatibility with this nasty attribute
- # until we're done refactoring
- return self.description
- else:
- if hasattr(super(Resource, self), name):
- return getattr(super(Resource, self), name)
- else:
- raise AttributeError("'%s' not found on object of class '%s'"
- % (name, self.__class__.__name__))
-
- def __setattr__(self, name, value):
- """ Supports setting contract attributes (ex. tenant.name = 'A1') """
-
- if name in self.contract_attributes:
- # Put those into the dict (and not as attrs)
- if value is not None:
- self[name] = value
- else:
- super(Resource, self).__setattr__(name, value)
-
- def __getitem__(self, name):
- if name in self.contract_attributes:
- if super(Resource, self).__contains__(name):
- return super(Resource, self).__getitem__(name)
- return None
- elif name == 'desc': # TODO(zns): deprecate this
- # We need to maintain this compatibility with this nasty attribute
- # until we're done refactoring
- return self.description
- elif name == self.__class__.__name__.lower():
- # Supports using dict syntax to access the attributes of the
- # class. Ex: Resource(id=1)['resource']['id']
- return self
- else:
- return super(Resource, self).__getitem__(name)
-
- def __contains__(self, key):
- if key in self.contract_attributes:
- return True
- return super(Resource, self).__contains__(key)
-
- #
- # Serialization Functions - may be moved to a different class
- #
- def to_dict(self, model_name=None, hints=None):
- """ For compatibility with logic.types """
- if model_name is None:
- model_name = self.__class__.__name__.lower()
- result = self.strip_null_fields(self.copy())
- if hints is None:
- hints = self.hints
- if hints:
- if "types" in hints:
- Resource.apply_type_mappings(
- result,
- hints["types"])
- if "maps" in hints:
- Resource.apply_name_mappings(
- result,
- hints["maps"])
- return {model_name: result}
-
- def to_json(self, hints=None, model_name=None):
- """ Serializes object to json - implies latest Keystone contract """
- d = self.to_dict(model_name=model_name)
- if hints is None:
- hints = self.hints
- if hints:
- if "types" in hints:
- Resource.apply_type_mappings(
- d[model_name or self.__class__.__name__.lower()],
- hints["types"])
- if "maps" in hints:
- Resource.apply_name_mappings(
- d[model_name or self.__class__.__name__.lower()],
- hints["maps"])
- return json.dumps(d)
-
- def to_xml(self, hints=None, model_name=None):
- """ Serializes object to XML string
- - implies latest Keystone contract
- :param hints: see introduction on format"""
- if hints is None:
- hints = self.hints
- dom = self.to_dom(hints=hints, model_name=model_name)
- return etree.tostring(dom)
-
- def to_dom(self, xmlns=None, hints=None, model_name=None):
- """ Serializes object to XML objec
- - implies latest Keystone contract
- :param xmlns: accepts an optional namespace for XML
- :param tags: accepts a list of attribute names that should go into XML
- tags instead of attributes
- """
- if xmlns is None:
- xmlns = self.xmlns
- if hints is None:
- hints = self.hints
- if model_name is None:
- model_name = self.__class__.__name__.lower()
- if xmlns:
- dom = etree.Element(model_name, xmlns=xmlns)
- else:
- dom = etree.Element(model_name)
- Resource.write_dict_to_xml(self, dom, hints)
- return dom
-
- #
- # Deserialization functions
- #
- @classmethod
- def from_json(cls, json_str, hints=None, model_name=None):
- """ Deserializes object from json - assumes latest Keystone
- contract
- """
- if hints is None:
- hints = cls.hints
- try:
- obj = json.loads(json_str)
- if model_name is None:
- model_name = cls.__name__.lower()
- if model_name in obj:
- # Ignore class name if it is there
- obj = obj[model_name]
- if hints and ('maps' in hints):
- name_mappings = hints['maps']
- if name_mappings:
- Resource.reverse_name_mappings(obj, name_mappings)
- model_object = None
- if hints:
- if 'contract_attributes' in hints:
- # build mapping and instantiate object with
- # contract_attributes provided
- params = {}
- for name in hints['contract_attributes']:
- if name in obj:
- params[name] = obj[name]
- else:
- params[name] = None
- model_object = cls(**params)
- if model_object is None:
- model_object = cls()
- model_object.update(obj)
-
- if hints and ('types' in hints):
- type_mappings = hints['types']
- Resource.apply_type_mappings(model_object, type_mappings)
- return model_object
- except (ValueError, TypeError) as e:
- raise fault.BadRequestFault("Cannot parse '%s' json" % \
- cls.__name__, str(e))
-
- @classmethod
- def from_xml(cls, xml_str, hints=None):
- """ Deserializes object from XML - assumes latest Keystone
- contract """
- if hints is None:
- hints = cls.hints
- try:
- object = etree.fromstring(xml_str)
- model_object = None
- type_mappings = None
- name_mappings = None
- if hints:
- if 'types' in hints:
- type_mappings = hints['types']
- if 'contract_attributes' in hints:
- # build mapping and instantiate object with
- # contract_attributes provided
- params = {}
- for name in hints['contract_attributes']:
- params[name] = object.get(name, None)
- model_object = cls(**params)
- if 'maps' in hints:
- name_mappings = hints['maps']
- if model_object is None:
- model_object = cls()
- cls.write_xml_to_dict(object, model_object)
- if type_mappings:
- Resource.apply_type_mappings(model_object, type_mappings)
- if name_mappings:
- Resource.reverse_name_mappings(model_object, name_mappings)
- return model_object
- except etree.LxmlError as e:
- raise fault.BadRequestFault("Cannot parse '%s' xml" % cls.__name__,
- str(e))
-
- #
- # Validation calls
- #
- def validate(self):
- """ Validates object attributes. Raises error if object not valid
-
- This calls inspect() in fail_fast mode, so it gets back the first
- validation error and raises it. It is up to the code in inspect()
- to determine what validations take precedence and are returned
- first
-
- :returns: True if no validation errors raise"""
- errors = self.inspect(fail_fast=True)
- if errors:
- raise errors[0][0](errors[0][1])
- return True
-
- # pylint: disable=W0613, R0201
- def inspect(self, fail_fast=None):
- """ Validates and retuns validation results without raising any errors
- :param fail_fast" return after first validation failure
-
- :returns: [(faultClass, message), ...], ordered by relevance
- - if None, then no errors found
- """
- return []
-
- #
- # Formatting, hint processing functions
- #
-
- @staticmethod
- def strip_null_fields(dict_object):
- """ Strips null fields from dict"""
- for k, v in dict_object.items():
- if v is None:
- del dict_object[k]
- return dict_object
-
- @staticmethod
- def write_dict_to_xml(dict_object, xml, hints=None):
- """ Attempts to convert a dict into XML as best as possible.
- Converts named keys and attributes and recursively calls for
- any values are are embedded dicts
-
- :param hints: handles tags (a list of attribute names that should go
- into XML tags instead of attributes) and maps
- """
- tags = []
- rename = []
- maps = {}
- if hints is not None:
- if 'tags' in hints:
- tags = hints['tags']
- if 'maps' in hints:
- maps = hints['maps']
- rename = maps.values()
- for name, value in dict_object.iteritems():
- if name in rename:
- name = maps.keys()[rename.index(name)]
- if isinstance(value, dict):
- element = etree.SubElement(xml, name)
- Resource.write_dict_to_xml(value, element)
- elif name in tags:
- element = xml.find(name)
- if isinstance(value, dict):
- if element is None:
- element = etree.SubElement(xml, name)
- Resource.write_dict_to_xml(value, element)
- else:
- if value is not None:
- if element is None:
- element = etree.SubElement(xml, name)
- element.text = str(value)
- else:
- if value is not None:
- if isinstance(value, dict):
- Resource.write_dict_to_xml(value, xml)
- elif isinstance(value, bool):
- xml.set(name, str(value).lower())
- else:
- xml.set(name, str(value))
- else:
- if name in xml:
- del xml.attrib[name]
-
- @staticmethod
- def write_xml_to_dict(xml, dict_object):
- """ Attempts to update a dict with XML as best as possible."""
- for key, value in xml.items():
- dict_object[key] = value
- for element in xml.iterdescendants():
- name = element.tag
- if "}" in name:
- #trim away namespace if it is there
- name = name[name.rfind("}") + 1:]
- if element.attrib == {}:
- dict_object[name] = element.text
- else:
- dict_object[name] = {}
- Resource.write_xml_to_dict(element, dict_object[element.tag])
-
- @staticmethod
- def apply_type_mappings(target, type_mappings):
- """Applies type mappings to dict values"""
- if type_mappings:
- for name, type in type_mappings:
- if type is int:
- target[name] = int(target[name])
- elif issubclass(type, basestring):
- # Move sub to string
- if name in target:
- value = target[name]
- if isinstance(value, dict):
- value = value[0]
- if value:
- target[name] = str(value)
- elif type is bool:
- target[name] = str(target[name]).lower() not in ['0',
- 'false']
- else:
- raise NotImplementedError("Model type mappings cannot \
- handle '%s' types" % type.__name__)
-
- @staticmethod
- def apply_name_mappings(target, name_mappings):
- """ Applies name mappings to dict values """
- if name_mappings:
- for outside, inside in name_mappings.iteritems():
- if inside in target:
- target[outside] = target.pop(inside)
-
- @staticmethod
- def reverse_name_mappings(target, name_mappings):
- """ Extracts names from mappings to dict values """
- if name_mappings:
- for outside, inside in name_mappings.iteritems():
- if outside in target:
- target[inside] = target.pop(outside)
-
- #
- # Backend management
- #
- def save(self):
- """ Handles finding correct backend and writing to it
- Supports both saving new object (create) and updating an existing one
- """
- #if self.status == 'new':
- # #backends[find the class].create(self)
- #elif self.status == 'existing':
- # #backends[find the class].update(self)
- pass
-
- def delete(self):
- """ Handles finding correct backend and deleting object from it """
- pass
-
- @classmethod
- def get(cls, id=None, *args, **kw):
- # backends[find the class].get(id, *args, **kw)
- return cls(*args, **kw)
-
-
-class Service(Resource):
- """ Service model """
- def __init__(self, id=None, name=None, type=None, description=None,
- owner_id=None, *args, **kw):
- super(Service, self).__init__(id=id, name=name, type=type,
- description=description,
- owner_id=owner_id, *args, **kw)
- # pylint: disable=E0203
- if isinstance(self.id, int):
- self.id = str(self.id)
-
- def to_dict(self, model_name=None):
- if model_name is None:
- model_name = 'OS-KSADM:service'
- return super(Service, self).to_dict(model_name=model_name)
-
- def to_dom(self, xmlns=None, hints=None, model_name=None):
- if xmlns is None:
- xmlns = "http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0"
- return super(Service, self).to_dom(xmlns, hints=hints,
- model_name=model_name)
-
- @classmethod
- def from_json(cls, json_str, hints=None, model_name=None):
- if model_name is None:
- model_name = 'OS-KSADM:service'
- result = super(Service, cls).from_json(json_str, hints=hints,
- model_name=model_name)
- result.validate() # TODO(zns): remove; compatibility with logic.types
- return result
-
- @classmethod
- def from_xml(cls, xml_str, hints=None):
- result = super(Service, cls).from_xml(xml_str, hints=hints)
- result.validate() # TODO(zns): remove; compatibility with logic.types
- return result
-
- def inspect(self, fail_fast=None):
- result = super(Service, self).inspect(fail_fast)
- if fail_fast and result:
- return result
-
- # Check that fields are valid
- invalid = [key for key in result if key not in
- ['id', 'name', 'type', 'description', 'owner_id']]
- if invalid:
- result.append((fault.BadRequestFault, "Invalid attribute(s): %s"
- % invalid))
- if fail_fast:
- return result
-
- if utils.is_empty_string(self.name):
- result.append((fault.BadRequestFault, "Expecting Service Name"))
- if fail_fast:
- return result
-
- if utils.is_empty_string(self.type):
- result.append((fault.BadRequestFault, "Expecting Service Type"))
- if fail_fast:
- return result
- return result
-
-
-class Services(object):
- "A collection of services."
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self, model_name=None):
- dom = etree.Element("services")
- dom.set(u"xmlns",
- "http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0")
-
- for t in self.values:
- dom.append(t.to_dom(model_name=model_name))
-
- for t in self.links:
- dom.append(t.to_dom(model_name=model_name))
-
- return etree.tostring(dom)
-
- def to_json(self, model_name=None):
- services = [t.to_dict()["OS-KSADM:service"]
- for t in self.values]
- services_links = [t.to_dict()["links"]
- for t in self.links]
- return json.dumps({"OS-KSADM:services": services,
- "OS-KSADM:services_links": services_links})
-
-
-class Tenant(Resource):
- """ Tenant model """
- # pylint: disable=E0203,C0103
- def __init__(self, id=None, name=None, description=None, enabled=None,
- *args, **kw):
- super(Tenant, self).__init__(id=id, name=name,
- description=description, enabled=enabled,
- *args, **kw)
- if isinstance(self.id, int):
- self.id = str(self.id)
- if isinstance(self.enabled, basestring):
- self.enabled = self.enabled.lower() == 'true'
-
- @classmethod
- def from_xml(cls, xml_str, hints=None):
- if hints is None:
- hints = {}
- if 'contract_attributes' not in hints:
- hints['contract_attributes'] = ['id', 'name', 'description',
- 'enabled']
- if 'tags' not in hints:
- hints['tags'] = ["description"]
- return super(Tenant, cls).from_xml(xml_str, hints=hints)
-
- def to_dom(self, xmlns=None, hints=None, model_name=None):
- if hints is None:
- hints = {}
- if 'tags' not in hints:
- hints['tags'] = ["description"]
- if xmlns is None:
- xmlns = "http://docs.openstack.org/identity/api/v2.0"
-
- return super(Tenant, self).to_dom(xmlns=xmlns, hints=hints,
- model_name=model_name)
-
- def to_xml(self, hints=None, model_name=None):
- if hints is None:
- hints = {}
- if 'tags' not in hints:
- hints['tags'] = ["description"]
- return super(Tenant, self).to_xml(hints=hints, model_name=model_name)
-
- def to_json(self, hints=None, model_name=None):
- if hints is None:
- hints = {}
- return super(Tenant, self).to_json(hints=hints, model_name=model_name)
-
-
-class User(Resource):
- """ User model
-
- Attribute Notes:
- default_tenant_id (formerly tenant_id): this attribute can be enabled or
- disabled by configuration. When enabled, any authentication call
- without a tenant gets authenticated to this tenant.
- """
- # pylint: disable=R0913
- def __init__(self, id=None, password=None, name=None,
- tenant_id=None,
- email=None, enabled=None,
- *args, **kw):
- super(User, self).__init__(id=id, password=password, name=name,
- tenant_id=tenant_id, email=email,
- enabled=enabled, *args, **kw)
-
- def to_json(self, hints=None, model_name=None):
- results = super(User, self).to_json(hints, model_name=model_name)
- assert 'password":' not in results
- return results
-
- def to_xml(self, hints=None):
- results = super(User, self).to_xml(hints)
- assert 'password"=' not in results
- return results
-
-
-class EndpointTemplate(Resource):
- """ EndpointTemplate model """
- # pylint: disable=R0913
- def __init__(self, id=None, region=None, service_id=None, public_url=None,
- admin_url=None, internal_url=None, enabled=None, is_global=None,
- version_id=None, version_list=None, version_info=None, *args,
- **kw):
- super(EndpointTemplate, self).__init__(id=id, region=region,
- service_id=service_id, public_url=public_url,
- admin_url=admin_url, internal_url=internal_url,
- enabled=enabled, is_global=is_global, version_id=version_id,
- version_list=version_list, version_info=version_info, *args,
- **kw)
-
-
-class Endpoint(Resource):
- """ Endpoint model """
- # pylint: disable=R0913
- def __init__(self, id=None, endpoint_template_id=None, tenant_id=None,
- *args, **kw):
- super(Endpoint, self).__init__(id=id, tenant_id=tenant_id,
- endpoint_template_id=endpoint_template_id, *args, **kw)
-
-
-class Role(Resource):
- """ Role model """
- hints = {"maps":
- {"userId": "user_id",
- "roleId": "role_id",
- "serviceId": "service_id",
- "tenantId": "tenant_id"},
- "contract_attributes": ['id', 'name', 'service_id',
- 'tenant_id', 'description'],
- "types": [('id', basestring), ('service_id', basestring)],
- }
- xmlns = "http://docs.openstack.org/identity/api/v2.0"
-
- def __init__(self, id=None, name=None, description=None, service_id=None,
- tenant_id=None, *args, **kw):
- super(Role, self).__init__(id=id, name=name,
- description=description,
- service_id=service_id,
- tenant_id=tenant_id,
- *args, **kw)
- # pylint: disable=E0203
- if isinstance(self.id, int):
- self.id = str(self.id)
- # pylint: disable=E0203
- if isinstance(self.service_id, int):
- self.service_id = str(self.service_id)
-
- @classmethod
- def from_json(cls, json_str, hints=None, model_name=None):
- # Check that fields are valid
- role = json.loads(json_str)
- if model_name is None:
- model_name = "role"
- if model_name in role:
- role = role[model_name]
-
- invalid = [key for key in role if key not in
- ['id', 'name', 'description', 'serviceId',
- # TODO(zns): remove those when we separate grants
- # from Roles
- 'tenantId', 'userId']]
- if invalid:
- raise fault.BadRequestFault("Invalid attribute(s): %s"
- % invalid)
-
- return super(Role, cls).from_json(json_str, hints=hints,
- model_name=model_name)
-
-
-class Roles(object):
- "A collection of roles."
-
- def __init__(self, values, links):
- self.values = values
- self.links = links
-
- def to_xml(self):
- dom = etree.Element("roles")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
-
- for t in self.values:
- dom.append(t.to_dom())
-
- for t in self.links:
- dom.append(t.to_dom())
-
- return etree.tostring(dom)
-
- def to_dom(self):
- dom = etree.Element("roles")
- dom.set(u"xmlns", "http://docs.openstack.org/identity/api/v2.0")
-
- if self.values:
- for t in self.values:
- dom.append(t.to_dom())
-
- if self.links:
- for t in self.links:
- dom.append(t.to_dom())
-
- return dom
-
- def to_json(self):
- values = [t.to_dict()["role"]
- for t in self.values]
- links = [t.to_dict()["links"]
- for t in self.links]
- model_name = "roles"
- return json.dumps({model_name: values,
- ("%s_links" % model_name): links})
-
- def to_json_values(self):
- values = [t.to_dict()["role"] for t in self.values]
- return values
-
-
-class Token(Resource):
- """ Token model """
- def __init__(self, id=None, user_id=None, expires=None, tenant_id=None,
- *args, **kw):
- super(Token, self).__init__(id=id, user_id=user_id, expires=expires,
- tenant_id=tenant_id, *args, **kw)
-
-
-class UserRoleAssociation(Resource):
- """ Role Grant model """
-
- hints = {
- 'contract_attributes': ['id', 'role_id', 'user_id', 'tenant_id'],
- 'types': [('user_id', basestring), ('tenant_id', basestring)],
- 'maps': {'userId': 'user_id', 'roleId': 'role_id',
- 'tenantId': 'tenant_id'}
- }
-
- def __init__(self, user_id=None, role_id=None, tenant_id=None,
- *args, **kw):
- # pylint: disable=E0203
- super(UserRoleAssociation, self).__init__(user_id=user_id,
- role_id=role_id, tenant_id=tenant_id,
- *args, **kw)
- if isinstance(self.user_id, int):
- # pylint: disable=E0203
- self.user_id = str(self.user_id)
- if isinstance(self.tenant_id, int):
- self.tenant_id = str(self.tenant_id)
-
- def to_json(self, hints=None, model_name=None):
- if model_name is None:
- model_name = "role"
- return super(UserRoleAssociation, self).to_json(hints=hints,
- model_name=model_name)
-
- def to_xml(self, hints=None, model_name=None):
- if model_name is None:
- model_name = "role"
- return super(UserRoleAssociation, self).to_xml(hints=hints,
- model_name=model_name)
-
-
-class Credentials(Resource):
- # pylint: disable=R0913
- def __init__(self, id=None, user_id=None, tenant_id=None, type=None,
- key=None, secret=None, *args, **kw):
- super(Credentials, self).__init__(id=id, user_id=user_id,
- tenant_id=tenant_id, type=type, key=key, secret=secret, *args,
- **kw)
diff --git a/keystone/policy/__init__.py b/keystone/policy/__init__.py
new file mode 100644
index 00000000..d16de59f
--- /dev/null
+++ b/keystone/policy/__init__.py
@@ -0,0 +1 @@
+from keystone.policy.core import *
diff --git a/keystone/contrib/extensions/service/osec2/__init__.py b/keystone/policy/backends/__init__.py
index e69de29b..e69de29b 100644
--- a/keystone/contrib/extensions/service/osec2/__init__.py
+++ b/keystone/policy/backends/__init__.py
diff --git a/keystone/policy/backends/simple.py b/keystone/policy/backends/simple.py
new file mode 100644
index 00000000..ec4840fe
--- /dev/null
+++ b/keystone/policy/backends/simple.py
@@ -0,0 +1,23 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+
+from keystone.common import logging
+
+
+class TrivialTrue(object):
+ def can_haz(self, target, credentials):
+ return True
+
+
+class SimpleMatch(object):
+ def can_haz(self, target, credentials):
+ """Check whether key-values in target are present in credentials."""
+ # TODO(termie): handle ANDs, probably by providing a tuple instead of a
+ # string
+ for requirement in target:
+ key, match = requirement.split(':', 1)
+ check = credentials.get(key)
+ if check is None or isinstance(check, basestring):
+ check = [check]
+ if match in check:
+ return True
diff --git a/keystone/policy/core.py b/keystone/policy/core.py
new file mode 100644
index 00000000..694f6285
--- /dev/null
+++ b/keystone/policy/core.py
@@ -0,0 +1,21 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Main entry point into the Policy service."""
+
+from keystone import config
+from keystone.common import manager
+
+
+CONF = config.CONF
+
+
+class Manager(manager.Manager):
+ """Default pivot point for the Policy backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.policy.driver)
diff --git a/keystone/routers/__init__.py b/keystone/routers/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/routers/__init__.py
+++ /dev/null
diff --git a/keystone/routers/admin.py b/keystone/routers/admin.py
deleted file mode 100755
index 63ceb4f0..00000000
--- a/keystone/routers/admin.py
+++ /dev/null
@@ -1,145 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 logging
-import routes
-
-from keystone.common import wsgi
-from keystone.controllers.token import TokenController
-from keystone.controllers.roles import RolesController
-from keystone.controllers.staticfiles import StaticFilesController
-from keystone.controllers.tenant import TenantController
-from keystone.controllers.user import UserController
-from keystone.controllers.version import VersionController
-from keystone.controllers.extensions import ExtensionsController
-import keystone.contrib.extensions.admin as extension
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class AdminApi(wsgi.Router):
- """WSGI entry point for admin Keystone API requests."""
-
- def __init__(self):
- mapper = routes.Mapper()
-
- # Load extensions first so they can override core if they need to
- extension.get_extension_configurer().configure(mapper)
-
- # Token Operations
- auth_controller = TokenController()
- mapper.connect("/tokens", controller=auth_controller,
- action="authenticate",
- conditions=dict(method=["POST"]))
- mapper.connect("/tokens/{token_id}", controller=auth_controller,
- action="validate_token",
- conditions=dict(method=["GET"]))
- mapper.connect("/tokens/{token_id}", controller=auth_controller,
- action="check_token",
- conditions=dict(method=["HEAD"]))
- # Do we need this. API doesn't have delete token.
- mapper.connect("/tokens/{token_id}", controller=auth_controller,
- action="delete_token",
- conditions=dict(method=["DELETE"]))
- mapper.connect("/tokens/{token_id}/endpoints",
- controller=auth_controller,
- action="endpoints",
- conditions=dict(method=["GET"]))
-
- # Tenant Operations
- tenant_controller = TenantController()
- mapper.connect("/tenants", controller=tenant_controller,
- action="get_tenants", conditions=dict(method=["GET"]))
- mapper.connect("/tenants/{tenant_id}",
- controller=tenant_controller,
- action="get_tenant", conditions=dict(method=["GET"]))
- roles_controller = RolesController()
- mapper.connect("/tenants/{tenant_id}/users/{user_id}/roles",
- controller=roles_controller, action="get_user_roles",
- conditions=dict(method=["GET"]))
- # User Operations
- user_controller = UserController()
- mapper.connect("/users/{user_id}",
- controller=user_controller,
- action="get_user",
- conditions=dict(method=["GET"]))
- mapper.connect("/users/{user_id}/roles",
- controller=roles_controller, action="get_user_roles",
- conditions=dict(method=["GET"]))
- # Miscellaneous Operations
- version_controller = VersionController()
- mapper.connect("/", controller=version_controller,
- action="get_version_info", file="admin/version",
- conditions=dict(method=["GET"]))
-
- extensions_controller = ExtensionsController()
- mapper.connect("/extensions",
- controller=extensions_controller,
- action="get_extensions_info",
- conditions=dict(method=["GET"]))
-
- # Static Files Controller
- static_files_controller = StaticFilesController()
- mapper.connect("/identityadminguide.pdf",
- controller=static_files_controller,
- action="get_pdf_contract",
- root="content/admin/", pdf="identityadminguide.pdf",
- conditions=dict(method=["GET"]))
- mapper.connect("/identity-admin.wadl",
- controller=static_files_controller,
- action="get_wadl_contract",
- root="content/admin/", wadl="identity-admin.wadl",
- conditions=dict(method=["GET"]))
- mapper.connect("/common.ent",
- controller=static_files_controller,
- action="get_wadl_contract",
- root="content/common/", wadl="common.ent",
- conditions=dict(method=["GET"]))
- mapper.connect("/xsd/{xsd}",
- controller=static_files_controller,
- action="get_xsd_contract",
- root="content/common/",
- conditions=dict(method=["GET"]))
- mapper.connect("/xsd/atom/{xsd}",
- controller=static_files_controller,
- action="get_xsd_atom_contract",
- root="content/common/",
- conditions=dict(method=["GET"]))
- mapper.connect("/xslt/{file:.*}",
- controller=static_files_controller,
- action="get_static_file",
- root="content/common/", path="xslt/",
- mimetype="application/xml",
- conditions=dict(method=["GET"]))
- mapper.connect("/js/{file:.*}",
- controller=static_files_controller,
- action="get_static_file",
- root="content/common/", path="js/",
- mimetype="application/javascript",
- conditions=dict(method=["GET"]))
- mapper.connect("/style/{file:.*}",
- controller=static_files_controller,
- action="get_static_file",
- root="content/common/", path="style/",
- mimetype="application/css",
- conditions=dict(method=["GET"]))
- mapper.connect("/samples/{file:.*}",
- controller=static_files_controller,
- action="get_static_file",
- root="content/common/", path="samples/",
- conditions=dict(method=["GET"]))
- super(AdminApi, self).__init__(mapper)
diff --git a/keystone/routers/service.py b/keystone/routers/service.py
deleted file mode 100644
index 529e5b44..00000000
--- a/keystone/routers/service.py
+++ /dev/null
@@ -1,117 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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 logging
-import routes
-
-from keystone.common import wsgi
-from keystone.controllers.token import TokenController
-from keystone.controllers.tenant import TenantController
-from keystone.controllers.version import VersionController
-from keystone.controllers.staticfiles import StaticFilesController
-from keystone.controllers.extensions import ExtensionsController
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-class ServiceApi(wsgi.Router):
- """WSGI entry point for Keystone Service API requests."""
-
- def __init__(self):
- mapper = routes.Mapper()
-
- # Token Operations
- auth_controller = TokenController()
- mapper.connect("/tokens", controller=auth_controller,
- action="authenticate",
- conditions=dict(method=["POST"]))
- # TODO(zns): this should be deprecated
- mapper.connect("/ec2tokens", controller=auth_controller,
- action="authenticate_ec2",
- conditions=dict(method=["POST"]))
-
- tenant_controller = TenantController(True)
- mapper.connect("/tenants",
- controller=tenant_controller,
- action="get_tenants",
- conditions=dict(method=["GET"]))
-
- # Miscellaneous Operations
- version_controller = VersionController()
- mapper.connect("/",
- controller=version_controller,
- action="get_version_info", file="service/version",
- conditions=dict(method=["GET"]))
-
- extensions_controller = ExtensionsController(True)
- mapper.connect("/extensions",
- controller=extensions_controller,
- action="get_extensions_info",
- conditions=dict(method=["GET"]))
-
- # Static Files Controller
- static_files_controller = StaticFilesController()
- mapper.connect("/identitydevguide.pdf",
- controller=static_files_controller,
- action="get_pdf_contract",
- root="content/service/", pdf="identitydevguide.pdf",
- conditions=dict(method=["GET"]))
- mapper.connect("/identity.wadl",
- controller=static_files_controller,
- action="get_wadl_contract",
- root="content/service/", wadl="identity.wadl",
- conditions=dict(method=["GET"]))
- mapper.connect("/common.ent",
- controller=static_files_controller,
- action="get_wadl_contract",
- wadl="common.ent", root="content/common/",
- conditions=dict(method=["GET"]))
- mapper.connect("/xslt/{file:.*}",
- controller=static_files_controller,
- action="get_static_file", path="common/xslt/",
- mimetype="application/xml",
- conditions=dict(method=["GET"]))
- mapper.connect("/style/{file:.*}",
- controller=static_files_controller,
- action="get_static_file", path="common/style/",
- mimetype="application/css",
- conditions=dict(method=["GET"]))
- mapper.connect("/js/{file:.*}",
- controller=static_files_controller,
- action="get_static_file", path="common/js/",
- mimetype="application/javascript",
- conditions=dict(method=["GET"]))
- mapper.connect("/samples/{file:.*}",
- controller=static_files_controller,
- action="get_static_file", path="common/samples/",
- conditions=dict(method=["GET"]))
- mapper.connect("/xsd/{xsd:.*}",
- controller=static_files_controller,
- action="get_xsd_contract", root="content/common/",
- conditions=dict(method=["GET"]))
- mapper.connect("/xsd/atom/{xsd}",
- controller=static_files_controller,
- action="get_xsd_atom_contract",
- root="content/common/",
- conditions=dict(method=["GET"]))
- mapper.connect("/xsd/atom/{xsd}",
- controller=static_files_controller,
- action="get_xsd_atom_contract",
- root="content/common/",
- conditions=dict(method=["GET"]))
-
- super(ServiceApi, self).__init__(mapper)
diff --git a/keystone/server.py b/keystone/server.py
deleted file mode 100755
index de040948..00000000
--- a/keystone/server.py
+++ /dev/null
@@ -1,186 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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.
-
-
-"""
-Service that stores identities and issues and manages tokens
-
-HEADERS
--------
-
-* HTTP\_ is a standard http header
-* HTTP_X is an extended http header
-
-Coming in from initial call
-^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-HTTP_X_AUTH_TOKEN
- the client token being passed in
-
-HTTP_X_STORAGE_TOKEN
- the client token being passed in (legacy Rackspace use) to support
- cloud files
-
-Used for communication between components
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-www-authenticate
- only used if this component is being used remotely
-
-HTTP_AUTHORIZATION
- basic auth password used to validate the connection
-
-What we add to the request for use by the OpenStack SERVICE
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-HTTP_X_AUTHORIZATION
- the client identity being passed in
-
-"""
-
-# pylint: disable=W0613
-
-import logging
-
-from keystone import config
-from keystone.common import config as common_config
-from keystone.common import wsgi
-from keystone.routers.service import ServiceApi
-from keystone.routers.admin import AdminApi
-
-CONF = config.CONF
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-
-def service_app_factory(global_conf, **local_conf):
- """paste.deploy app factory for creating OpenStack API server apps"""
- return ServiceApi()
-
-
-def admin_app_factory(global_conf, **local_conf):
- """paste.deploy app factory for creating OpenStack API server apps"""
- return AdminApi()
-
-
-# pylint: disable=R0902
-class Server():
- """Used to start and stop Keystone servers
-
- This class is called from shell and command-line scripts and is the
- entry-point for starting and stopping Keystone servers.
-
- The initializer can take option and argument overrides, but otherwise will
- parse arguments and configuration files itself to determine how to start
- the server.
- """
-
- def __init__(self, name='admin', config_name=None, args=None):
- """Initizalizer which takes the following paramaters:
-
- :param name: A cosmetic name for the server (ex. Admin API)
- :param config: the paste config name to look for when starting the
- server
- :param args: override for sys.argv (otherwise sys.argv is used)
- """
- logger.debug("Init server '%s' with config=%s" % (name, config_name))
-
- self.name = name
- self.config = config_name or self.name
- self.args = args
- self.key = None
- self.server = None
- self.port = None
- self.host = None
- self.protocol = None
- self.options = CONF.to_dict()
-
- def start(self, host=None, port=None, wait=True):
- """Starts the Keystone server
-
- :param host: the IP address to listen on
- :param port: the TCP/IP port to listen on
- :param wait: whether to wait (block) for the server to terminate or
- return to the caller without waiting
- """
- logger.debug("Starting API server")
- conf, app = common_config.load_paste_app(self.config, self.options,
- self.args)
-
- debug = CONF.debug in [True, "True", "1"]
- verbose = CONF.verbose in [True, "True", "1"]
-
- if debug or verbose:
- config_file = common_config.find_config_file(self.options,
- self.args)
- logger.info("Starting '%s' with config: %s" %
- (self.config, config_file))
-
- if port is None:
- if self.config == 'admin':
- # Legacy
- port = int(CONF.admin_port or 35357)
- else:
- port = int(CONF.service_port or CONF.bind_port or 5000)
- if host is None:
- host = CONF.bind_host or CONF.service_host or "0.0.0.0"
-
- self.key = "%s-%s:%s" % (self.name, host, port)
-
- # Safely get SSL options
- service_ssl = CONF.service_ssl in [True, "True", "1"]
-
- # Load the server
- if service_ssl:
- cert_required = conf.get('cert_required', False)
- cert_required = cert_required in [True, "True", "1"]
- certfile = conf.get('certfile')
- keyfile = conf.get('keyfile')
- ca_certs = conf.get('ca_certs')
-
- self.server = wsgi.SslServer()
- self.server.start(app, port, host,
- certfile=certfile, keyfile=keyfile,
- ca_certs=ca_certs,
- cert_required=cert_required,
- key=self.key)
- self.protocol = 'https'
- else:
- self.server = wsgi.Server()
- self.server.start(app, port, host,
- key="%s-%s:%s" % (self.config, host, port))
- self.protocol = 'http'
-
- self.port = port
- self.host = host
-
- logger.info("%s listening on %s://%s:%s" % (
- self.name, ['http', 'https'][service_ssl], host, port))
-
- # Wait until done
- if wait:
- self.server.wait()
-
- def stop(self):
- """Stops the Keystone server
-
- This should be called always to release the network socket
- """
- if self.server is not None:
- if self.key in self.server.threads:
- logger.debug("Killing %s" % self.key)
- self.server.threads[self.key].kill()
- self.server = None
diff --git a/keystone/service.py b/keystone/service.py
new file mode 100644
index 00000000..2c361e40
--- /dev/null
+++ b/keystone/service.py
@@ -0,0 +1,448 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import uuid
+
+import routes
+import webob.dec
+import webob.exc
+
+from keystone import catalog
+from keystone import exception
+from keystone import identity
+from keystone import policy
+from keystone import token
+from keystone.common import logging
+from keystone.common import utils
+from keystone.common import wsgi
+
+
+class AdminRouter(wsgi.ComposingRouter):
+ def __init__(self):
+ mapper = routes.Mapper()
+
+ # Token Operations
+ auth_controller = TokenController()
+ mapper.connect('/tokens',
+ controller=auth_controller,
+ action='authenticate',
+ conditions=dict(method=['POST']))
+ mapper.connect('/tokens/{token_id}',
+ controller=auth_controller,
+ action='validate_token',
+ conditions=dict(method=['GET']))
+ mapper.connect('/tokens/{token_id}',
+ controller=auth_controller,
+ action='delete_token',
+ conditions=dict(method=['DELETE']))
+ mapper.connect('/tokens/{token_id}/endpoints',
+ controller=auth_controller,
+ action='endpoints',
+ conditions=dict(method=['GET']))
+
+ # Miscellaneous Operations
+ extensions_controller = ExtensionsController()
+ mapper.connect('/extensions',
+ controller=extensions_controller,
+ action='get_extensions_info',
+ conditions=dict(method=['GET']))
+ identity_router = identity.AdminRouter()
+ routers = [identity_router]
+ super(AdminRouter, self).__init__(mapper, routers)
+
+
+class PublicRouter(wsgi.ComposingRouter):
+ def __init__(self):
+ mapper = routes.Mapper()
+
+ noop_controller = NoopController()
+ mapper.connect('/',
+ controller=noop_controller,
+ action='noop')
+
+ # Token Operations
+ auth_controller = TokenController()
+ mapper.connect('/tokens',
+ controller=auth_controller,
+ action='authenticate',
+ conditions=dict(method=['POST']))
+
+ # Miscellaneous
+ extensions_controller = ExtensionsController()
+ mapper.connect('/extensions',
+ controller=extensions_controller,
+ action='get_extensions_info',
+ conditions=dict(method=['GET']))
+
+ identity_router = identity.PublicRouter()
+ routers = [identity_router]
+
+ super(PublicRouter, self).__init__(mapper, routers)
+
+
+class PublicVersionRouter(wsgi.ComposingRouter):
+ def __init__(self):
+ mapper = routes.Mapper()
+ version_controller = VersionController('public')
+ mapper.connect('/',
+ controller=version_controller,
+ action='get_versions')
+ routers = []
+ super(PublicVersionRouter, self).__init__(mapper, routers)
+
+
+class AdminVersionRouter(wsgi.ComposingRouter):
+ def __init__(self):
+ mapper = routes.Mapper()
+ version_controller = VersionController('admin')
+ mapper.connect('/',
+ controller=version_controller,
+ action='get_versions')
+ routers = []
+ super(AdminVersionRouter, self).__init__(mapper, routers)
+
+
+class VersionController(wsgi.Application):
+ def __init__(self, version_type):
+ self.catalog_api = catalog.Manager()
+ self.url_key = "%sURL" % version_type
+ super(VersionController, self).__init__()
+
+ def _get_identity_url(self, context):
+ catalog_ref = self.catalog_api.get_catalog(
+ context=context,
+ user_id=None,
+ tenant_id=None)
+ for region, region_ref in catalog_ref.iteritems():
+ for service, service_ref in region_ref.iteritems():
+ if service == 'identity':
+ return service_ref[self.url_key]
+
+ raise NotImplemented()
+
+ def get_versions(self, context):
+ identity_url = self._get_identity_url(context)
+ if not identity_url.endswith('/'):
+ identity_url = identity_url + '/'
+ return {
+ "versions": {
+ "values": [{
+ "id": "v2.0",
+ "status": "beta",
+ "updated": "2011-11-19T00:00:00Z",
+ "links": [{
+ "rel": "self",
+ "href": identity_url,
+ }, {
+ "rel": "describedby",
+ "type": "text/html",
+ "href": "http://docs.openstack.org/api/openstack-"
+ "identity-service/2.0/content/"
+ }, {
+ "rel": "describedby",
+ "type": "application/pdf",
+ "href": "http://docs.openstack.org/api/openstack-"
+ "identity-service/2.0/identity-dev-guide-"
+ "2.0.pdf"
+ }],
+ "media-types": [{
+ "base": "application/json",
+ "type": "application/vnd.openstack.identity-v2.0"
+ "+json"
+ }]
+ }]
+ }
+ }
+
+
+class NoopController(wsgi.Application):
+ def __init__(self):
+ super(NoopController, self).__init__()
+
+ def noop(self, context):
+ return {}
+
+
+class TokenController(wsgi.Application):
+ def __init__(self):
+ self.catalog_api = catalog.Manager()
+ self.identity_api = identity.Manager()
+ self.token_api = token.Manager()
+ self.policy_api = policy.Manager()
+ super(TokenController, self).__init__()
+
+ def authenticate(self, context, auth=None):
+ """Authenticate credentials and return a token.
+
+ Accept auth as a dict that looks like::
+
+ {
+ "auth":{
+ "passwordCredentials":{
+ "username":"test_user",
+ "password":"mypass"
+ },
+ "tenantName":"customer-x"
+ }
+ }
+
+ In this case, tenant is optional, if not provided the token will be
+ considered "unscoped" and can later be used to get a scoped token.
+
+ Alternatively, this call accepts auth with only a token and tenant
+ that will return a token that is scoped to that tenant.
+ """
+
+ token_id = uuid.uuid4().hex
+ if 'passwordCredentials' in auth:
+ username = auth['passwordCredentials'].get('username', '')
+ password = auth['passwordCredentials'].get('password', '')
+ tenant_name = auth.get('tenantName', None)
+
+ if username:
+ user_ref = self.identity_api.get_user_by_name(
+ context=context, user_name=username)
+ user_id = user_ref['id']
+ else:
+ user_id = auth['passwordCredentials'].get('userId', None)
+
+ # more compat
+ if tenant_name:
+ tenant_ref = self.identity_api.get_tenant_by_name(
+ context=context, tenant_name=tenant_name)
+ tenant_id = tenant_ref['id']
+ else:
+ tenant_id = auth.get('tenantId', None)
+
+ try:
+ (user_ref, tenant_ref, metadata_ref) = \
+ self.identity_api.authenticate(context=context,
+ user_id=user_id,
+ password=password,
+ tenant_id=tenant_id)
+
+ # If the user is disabled don't allow them to authenticate
+ if not user_ref.get('enabled', True):
+ raise webob.exc.HTTPForbidden('User has been disabled')
+ except AssertionError as e:
+ raise webob.exc.HTTPForbidden(e.message)
+
+ token_ref = self.token_api.create_token(
+ context, token_id, dict(id=token_id,
+ user=user_ref,
+ tenant=tenant_ref,
+ metadata=metadata_ref))
+ if tenant_ref:
+ catalog_ref = self.catalog_api.get_catalog(
+ context=context,
+ user_id=user_ref['id'],
+ tenant_id=tenant_ref['id'],
+ metadata=metadata_ref)
+ else:
+ catalog_ref = {}
+
+ elif 'token' in auth:
+ token = auth['token'].get('id', None)
+
+ tenant_name = auth.get('tenantName')
+
+ # more compat
+ if tenant_name:
+ tenant_ref = self.identity_api.get_tenant_by_name(
+ context=context, tenant_name=tenant_name)
+ tenant_id = tenant_ref['id']
+ else:
+ tenant_id = auth.get('tenantId', None)
+
+ try:
+ old_token_ref = self.token_api.get_token(context=context,
+ token_id=token)
+ except exception.NotFound:
+ raise exception.Unauthorized()
+
+ user_ref = old_token_ref['user']
+
+ tenants = self.identity_api.get_tenants_for_user(context,
+ user_ref['id'])
+ if tenant_id:
+ assert tenant_id in tenants
+
+ tenant_ref = self.identity_api.get_tenant(context=context,
+ tenant_id=tenant_id)
+ if tenant_ref:
+ metadata_ref = self.identity_api.get_metadata(
+ context=context,
+ user_id=user_ref['id'],
+ tenant_id=tenant_ref['id'])
+ catalog_ref = self.catalog_api.get_catalog(
+ context=context,
+ user_id=user_ref['id'],
+ tenant_id=tenant_ref['id'],
+ metadata=metadata_ref)
+ else:
+ metadata_ref = {}
+ catalog_ref = {}
+
+ token_ref = self.token_api.create_token(
+ context, token_id, dict(id=token_id,
+ user=user_ref,
+ tenant=tenant_ref,
+ metadata=metadata_ref))
+
+ # TODO(termie): optimize this call at some point and put it into the
+ # the return for metadata
+ # fill out the roles in the metadata
+ roles_ref = []
+ for role_id in metadata_ref.get('roles', []):
+ roles_ref.append(self.identity_api.get_role(context, role_id))
+ logging.debug('TOKEN_REF %s', token_ref)
+ return self._format_authenticate(token_ref, roles_ref, catalog_ref)
+
+ # admin only
+ def validate_token(self, context, token_id, belongs_to=None):
+ """Check that a token is valid.
+
+ Optionally, also ensure that it is owned by a specific tenant.
+
+ """
+ # TODO(termie): this stuff should probably be moved to middleware
+ self.assert_admin(context)
+
+ token_ref = self.token_api.get_token(context=context,
+ token_id=token_id)
+
+ if belongs_to:
+ assert token_ref['tenant']['id'] == belongs_to
+
+ # TODO(termie): optimize this call at some point and put it into the
+ # the return for metadata
+ # fill out the roles in the metadata
+ metadata_ref = token_ref['metadata']
+ roles_ref = []
+ for role_id in metadata_ref.get('roles', []):
+ roles_ref.append(self.identity_api.get_role(context, role_id))
+ return self._format_token(token_ref, roles_ref)
+
+ def delete_token(self, context, token_id):
+ """Delete a token, effectively invalidating it for authz."""
+ # TODO(termie): this stuff should probably be moved to middleware
+ self.assert_admin(context)
+
+ self.token_api.delete_token(context=context, token_id=token_id)
+
+ def endpoints(self, context, token_id):
+ """Return service catalog endpoints."""
+ try:
+ token_ref = self.token_api.get_token(context=context,
+ token_id=token_id)
+ except exception.NotFound:
+ raise exception.Unauthorized()
+
+ catalog_ref = self.catalog_api.get_catalog(context,
+ token_ref['user']['id'],
+ token_ref['tenant']['id'])
+ return {'token': {'serviceCatalog': self._format_catalog(catalog_ref)}}
+
+ def _format_authenticate(self, token_ref, roles_ref, catalog_ref):
+ o = self._format_token(token_ref, roles_ref)
+ o['access']['serviceCatalog'] = self._format_catalog(catalog_ref)
+ return o
+
+ def _format_token(self, token_ref, roles_ref):
+ user_ref = token_ref['user']
+ metadata_ref = token_ref['metadata']
+ expires = token_ref['expires']
+ if expires is not None:
+ expires = utils.isotime(expires)
+ o = {'access': {'token': {'id': token_ref['id'],
+ 'expires': expires,
+ },
+ 'user': {'id': user_ref['id'],
+ 'name': user_ref['name'],
+ 'username': user_ref['name'],
+ 'roles': roles_ref,
+ 'roles_links': metadata_ref.get('roles_links',
+ [])
+ }
+ }
+ }
+ if 'tenant' in token_ref and token_ref['tenant']:
+ token_ref['tenant']['enabled'] = True
+ o['access']['token']['tenant'] = token_ref['tenant']
+ return o
+
+ def _format_catalog(self, catalog_ref):
+ """Munge catalogs from internal to output format
+ Internal catalogs look like:
+
+ {$REGION: {
+ {$SERVICE: {
+ $key1: $value1,
+ ...
+ }
+ }
+ }
+
+ The legacy api wants them to look like
+
+ [{'name': $SERVICE[name],
+ 'type': $SERVICE,
+ 'endpoints': [{
+ 'tenantId': $tenant_id,
+ ...
+ 'region': $REGION,
+ }],
+ 'endpoints_links': [],
+ }]
+
+ """
+ if not catalog_ref:
+ return {}
+
+ services = {}
+ for region, region_ref in catalog_ref.iteritems():
+ for service, service_ref in region_ref.iteritems():
+ new_service_ref = services.get(service, {})
+ new_service_ref['name'] = service_ref.pop('name')
+ new_service_ref['type'] = service
+ new_service_ref['endpoints_links'] = []
+ service_ref['region'] = region
+
+ endpoints_ref = new_service_ref.get('endpoints', [])
+ endpoints_ref.append(service_ref)
+
+ new_service_ref['endpoints'] = endpoints_ref
+ services[service] = new_service_ref
+
+ return services.values()
+
+
+class ExtensionsController(wsgi.Application):
+ def __init__(self):
+ super(ExtensionsController, self).__init__()
+
+ def get_extensions_info(self, context):
+ raise NotImplemented()
+
+
+def public_app_factory(global_conf, **local_conf):
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return PublicRouter()
+
+
+def admin_app_factory(global_conf, **local_conf):
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return AdminRouter()
+
+
+def public_version_app_factory(global_conf, **local_conf):
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return PublicVersionRouter()
+
+
+def admin_version_app_factory(global_conf, **local_conf):
+ conf = global_conf.copy()
+ conf.update(local_conf)
+ return AdminVersionRouter()
diff --git a/keystone/test.py b/keystone/test.py
new file mode 100644
index 00000000..f28ce6f7
--- /dev/null
+++ b/keystone/test.py
@@ -0,0 +1,248 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import os
+import unittest
+import subprocess
+import sys
+import time
+
+from paste import deploy
+
+from keystone import config
+from keystone.common import kvs
+from keystone.common import logging
+from keystone.common import utils
+from keystone.common import wsgi
+
+
+ROOTDIR = os.path.dirname(os.path.dirname(__file__))
+VENDOR = os.path.join(ROOTDIR, 'vendor')
+TESTSDIR = os.path.join(ROOTDIR, 'tests')
+ETCDIR = os.path.join(ROOTDIR, 'etc')
+CONF = config.CONF
+
+
+cd = os.chdir
+
+
+def rootdir(*p):
+ return os.path.join(ROOTDIR, *p)
+
+
+def etcdir(*p):
+ return os.path.join(ETCDIR, *p)
+
+
+def testsdir(*p):
+ return os.path.join(TESTSDIR, *p)
+
+
+def checkout_vendor(repo, rev):
+ # TODO(termie): this function is a good target for some optimizations :PERF
+ name = repo.split('/')[-1]
+ if name.endswith('.git'):
+ name = name[:-4]
+
+ working_dir = os.getcwd()
+ revdir = os.path.join(VENDOR, '%s-%s' % (name, rev.replace('/', '_')))
+ modcheck = os.path.join(VENDOR, '.%s-%s' % (name, rev.replace('/', '_')))
+ try:
+ if os.path.exists(modcheck):
+ mtime = os.stat(modcheck).st_mtime
+ if int(time.time()) - mtime < 10000:
+ return revdir
+
+ if not os.path.exists(revdir):
+ utils.git('clone', repo, revdir)
+
+ cd(revdir)
+ utils.git('checkout', '-q', 'master')
+ utils.git('pull', '-q')
+ utils.git('checkout', '-q', rev)
+
+ # write out a modified time
+ with open(modcheck, 'w') as fd:
+ fd.write('1')
+ except subprocess.CalledProcessError as e:
+ logging.warning('Failed to checkout %s', repo)
+ cd(working_dir)
+ return revdir
+
+
+class TestClient(object):
+ def __init__(self, app=None, token=None):
+ self.app = app
+ self.token = token
+
+ def request(self, method, path, headers=None, body=None):
+ if headers is None:
+ headers = {}
+
+ if self.token:
+ headers.setdefault('X-Auth-Token', self.token)
+
+ req = wsgi.Request.blank(path)
+ req.method = method
+ for k, v in headers.iteritems():
+ req.headers[k] = v
+ if body:
+ req.body = body
+ return req.get_response(self.app)
+
+ def get(self, path, headers=None):
+ return self.request('GET', path=path, headers=headers)
+
+ def post(self, path, headers=None, body=None):
+ return self.request('POST', path=path, headers=headers, body=body)
+
+ def put(self, path, headers=None, body=None):
+ return self.request('PUT', path=path, headers=headers, body=body)
+
+
+class TestCase(unittest.TestCase):
+ def __init__(self, *args, **kw):
+ super(TestCase, self).__init__(*args, **kw)
+ self._paths = []
+ self._memo = {}
+
+ def setUp(self):
+ super(TestCase, self).setUp()
+ self.config()
+
+ def config(self):
+ CONF(config_files=[etcdir('keystone.conf'),
+ testsdir('test_overrides.conf')])
+
+ def tearDown(self):
+ for path in self._paths:
+ if path in sys.path:
+ sys.path.remove(path)
+ kvs.INMEMDB.clear()
+ CONF.reset()
+ super(TestCase, self).tearDown()
+
+ def load_backends(self):
+ """Hacky shortcut to load the backends for data manipulation."""
+ self.identity_api = utils.import_object(CONF.identity.driver)
+ self.token_api = utils.import_object(CONF.token.driver)
+ self.catalog_api = utils.import_object(CONF.catalog.driver)
+
+ def load_fixtures(self, fixtures):
+ """Hacky basic and naive fixture loading based on a python module.
+
+ Expects that the various APIs into the various services are already
+ defined on `self`.
+
+ """
+ # TODO(termie): doing something from json, probably based on Django's
+ # loaddata will be much preferred.
+ for tenant in fixtures.TENANTS:
+ rv = self.identity_api.create_tenant(tenant['id'], tenant)
+ setattr(self, 'tenant_%s' % tenant['id'], rv)
+
+ for user in fixtures.USERS:
+ user_copy = user.copy()
+ tenants = user_copy.pop('tenants')
+ rv = self.identity_api.create_user(user['id'], user_copy.copy())
+ for tenant_id in tenants:
+ self.identity_api.add_user_to_tenant(tenant_id, user['id'])
+ setattr(self, 'user_%s' % user['id'], user_copy)
+
+ for role in fixtures.ROLES:
+ rv = self.identity_api.create_role(role['id'], role)
+ setattr(self, 'role_%s' % role['id'], rv)
+
+ for metadata in fixtures.METADATA:
+ metadata_ref = metadata.copy()
+ # TODO(termie): these will probably end up in the model anyway,
+ # so this may be futile
+ del metadata_ref['user_id']
+ del metadata_ref['tenant_id']
+ rv = self.identity_api.create_metadata(metadata['user_id'],
+ metadata['tenant_id'],
+ metadata_ref)
+ setattr(self,
+ 'metadata_%s%s' % (metadata['user_id'],
+ metadata['tenant_id']), rv)
+
+ def _paste_config(self, config):
+ if not config.startswith('config:'):
+ test_path = os.path.join(TESTSDIR, config)
+ etc_path = os.path.join(ROOTDIR, 'etc', config)
+ for path in [test_path, etc_path]:
+ if os.path.exists('%s.conf' % path):
+ return 'config:%s.conf' % path
+ return config
+
+ def loadapp(self, config, name='main'):
+ return deploy.loadapp(self._paste_config(config), name=name)
+
+ def appconfig(self, config):
+ return deploy.appconfig(self._paste_config(config))
+
+ def serveapp(self, config, name=None):
+ app = self.loadapp(config, name=name)
+ server = wsgi.Server(app, 0)
+ server.start(key='socket')
+
+ # Service catalog tests need to know the port we ran on.
+ port = server.socket_info['socket'][1]
+ CONF.public_port = port
+ CONF.admin_port = port
+ return server
+
+ def client(self, app, *args, **kw):
+ return TestClient(app, *args, **kw)
+
+ def add_path(self, path):
+ sys.path.insert(0, path)
+ self._paths.append(path)
+
+ def clear_module(self, module):
+ for x in sys.modules.keys():
+ if x.startswith(module):
+ del sys.modules[x]
+
+ def assertListEquals(self, actual, expected):
+ copy = expected[:]
+ #print expected, actual
+ self.assertEquals(len(actual), len(expected))
+ while copy:
+ item = copy.pop()
+ matched = False
+ for x in actual:
+ #print 'COMPARE', item, x,
+ try:
+ self.assertDeepEquals(x, item)
+ matched = True
+ #print 'MATCHED'
+ break
+ except AssertionError as e:
+ #print e
+ pass
+ if not matched:
+ raise AssertionError('Expected: %s\n Got: %s' % (expected,
+ actual))
+
+ def assertDictEquals(self, actual, expected):
+ for k in expected:
+ self.assertTrue(k in actual,
+ 'Expected key %s not in %s.' % (k, actual))
+ self.assertDeepEquals(expected[k], actual[k])
+
+ for k in actual:
+ self.assertTrue(k in expected,
+ 'Unexpected key %s in %s.' % (k, actual))
+
+ def assertDeepEquals(self, actual, expected):
+ try:
+ if type(expected) is type([]) or type(expected) is type(tuple()):
+ # assert items equal, ignore order
+ self.assertListEquals(actual, expected)
+ elif type(expected) is type({}):
+ self.assertDictEquals(actual, expected)
+ else:
+ self.assertEquals(actual, expected)
+ except AssertionError as e:
+ raise
+ raise AssertionError('Expected: %s\n Got: %s' % (expected, actual))
diff --git a/keystone/test/EchoSOAPUI.xml b/keystone/test/EchoSOAPUI.xml
deleted file mode 100644
index 8a74eee0..00000000
--- a/keystone/test/EchoSOAPUI.xml
+++ /dev/null
@@ -1,2 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<con:soapui-project name="Echo" resourceRoot="" soapui-version="3.6.1" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"><con:settings/><con:interface xsi:type="con:RestService" wadlVersion="http://wadl.dev.java.net/2009/02" name="Echo" type="rest" basePath="" definitionUrl="file:/Users/jorgew/projects/keystone/echo/echo.wadl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:settings/><con:definitionCache/><con:endpoints><con:endpoint>http://localhost:8090</con:endpoint></con:endpoints><con:resource name="/" path="/"><con:settings/><con:parameters><con:parameter required="true"><con:name>X-Auth-Token</con:name><con:value xsi:nil="true"/><con:style>HEADER</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:method name="GET - get" method="GET"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>*/*</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/echo/api/v1.0">v1:echo</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="*/*"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8090</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:request></con:method><con:method name="PUT - put" method="PUT"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>*/*</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/echo/api/v1.0">v1:echo</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1"><con:settings/><con:endpoint>http://localhost:8090</con:endpoint><con:parameters/></con:request></con:method><con:method name="POST - post" method="POST"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>*/*</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/echo/api/v1.0">v1:echo</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1"><con:settings/><con:endpoint>http://localhost:8090</con:endpoint><con:parameters/></con:request></con:method><con:method name="DELETE - delete" method="DELETE"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>*/*</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/echo/api/v1.0">v1:echo</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1"><con:settings/><con:endpoint>http://localhost:8090</con:endpoint><con:parameters/></con:request></con:method><con:method name="HEAD - head" method="HEAD"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>*/*</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/echo/api/v1.0">v1:echo</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1"><con:settings/><con:endpoint>http://localhost:8090</con:endpoint><con:parameters/></con:request></con:method><con:method name="OPTIONS - options" method="OPTIONS"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>*/*</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/echo/api/v1.0">v1:echo</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1"><con:settings/><con:endpoint>http://localhost:8090</con:endpoint><con:parameters/></con:request></con:method></con:resource></con:interface><con:properties/><con:wssContainer/><con:databaseConnectionContainer/><con:reporting><con:xmlTemplates/><con:parameters/></con:reporting></con:soapui-project> \ No newline at end of file
diff --git a/keystone/test/IdentitySOAPUI.xml b/keystone/test/IdentitySOAPUI.xml
deleted file mode 100644
index de072afb..00000000
--- a/keystone/test/IdentitySOAPUI.xml
+++ /dev/null
@@ -1,1355 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<con:soapui-project name="Keystone" resourceRoot="" soapui-version="3.6.1" abortOnError="false" runType="SEQUENTIAL" xmlns:con="http://eviware.com/soapui/config"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.actions.iface.tools.soapui.TestRunnerAction@values-local"><![CDATA[<xml-fragment xmlns:con="http://eviware.com/soapui/config">
- <con:entry key="Global Properties" value=""/>
- <con:entry key="TestSuite" value="Keystone Tests"/>
- <con:entry key="Report to Generate" value=""/>
- <con:entry key="Password" value=""/>
- <con:entry key="soapui-setings.xml Password" value=""/>
- <con:entry key="TestRunner Path" value=""/>
- <con:entry key="Tool Args" value=""/>
- <con:entry key="Ignore Errors" value="false"/>
- <con:entry key="Host:Port" value=""/>
- <con:entry key="WSS Password Type" value=""/>
- <con:entry key="Save Project" value="false"/>
- <con:entry key="Enable UI" value="true"/>
- <con:entry key="System Properties" value=""/>
- <con:entry key="Domain" value=""/>
- <con:entry key="Coverage Report" value="false"/>
- <con:entry key="Export JUnit Results" value="false"/>
- <con:entry key="Open Report" value="false"/>
- <con:entry key="Project Properties" value=""/>
- <con:entry key="Project Password" value=""/>
- <con:entry key="Export All" value="false"/>
- <con:entry key="Report Format(s)" value=""/>
- <con:entry key="TestCase" value="&lt;all>"/>
- <con:entry key="Print Report" value="false"/>
- <con:entry key="Username" value=""/>
- <con:entry key="Root Folder" value=""/>
- <con:entry key="Save After" value="false"/>
- <con:entry key="Add Settings" value="false"/>
- <con:entry key="Endpoint" value=""/>
-</xml-fragment>]]></con:setting></con:settings><con:interface xsi:type="con:RestService" wadlVersion="http://wadl.dev.java.net/2009/02" name="Keystone" type="rest" basePath="" definitionUrl="file:/Users/jorgew/projects/keystone/keystone/identity.wadl" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:settings/><con:definitionCache type="TEXT" rootPart="file:/Users/jorgew/projects/keystone/keystone/identity.wadl"><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/identity.wadl</con:url><con:content><![CDATA[<application xsi:schemaLocation="http://docs.openstack.org/identity/api/v2.0 xsd/api.xsd http://docs.openstack.org/common/api/v1.0 xsd/api-common.xsd " xmlns="http://wadl.dev.java.net/2009/02" xmlns:identity="http://docs.openstack.org/identity/api/v2.0" xmlns:capi="http://docs.openstack.org/common/api/v1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <grammars>
- <include href="xsd/api.xsd"/>
- <include href="xsd/api-common.xsd"/>
- </grammars>
- <!--We should use SSL in production-->
- <resources base="http://localhost:5000">
- <resource id="version" path="v1.0">
- <method href="#getVersionInfo"/>
- <resource id="extensions" path="extensions">
- <method href="#getExtensions"/>
- <resource id="alias" path="{alias}">
- <param name="alias" style="template" type="xsd:string"/>
- <method href="#getExtension"/>
- </resource>
- </resource>
- <resource id="token" path="token">
- <method href="#authenticate"/>
- <resource id="tokenId" path="{tokenId}">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true"/>
- <param name="tokenId" style="template" type="xsd:string"/>
- <method href="#validateToken"/>
- <method href="#revokeToken"/>
- </resource>
- </resource>
- <resource id="tenants" path="tenants">
- <param name="X-Auth-Token" style="header" type="xsd:string" required="true"/>
- <method href="#getTenants"/>
- <method href="#createTenant"/>
- <resource id="tenantId" path="{tenantId}">
- <param name="tenantId" style="template" type="xsd:string"/>
- <method href="#getTenant"/>
- <method href="#updateTenant"/>
- <method href="#deleteTenant"/>
- </resource>
- </resource>
- </resource>
- </resources>
- <!--Extensions-->
- <method name="GET" id="getExtensions">
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:extensions"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="GET" id="getExtension">
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:extension"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 404 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <!--Version Info-->
- <method name="GET" id="getVersionInfo">
- <response status="200 203">
- <representation mediaType="application/xml" element="capi:version"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <!--Token Operations-->
- <method name="POST" id="authenticate">
- <request>
- <representation mediaType="application/xml" element="identity:passwordCredentials"/>
- <representation mediaType="application/json"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:auth"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:userDisabled"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="401 403 400 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="GET" id="validateToken">
- <request>
- <param name="belongsTo" style="query" required="false" type="xsd:string"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:auth"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- <representation mediaType="application/xml" element="identity:userDisabled"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 401 403 404 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="DELETE" id="revokeToken">
- <response status="204"/>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 401 403 404 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <!--Tenant Operations-->
- <method name="GET" id="getTenants">
- <request>
- <param name="marker" style="query" required="false" type="xsd:string"/>
- <param name="limit" style="query" required="false" type="xsd:int"/>
- </request>
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:tenants"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 401 403 404 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="POST" id="createTenant">
- <request>
- <representation mediaType="application/xml" element="identity:tenant"/>
- <representation mediaType="application/json"/>
- </request>
- <response status="201">
- <representation mediaType="application/xml" element="identity:tenant"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- </response>
- <response status="409">
- <representation mediaType="application/xml" element="identity:tenantConflict"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="401 403 400 409 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="GET" id="getTenant">
- <response status="200 203">
- <representation mediaType="application/xml" element="identity:tenant"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 401 403 404 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="PUT" id="updateTenant">
- <request>
- <representation mediaType="application/xml" element="identity:tenant"/>
- <representation mediaType="application/json"/>
- </request>
- <response status="200">
- <representation mediaType="application/xml" element="identity:tenant"/>
- <representation mediaType="application/json"/>
- </response>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="401 403 404 400 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
- <method name="DELETE" id="deleteTenant">
- <response status="204"/>
- <response status="401">
- <representation mediaType="application/xml" element="identity:unauthorized"/>
- </response>
- <response status="403">
- <representation mediaType="application/xml" element="identity:forbidden"/>
- </response>
- <response status="400">
- <representation mediaType="application/xml" element="identity:badRequest"/>
- </response>
- <response status="404">
- <representation mediaType="application/xml" element="identity:itemNotFound"/>
- </response>
- <response status="500">
- <representation mediaType="application/xml" element="identity:identityFault"/>
- </response>
- <response status="503">
- <representation mediaType="application/xml" element="identity:serviceUnavailable"/>
- </response>
- <response status="400 401 403 404 500 503">
- <representation mediaType="application/json"/>
- </response>
- </method>
-</application>]]></con:content><con:type>http://wadl.dev.java.net/2009/02</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/api.xsd</con:url><con:content>&lt;schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/identity/api/v2.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:identity="http://docs.openstack.org/identity/api/v2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- &lt;include schemaLocation="token.xsd"/>
- &lt;include schemaLocation="tenant.xsd"/>
- &lt;include schemaLocation="fault.xsd"/>
-&lt;/schema></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/token.xsd</con:url><con:content><![CDATA[<schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/identity/api/v2.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:identity="http://docs.openstack.org/identity/api/v2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <!--Elements-->
- <element name="passwordCredentials" type="identity:PasswordCredentials"/>
- <element name="auth" type="identity:AuthData"/>
- <!--Complex Types-->
- <complexType name="Credentials" abstract="true"/>
- <complexType name="PasswordCredentials">
- <complexContent>
- <extension base="identity:Credentials">
- <sequence>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="password" type="xsd:string" use="required"/>
- <attribute name="username" type="xsd:string" use="required"/>
- <attribute name="tenantId" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </extension>
- </complexContent>
- </complexType>
- <complexType name="AuthData">
- <sequence>
- <element name="token" type="identity:Token"/>
- <element name="user" type="identity:User"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="Token">
- <sequence>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="expires" type="xsd:dateTime" use="required"/>
- <attribute name="id" type="xsd:string" use="required"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="User">
- <sequence>
- <element name="groups" type="identity:Groups"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="tenantId" type="xsd:string"/>
- <attribute name="username" type="xsd:string"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="Groups">
- <sequence>
- <element name="group" type="identity:Group" maxOccurs="1000"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="Group">
- <attribute name="id" type="xsd:string" use="required"/>
- <attribute name="tenantId" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/tenant.xsd</con:url><con:content><![CDATA[<schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/identity/api/v2.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:identity="http://docs.openstack.org/identity/api/v2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns:atom="http://www.w3.org/2005/Atom">
- <!--Import ATOM specific schema definitions-->
- <import vc:minVersion="1.1" namespace="http://www.w3.org/2005/Atom" schemaLocation="./atom/atom.xsd"/>
- <!--Elements-->
- <element name="tenant" type="identity:Tenant"/>
- <element name="tenants" type="identity:Tenants"/>
- <!--Complex Types-->
- <complexType name="Tenants">
- <sequence>
- <element name="tenant" type="identity:Tenant" maxOccurs="1000"/>
- <element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="Tenant">
- <sequence>
- <element name="description" type="xsd:string"/>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="enabled" type="xsd:boolean" use="optional" default="true"/>
- <attribute name="id" type="xsd:string" use="optional"/>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
-</schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/atom/atom.xsd</con:url><con:content><![CDATA[<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://www.w3.org/2005/Atom" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xs:import namespace="http://www.w3.org/XML/1998/namespace" schemaLocation="xml.xsd"/>
- <xs:simpleType name="relation">
- <xs:restriction base="xs:string">
- <xs:enumeration value="alternate"/>
- <xs:enumeration value="appendix"/>
- <xs:enumeration value="archives"/>
- <xs:enumeration value="author"/>
- <xs:enumeration value="bookmark"/>
- <xs:enumeration value="chapter"/>
- <xs:enumeration value="contents"/>
- <xs:enumeration value="copyright"/>
- <xs:enumeration value="current"/>
- <xs:enumeration value="describedby"/>
- <xs:enumeration value="edit"/>
- <xs:enumeration value="edit-media"/>
- <xs:enumeration value="first"/>
- <xs:enumeration value="glossary"/>
- <xs:enumeration value="help"/>
- <xs:enumeration value="hub"/>
- <xs:enumeration value="icon"/>
- <xs:enumeration value="index"/>
- <xs:enumeration value="last"/>
- <xs:enumeration value="latest-version"/>
- <xs:enumeration value="license"/>
- <xs:enumeration value="monitor"/>
- <xs:enumeration value="monitor-group"/>
- <xs:enumeration value="next"/>
- <xs:enumeration value="next-arvhice"/>
- <xs:enumeration value="nofollow"/>
- <xs:enumeration value="payment"/>
- <xs:enumeration value="predecessor-version"/>
- <xs:enumeration value="prefetch"/>
- <xs:enumeration value="prev"/>
- <xs:enumeration value="previous"/>
- <xs:enumeration value="prev-archive"/>
- <xs:enumeration value="replies"/>
- <xs:enumeration value="search"/>
- <xs:enumeration value="section"/>
- <xs:enumeration value="self"/>
- <xs:enumeration value="service"/>
- <xs:enumeration value="start"/>
- <xs:enumeration value="stylesheet"/>
- <xs:enumeration value="subsection"/>
- <xs:enumeration value="successor-version"/>
- <xs:enumeration value="up"/>
- <xs:enumeration value="version-history"/>
- <xs:enumeration value="via"/>
- <xs:enumeration value="working-copy"/>
- <xs:enumeration value="working-copy-of"/>
- </xs:restriction>
- </xs:simpleType>
- <xs:element name="link" type="atom:link"/>
- <xs:complexType name="link">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- See section 3.4 of the ATOM RFC
- <html:a href="http://tools.ietf.org/html/rfc4287">RFC4287</html:a>
- </html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:attribute name="rel" use="required" type="atom:relation">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="type" use="optional" type="xs:string">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="href" use="required" type="xs:anyURI">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="hreflang" use="optional" type="xs:NMTOKEN">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="title" use="optional" type="xs:string">
- <xs:annotation>
- <xs:documentation>
- <html:p>TODO</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute ref="xml:base"/>
- <xs:attribute ref="xml:lang"/>
- </xs:complexType>
-</xs:schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/atom/xml.xsd</con:url><con:content><![CDATA[<?xml-stylesheet href="../2008/09/xsd.xsl" type="text/xsl"?>
-<xs:schema targetNamespace="http://www.w3.org/XML/1998/namespace" xml:lang="en" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns="http://www.w3.org/1999/xhtml">
- <xs:annotation>
- <xs:documentation>
- <div>
- <h1>About the XML namespace</h1>
- <div class="bodytext">
- <p>This schema document describes the XML namespace, in a form
- suitable for import by other schema documents.</p>
- <p>
- See
- <a href="http://www.w3.org/XML/1998/namespace.html">http://www.w3.org/XML/1998/namespace.html</a>
- and
- <a href="http://www.w3.org/TR/REC-xml">http://www.w3.org/TR/REC-xml</a>
- for information
- about this namespace.
- </p>
- <p>Note that local names in this namespace are intended to be
- defined only by the World Wide Web Consortium or its subgroups.
- The names currently defined in this namespace are listed below.
- They should not be used with conflicting semantics by any Working
- Group, specification, or document instance.</p>
- <p>
- See further below in this document for more information about
- <a href="#usage">how to refer to this schema document from your own
- XSD schema documents</a>
- and about
- <a href="#nsversioning">the
- namespace-versioning policy governing this schema document</a>
- .
- </p>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:attribute name="lang">
- <xs:annotation>
- <xs:documentation>
- <div>
- <h3>lang (as an attribute name)</h3>
- <p>denotes an attribute whose value
- is a language code for the natural language of the content of
- any element; its value is inherited. This name is reserved
- by virtue of its definition in the XML specification.</p>
- </div>
- <div>
- <h4>Notes</h4>
- <p>Attempting to install the relevant ISO 2- and 3-letter
- codes as the enumerated possible values is probably never
- going to be a realistic possibility.</p>
- <p>
- See BCP 47 at
- <a href="http://www.rfc-editor.org/rfc/bcp/bcp47.txt">http://www.rfc-editor.org/rfc/bcp/bcp47.txt</a>
- and the IANA language subtag registry at
- <a href="http://www.iana.org/assignments/language-subtag-registry">http://www.iana.org/assignments/language-subtag-registry</a>
- for further information.
- </p>
- <p>The union allows for the 'un-declaration' of xml:lang with
- the empty string.</p>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:union memberTypes="xs:language">
- <xs:simpleType>
- <xs:restriction base="xs:string">
- <xs:enumeration value=""/>
- </xs:restriction>
- </xs:simpleType>
- </xs:union>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="space">
- <xs:annotation>
- <xs:documentation>
- <div>
- <h3>space (as an attribute name)</h3>
- <p>denotes an attribute whose
- value is a keyword indicating what whitespace processing
- discipline is intended for the content of the element; its
- value is inherited. This name is reserved by virtue of its
- definition in the XML specification.</p>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:simpleType>
- <xs:restriction base="xs:NCName">
- <xs:enumeration value="default"/>
- <xs:enumeration value="preserve"/>
- </xs:restriction>
- </xs:simpleType>
- </xs:attribute>
- <xs:attribute name="base" type="xs:anyURI">
- <xs:annotation>
- <xs:documentation>
- <div>
- <h3>base (as an attribute name)</h3>
- <p>denotes an attribute whose value
- provides a URI to be used as the base for interpreting any
- relative URIs in the scope of the element on which it
- appears; its value is inherited. This name is reserved
- by virtue of its definition in the XML Base specification.</p>
- <p>
- See
- <a href="http://www.w3.org/TR/xmlbase/">http://www.w3.org/TR/xmlbase/</a>
- for information about this attribute.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="id" type="xs:ID">
- <xs:annotation>
- <xs:documentation>
- <div>
- <h3>id (as an attribute name)</h3>
- <p>denotes an attribute whose value
- should be interpreted as if declared to be of type ID.
- This name is reserved by virtue of its definition in the
- xml:id specification.</p>
- <p>
- See
- <a href="http://www.w3.org/TR/xml-id/">http://www.w3.org/TR/xml-id/</a>
- for information about this attribute.
- </p>
- </div>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attributeGroup name="specialAttrs">
- <xs:attribute ref="xml:base"/>
- <xs:attribute ref="xml:lang"/>
- <xs:attribute ref="xml:space"/>
- <xs:attribute ref="xml:id"/>
- </xs:attributeGroup>
- <xs:annotation>
- <xs:documentation>
- <div>
- <h3>Father (in any context at all)</h3>
- <div class="bodytext">
- <p>denotes Jon Bosak, the chair of
- the original XML Working Group. This name is reserved by
- the following decision of the W3C XML Plenary and
- XML Coordination groups:</p>
- <blockquote>
- <p>In appreciation for his vision, leadership and
- dedication the W3C XML Plenary on this 10th day of
- February, 2000, reserves for Jon Bosak in perpetuity
- the XML name "xml:Father".</p>
- </blockquote>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:annotation>
- <xs:documentation>
- <div xml:id="usage" id="usage">
- <h2>
- <a name="usage">About this schema document</a>
- </h2>
- <div class="bodytext">
- <p>
- This schema defines attributes and an attribute group suitable
- for use by schemas wishing to allow
- <code>xml:base</code>
- ,
- <code>xml:lang</code>
- ,
- <code>xml:space</code>
- or
- <code>xml:id</code>
- attributes on elements they define.
- </p>
- <p>To enable this, such a schema must import this schema for
- the XML namespace, e.g. as follows:</p>
- <pre>&lt;schema . . .>
- . . .
- &lt;import namespace="http://www.w3.org/XML/1998/namespace"
- schemaLocation="http://www.w3.org/2001/xml.xsd"/></pre>
- <p>or</p>
- <pre>&lt;import namespace="http://www.w3.org/XML/1998/namespace"
- schemaLocation="http://www.w3.org/2009/01/xml.xsd"/></pre>
- <p>Subsequently, qualified reference to any of the attributes or the
- group defined below will have the desired effect, e.g.</p>
- <pre>&lt;type . . .>
- . . .
- &lt;attributeGroup ref="xml:specialAttrs"/></pre>
- <p>will define a type which will schema-validate an instance element
- with any of those attributes.</p>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
- <xs:annotation>
- <xs:documentation>
- <div id="nsversioning" xml:id="nsversioning">
- <h2>
- <a name="nsversioning">Versioning policy for this schema document</a>
- </h2>
- <div class="bodytext">
- <p>
- In keeping with the XML Schema WG's standard versioning
- policy, this schema document will persist at
- <a href="http://www.w3.org/2009/01/xml.xsd">http://www.w3.org/2009/01/xml.xsd</a>
- .
- </p>
- <p>
- At the date of issue it can also be found at
- <a href="http://www.w3.org/2001/xml.xsd">http://www.w3.org/2001/xml.xsd</a>
- .
- </p>
- <p>
- The schema document at that URI may however change in the future,
- in order to remain compatible with the latest version of XML
- Schema itself, or with the XML namespace itself. In other words,
- if the XML Schema or XML namespaces change, the version of this
- document at
- <a href="http://www.w3.org/2001/xml.xsd">http://www.w3.org/2001/xml.xsd</a>
- will change accordingly; the version at
- <a href="http://www.w3.org/2009/01/xml.xsd">http://www.w3.org/2009/01/xml.xsd</a>
- will not change.
- </p>
- <p>Previous dated (and unchanging) versions of this schema
- document are at:</p>
- <ul>
- <li>
- <a href="http://www.w3.org/2009/01/xml.xsd">http://www.w3.org/2009/01/xml.xsd</a>
- </li>
- <li>
- <a href="http://www.w3.org/2007/08/xml.xsd">http://www.w3.org/2007/08/xml.xsd</a>
- </li>
- <li>
- <a href="http://www.w3.org/2004/10/xml.xsd">http://www.w3.org/2004/10/xml.xsd</a>
- </li>
- <li>
- <a href="http://www.w3.org/2001/03/xml.xsd">http://www.w3.org/2001/03/xml.xsd</a>
- </li>
- </ul>
- </div>
- </div>
- </xs:documentation>
- </xs:annotation>
-</xs:schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/fault.xsd</con:url><con:content><![CDATA[<schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/identity/api/v2.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:identity="http://docs.openstack.org/identity/api/v2.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <!--Fault Elements-->
- <element name="identityFault" type="identity:IdentityFault"/>
- <element name="serviceUnavailable" type="identity:ServiceUnavailableFault"/>
- <element name="badRequest" type="identity:BadRequestFault"/>
- <element name="unauthorized" type="identity:UnauthorizedFault"/>
- <element name="overLimit" type="identity:OverLimitFault"/>
- <element name="userDisabled" type="identity:UserDisabledFault"/>
- <element name="forbidden" type="identity:ForbiddenFault"/>
- <element name="itemNotFound" type="identity:ItemNotFoundFault"/>
- <element name="tenantConflict" type="identity:TenantConflictFault"/>
- <!--Fault Types-->
- <complexType name="IdentityFault">
- <sequence>
- <element name="message" type="xsd:string">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>A human readable message that is appropriate for display
- to the end user.</p>
- </xsd:documentation>
- </annotation>
- </element>
- <element name="details" type="xsd:string" minOccurs="0">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>The optional &lt;details> element may contain useful
- information for tracking down errors (e.g a stack
- trace). This information may or may not be appropriate
- for display to an end user.</p>
- </xsd:documentation>
- </annotation>
- </element>
- <any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </sequence>
- <attribute name="code" type="xsd:int" use="required">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>The HTTP status code associated with the current fault.</p>
- </xsd:documentation>
- </annotation>
- </attribute>
- <anyAttribute namespace="##other" processContents="lax"/>
- </complexType>
- <complexType name="ServiceUnavailableFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="BadRequestFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="UnauthorizedFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="UserDisabledFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="ForbiddenFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="ItemNotFoundFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="TenantConflictFault">
- <complexContent>
- <extension base="identity:IdentityFault"></extension>
- </complexContent>
- </complexType>
- <complexType name="OverLimitFault">
- <complexContent>
- <extension base="identity:IdentityFault">
- <attribute name="retryAt" type="xsd:dateTime" use="optional">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>An optional dateTime denoting when an operation should
- be retried.</p>
- </xsd:documentation>
- </annotation>
- </attribute>
- </extension>
- </complexContent>
- </complexType>
-</schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/api-common.xsd</con:url><con:content><![CDATA[<?xml-stylesheet type="text/xsl" href="../xslt/schema.xslt"?>
-<!--(C) 2009-2011 Rackspace Hosting, All Rights Reserved-->
-<schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/common/api/v1.0" xmlns="http://www.w3.org/2001/XMLSchema" xmlns:capi="http://docs.openstack.org/common/api/v1.0" xmlns:xsdxt="http://docs.rackspacecloud.com/xsd-ext/v1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <annotation>
- <xsd:appinfo xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <xsdxt:title>Open Stack Common API Schema Types 1.0</xsdxt:title>
- <xsdxt:link rev="index" href="extensions.xsd"/>
- <xsdxt:link rev="index" href="limits.xsd"/>
- <xsdxt:link rev="index" href="version.xsd"/>
- </xsd:appinfo>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>This is the main index XML Schema document
- for Common API Schema Types Version 1.0.</p>
- </xsd:documentation>
- </annotation>
- <include schemaLocation="extensions.xsd">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>Types related to extensions.</p>
- </xsd:documentation>
- </annotation>
- </include>
- <include schemaLocation="version.xsd">
- <annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <p>Types related to API version details.</p>
- </xsd:documentation>
- </annotation>
- </include>
-</schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/extensions.xsd</con:url><con:content><![CDATA[<xsd:schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/common/api/v1.0" xmlns:ext="http://docs.openstack.org/common/api/v1.0" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
- <!--Import ATOM specific schema definitions-->
- <xsd:import namespace="http://www.w3.org/2005/Atom" schemaLocation="./atom/atom.xsd"/>
- <xsd:element name="extensions" type="ext:Extensions"/>
- <xsd:element name="extension" type="ext:Extension"/>
- <xsd:complexType name="Extensions">
- <xsd:sequence>
- <xsd:element name="extension" type="ext:Extension" minOccurs="0" maxOccurs="unbounded"/>
- <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </xsd:sequence>
- <xsd:anyAttribute namespace="##other" processContents="lax"/>
- </xsd:complexType>
- <xsd:complexType name="Extension">
- <xsd:sequence>
- <xsd:element name="description" type="xsd:string" minOccurs="1"/>
- <xsd:element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded"/>
- <xsd:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </xsd:sequence>
- <xsd:attribute name="name" type="xsd:string" use="required"/>
- <xsd:attribute name="namespace" type="xsd:anyURI" use="required"/>
- <xsd:attribute name="alias" type="ext:Alias" use="required"/>
- <xsd:attribute name="updated" type="xsd:dateTime" use="optional"/>
- <xsd:anyAttribute namespace="##other" processContents="lax"/>
- <xsd:assert vc:minVersion="1.1" test="atom:link[@rel='describedby']">
- <xsd:annotation>
- <xsd:documentation xml:lang="EN" xmlns="http://www.w3.org/1999/xhtml">
- <p>There should be at least one atom link
- with a describedby relation.</p>
- </xsd:documentation>
- </xsd:annotation>
- </xsd:assert>
- </xsd:complexType>
- <xsd:simpleType name="Alias">
- <xsd:restriction base="xsd:string">
- <xsd:pattern value="\w+\-\w+"/>
- </xsd:restriction>
- </xsd:simpleType>
-</xsd:schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part><con:part><con:url>file:/Users/jorgew/projects/keystone/keystone/xsd/version.xsd</con:url><con:content><![CDATA[<xs:schema elementFormDefault="qualified" attributeFormDefault="unqualified" targetNamespace="http://docs.openstack.org/common/api/v1.0" xmlns:vers="http://docs.openstack.org/common/api/v1.0" xmlns:vc="http://www.w3.org/2007/XMLSchema-versioning" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:xs="http://www.w3.org/2001/XMLSchema">
- <!--Import ATOM specific schema definitions-->
- <xs:import namespace="http://www.w3.org/2005/Atom" schemaLocation="./atom/atom.xsd"/>
- <!--Multiple choices-->
- <xs:element name="choices" type="vers:VersionChoiceList"/>
- <!--Versioning-->
- <xs:element name="versions" type="vers:VersionChoiceList"/>
- <xs:element name="version" type="vers:VersionChoice" vc:minVersion="1.0" vc:maxVersion="1.1"/>
- <xs:element name="version" type="vers:VersionChoiceRoot" vc:minVersion="1.1"/>
- <!--Types-->
- <xs:simpleType name="VersionStatus">
- <xs:annotation>
- <xs:documentation>
- <html:p>The VersionStatus type describes a service's operational status.</html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:restriction base="xs:string">
- <xs:enumeration value="DEPRECATED"/>
- <xs:enumeration value="ALPHA"/>
- <xs:enumeration value="BETA"/>
- <xs:enumeration value="CURRENT"/>
- </xs:restriction>
- </xs:simpleType>
- <xs:complexType name="VersionChoiceList">
- <xs:annotation>
- <xs:documentation>
- <html:p>A version choice list outlines a collection of service version choices.</html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:element name="version" type="vers:VersionChoice" minOccurs="1" maxOccurs="unbounded"/>
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- <xs:assert vc:minVersion="1.1" test="every $v in vers:version satisfies $v/atom:link[@rel='self']">
- <xs:annotation>
- <xs:documentation>
- <html:p>In version lists, every single version must
- contain at least one self link.</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:assert>
- </xs:complexType>
- <xs:complexType name="VersionChoiceRoot" vc:minVersion="1.1">
- <xs:complexContent>
- <xs:extension base="vers:VersionChoice">
- <xs:assert test="atom:link[@rel='describedby']">
- <xs:annotation>
- <xs:documentation>
- <html:p>When used as a root element, a version choice
- must contain at least one describedby link.</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:assert>
- </xs:extension>
- </xs:complexContent>
- </xs:complexType>
- <xs:complexType name="VersionChoice">
- <xs:annotation>
- <xs:documentation>
- <html:p>A version choice contains relevant information about an available service
- that a user can then use to target a specific version of the service. Note
- that both the descriptive media types and the atom link references are
- not manditory and are offered as message enrichment elements rather
- than message requirements.</html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:element name="media-types" type="vers:MediaTypeList" minOccurs="0" maxOccurs="1"/>
- <xs:element vc:minVersion="1.1" ref="atom:link" minOccurs="0" maxOccurs="unbounded"/>
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- <xs:attribute name="id" type="xs:string" use="required">
- <xs:annotation>
- <xs:documentation>
- <html:p>The ID of a version choice represents the service version's unique
- identifier. This ID is guaranteed to be unique only among the
- service version choices outlined in the VersionChoiceList.</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="status" type="vers:VersionStatus" use="required">
- <xs:annotation>
- <xs:documentation>
- <html:p>A version choice's status describes the current operational state of
- the given service version. The operational status is captured in a
- simple type enumeration called VersionStatus.</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="updated" type="xs:dateTime" use="optional">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- A version choice's updated attribute describes
- the time when the version was updated. The
- time should be updated anytime
- <html:strong>anything</html:strong>
- in the
- version has changed: documentation,
- extensions, bug fixes.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- </xs:complexType>
- <xs:complexType name="MediaTypeList">
- <xs:annotation>
- <xs:documentation>
- <html:p>A MediaTypeList outlines a collection of valid media types for a given
- service version.</html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:element name="media-type" type="vers:MediaType" minOccurs="1" maxOccurs="unbounded"/>
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- </xs:complexType>
- <xs:complexType name="MediaType">
- <xs:annotation>
- <xs:documentation>
- <html:p>A MediaType describes what content types the service version understands.</html:p>
- </xs:documentation>
- </xs:annotation>
- <xs:sequence>
- <xs:any namespace="##other" processContents="lax" minOccurs="0" maxOccurs="unbounded"/>
- </xs:sequence>
- <xs:attribute name="base" type="xs:string" use="optional" default="">
- <xs:annotation>
- <xs:documentation>
- <html:p>The base of a given media type describes the simple MIME type
- that then a more complicated media type can be derived from. These
- types are basic and provide no namespace or version specific
- data are are only provided as a convenience. Because of this the
- base attribute is declared as optional.</html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:attribute name="type" type="xs:string" use="required">
- <xs:annotation>
- <xs:documentation>
- <html:p>
- The type attribute of a MediaType describes the MIME specific
- identifier of the media type in question. This identifier should include
- a vendor namespace (
- <html:a href="http://tools.ietf.org/html/rfc2048">See RFC 2048</html:a>
- )
- as well as a version suffix.
- </html:p>
- </xs:documentation>
- </xs:annotation>
- </xs:attribute>
- <xs:anyAttribute namespace="##other" processContents="lax"/>
- </xs:complexType>
-</xs:schema>]]></con:content><con:type>http://www.w3.org/2001/XMLSchema</con:type></con:part></con:definitionCache><con:endpoints><con:endpoint>http://localhost:5000</con:endpoint></con:endpoints><con:resource name="v1.0" path="v1.0"><con:settings/><con:parameters/><con:resource name="extensions" path="extensions"><con:settings/><con:parameters/><con:resource name="{alias}" path="{alias}"><con:settings/><con:parameters><con:parameter><con:name>alias</con:name><con:value xsi:nil="true"/><con:style>TEMPLATE</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:method name="GET - getExtension" method="GET"><con:settings/><con:parameters/><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200 203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/common/api/v1.0">v1:extension</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200 203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400 404 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="alias" value="RAX-TEST" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:request></con:method></con:resource><con:method name="GET - getExtensions" method="GET"><con:settings/><con:parameters/><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200 203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/common/api/v1.0">v1:extensions</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200 203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:request></con:method></con:resource><con:resource name="token" path="token"><con:settings/><con:parameters/><con:resource name="{tokenId}" path="{tokenId}"><con:settings/><con:parameters><con:parameter required="true"><con:name>X-Auth-Token</con:name><con:value xsi:nil="true"/><con:style>HEADER</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter><con:parameter><con:name>tokenId</con:name><con:value xsi:nil="true"/><con:style>TEMPLATE</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:method name="GET - validateToken" method="GET"><con:settings/><con:parameters><con:parameter><con:name>belongsTo</con:name><con:value xsi:nil="true"/><con:style>QUERY</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200 203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:auth</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200 203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:userDisabled</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400 401 403 404 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
- <con:entry key="belongsTo" value="1234"/>
-</con:parameters></con:request></con:method><con:method name="DELETE - revokeToken" method="DELETE"><con:settings/><con:parameters/><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400 401 403 404 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:5000</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="3u37737"/>
- <con:entry key="X-Auth-Token" value="3838737726"/>
-</con:parameters></con:request></con:method></con:resource><con:method name="POST - authenticate" method="POST"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>application/xml</con:mediaType><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:passwordCredentials</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="REQUEST" id=""><con:mediaType>application/json</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:auth</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:userDisabled</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>401
-403 400 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:5000</con:endpoint><con:request>&lt;passwordCredentials
-password="secrete" username="joeuser"
-xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:request></con:method></con:resource><con:resource name="tenants" path="tenants"><con:settings/><con:parameters><con:parameter required="true"><con:name>X-Auth-Token</con:name><con:value xsi:nil="true"/><con:style>HEADER</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:resource name="{tenantId}" path="{tenantId}"><con:settings/><con:parameters><con:parameter><con:name>tenantId</con:name><con:value xsi:nil="true"/><con:style>TEMPLATE</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:method name="GET - getTenant" method="GET"><con:settings/><con:parameters/><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenant</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400
-401 403 404 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="1234"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:request></con:method><con:method name="PUT - updateTenant" method="PUT"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>application/xml</con:mediaType><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenant</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="REQUEST" id=""><con:mediaType>application/json</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenant</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>401
-403 404 400 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" postQueryString="false"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>New Description&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="1234"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:request></con:method><con:method name="DELETE - deleteTenant" method="DELETE"><con:settings/><con:parameters/><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400
-401 403 404 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="0000"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:request></con:method></con:resource><con:method name="GET - getTenants" method="GET"><con:settings/><con:parameters><con:parameter><con:name>marker</con:name><con:value xsi:nil="true"/><con:style>QUERY</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:string</con:type><con:default xsi:nil="true"/></con:parameter><con:parameter><con:name>limit</con:name><con:value xsi:nil="true"/><con:style>QUERY</con:style><con:type xmlns:xs="http://www.w3.org/2001/XMLSchema">xs:int</con:type><con:default xsi:nil="true"/></con:parameter></con:parameters><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenants</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>404</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:itemNotFound</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400
-401 403 404 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:request></con:method><con:method name="POST - createTenant" method="POST"><con:settings/><con:parameters/><con:representation type="REQUEST" id=""><con:mediaType>application/xml</con:mediaType><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenant</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="REQUEST" id=""><con:mediaType>application/json</con:mediaType><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>201</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenant</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>201</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>401</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:unauthorized</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>403</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:forbidden</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType>
-<con:status>409</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:tenantConflict</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType>
-<con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>401
-403 400 409 500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant
-enabled="true" id="my_new_tenant"
-xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;v1:description>This
-is a description of my tenant. Thank you very
-much.&lt;/v1:description>&lt;/v1:tenant></con:request><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:request></con:method></con:resource><con:method name="GET - getVersionInfo" method="GET"><con:settings/><con:parameters/><con:representation type="RESPONSE" id=""><con:mediaType>application/xml</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/common/api/v1.0">v1:version</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="RESPONSE" id=""><con:mediaType>application/json</con:mediaType><con:status>200
-203</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>400</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:badRequest</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>500</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:identityFault</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/xml</con:mediaType><con:status>503</con:status><con:params/><con:element xmlns:v1="http://docs.openstack.org/identity/api/v2.0">v1:serviceUnavailable</con:element><con:description xsi:nil="true"/></con:representation><con:representation type="FAULT" id=""><con:mediaType>application/json</con:mediaType><con:status>400
-500 503</con:status><con:params/><con:element xsi:nil="true"/><con:description xsi:nil="true"/></con:representation><con:request name="Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:request></con:method></con:resource></con:interface><con:testSuite name="Keystone Tests"><con:settings/><con:runType>SEQUENTIAL</con:runType><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Admin Credential Check" searchProperties="true" id="29b2fa4b-e1c3-49c4-a7e6-334724e74bb9"><con:settings/><con:testStep type="restrequest" name="GET - validateToken - Valid Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Valid Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>auth</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
- <con:entry key="belongsTo" value="1234"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Expired Admin Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Expired Admin Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="377372"/>
- <con:entry key="X-Auth-Token" value="000999"/>
- <con:entry key="belongsTo" value="3334"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Missing Admin Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Missing Admin Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="377372"/>
- <con:entry key="X-Auth-Token" value=" "/>
- <con:entry key="belongsTo" value="3334"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Bad Admin Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Bad Admin Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="377372"/>
- <con:entry key="X-Auth-Token" value="976BAD"/>
- <con:entry key="belongsTo" value="3334"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Joe User Makes Admin Call"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Joe User Makes Admin Call" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>forbidden</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>403</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="377372"/>
- <con:entry key="X-Auth-Token" value="887665443383838"/>
- <con:entry key="belongsTo" value="3334"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Disabled User Makes Admin Call"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Disabled User Makes Admin Call" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>userDisabled</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>403</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="377372"/>
- <con:entry key="X-Auth-Token" value="999888777"/>
- <con:entry key="belongsTo" value="3334"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Validate Token" searchProperties="true" id="e4d9f6ba-f392-4c78-bddc-47fca1fc9b0e"><con:settings/><con:testStep type="restrequest" name="GET - validateToken - Valid Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Valid Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>auth</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
- <con:entry key="belongsTo" value="1234"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Valid Token no belongsTo"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Valid Token no belongsTo" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>auth</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Valid Token bad belongsTo"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Valid Token bad belongsTo" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
- <con:entry key="belongsTo" value="998877665"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Bad Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Bad Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="0009991919"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - Expired Token"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - Expired Token" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="000999"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Authenticate" searchProperties="true" id="6daa3ca5-8855-4181-afd4-151833f786ff"><con:settings/><con:testStep type="restrequest" name="POST - authenticate - Bad Credentials, user doesn't exist"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Bad Credentials, user doesn't exist" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="P@ssword1" username="testuser" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Disabled User"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Disabled User" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="1234" username="disabled" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>403</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>userDisabled</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Bad Credentials, bad password"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Bad Credentials, bad password" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="123774" username="joeuser" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Valid Credentials - Admin"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Valid Credentials - Admin" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="secrete" username="admin" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>Admin</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace auth='http://docs.openstack.org/identity/api/v2.0';
-/auth:auth/auth:user/auth:groups/auth:group/@id='Admin'</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Valid Credentials - Joe User"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Valid Credentials - Joe User" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="secrete" username="joeuser" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple NotContains"><con:configuration><token>Admin</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace auth='http://docs.openstack.org/identity/api/v2.0';
-/auth:auth/auth:user/auth:groups/auth:group/@id='Admin'</path><content>false</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Authenticate (JSON)" searchProperties="true" id="686eabb3-4d04-4f63-a46c-fab41cd1ea62"><con:settings/><con:testStep type="restrequest" name="POST - authenticate - Bad Credentials, user doesn't exist"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Bad Credentials, user doesn't exist" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{
- "passwordCredentials" : {
- "username" : "testuser",
- "password" : "P@ssword1"
- }
-}</con:request><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Disabled User"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Disabled User" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{
- "passwordCredentials" : {
- "username" : "disabled",
- "password" : "1234"
- }
-}</con:request><con:assertion type="Simple Contains"><con:configuration><token>403</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>userDisabled</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Bad Credentials, bad password"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Bad Credentials, bad password" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{
- "passwordCredentials" : {
- "username" : "joeuser",
- "password" : "123774"
- }
-}</con:request><con:assertion type="Simple Contains"><con:configuration><token>401</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>unauthorized</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Valid Credentials - Admin"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Valid Credentials - Admin" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{
- "passwordCredentials" : {
- "username" : "admin",
- "password" : "secrete"
- }
-}</con:request><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>Admin</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Valid Credentials - Joe User"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Valid Credentials - Joe User" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{
- "passwordCredentials" : {
- "username" : "joeuser",
- "password" : "secrete"
- }
-}</con:request><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple NotContains"><con:configuration><token>Admin</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Revoke Token" searchProperties="true" id="f10219b1-055a-4cf4-aeb3-4172bd596979"><con:settings/><con:testStep type="restrequest" name="DELETE - revokeToken - token doesn't exist"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="DELETE - revokeToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="DELETE - revokeToken - token doesn't exist" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="3u37737"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Valid Credentials - Joe User, old Token?"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Valid Credentials - Joe User, old Token?" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="secrete" username="joeuser" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple NotContains"><con:configuration><token>Admin</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace auth='http://docs.openstack.org/identity/api/v2.0';
-/auth:auth/auth:user/auth:groups/auth:group/@id='Admin'</path><content>false</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace auth='http://docs.openstack.org/identity/api/v2.0';
-/auth:auth/auth:token/@id</path><content>887665443383838</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="DELETE - revokeToken - Joe User"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="DELETE - revokeToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="DELETE - revokeToken - Joe User" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="GroovyScriptAssertion"><con:configuration><scriptText>assert(context.response==null)</scriptText></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - validateToken - old Token, Bad?"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens/{tokenId}" methodName="GET - validateToken" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - validateToken - old Token, Bad?" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tokenId" value="887665443383838"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - authenticate - Valid Credentials - Joe User, new Token?"><con:settings/><con:config service="Keystone" resourcePath="/v2.0/tokens" methodName="POST - authenticate" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - authenticate - Valid Credentials - Joe User, new Token?" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;passwordCredentials password="secrete" username="joeuser" xmlns="http://docs.openstack.org/identity/api/v2.0"/></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>user</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>token</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple NotContains"><con:configuration><token>Admin</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace auth='http://docs.openstack.org/identity/api/v2.0';
-/auth:auth/auth:user/auth:groups/auth:group/@id='Admin'</path><content>false</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace auth='http://docs.openstack.org/identity/api/v2.0';
-/auth:auth/auth:token/@id="887665443383838"</path><content>false</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Tenant Create" searchProperties="true" id="ec537986-d739-4ade-a2f6-f0fca19b876e"><con:settings/><con:testStep type="restrequest" name="POST - createTenant - New Tenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" id="my_new_tenant" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;v1:description>This is a description of my tenant. Thank you very much.&lt;/v1:description>&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@enabled = "true" and /ns1:tenant/@id="my_new_tenant" and /ns1:tenant/ns1:description = "This is a description of my tenant. Thank you very much."</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant, same id"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant, same id" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" id="my_new_tenant" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;v1:description>This is a description of my tenant. Thank you very much.&lt;/v1:description>&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>tenantConflict</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>409</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Disabled Tenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Disabled Tenant" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="false" id="mt2" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;v1:description>New Disabled Tenant&lt;/v1:description>&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@enabled = "false" and /ns1:tenant/@id="mt2" and /ns1:tenant/ns1:description = "New Disabled Tenant"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant No Enable"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant No Enable" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant id="mt3" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;v1:description>New Tenant 3&lt;/v1:description>&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="mt3" and /ns1:tenant/ns1:description = "New Tenant 3"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant No ID"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant No ID" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;v1:description>New Tenant No ID&lt;/v1:description>&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>400</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>badRequest</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant no Description"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant no Description" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" id="my_new_tenant" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>400</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>badRequest</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Tenant Create (JSON)" searchProperties="true" id="8e95cb90-ef1b-4f0e-a882-09a4a43dd01f"><con:settings/><con:testStep type="restrequest" name="POST - createTenant - New Tenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "id": "JGroup",
- "description": "A description ...",
- "enabled": true
- }
-}
-</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/tenants';
-ns1:Response/ns1:tenant/ns1:id="JGroup" and ns1:Response/ns1:tenant/ns1:enabled="true" and ns1:Response/ns1:tenant/ns1:description="A description ..."</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant, same id"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant, same id" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "id": "JGroup",
- "description": "A description ...",
- "enabled": true
- }
-}</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>tenantConflict</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>409</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Disabled Tenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Disabled Tenant" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "id": "JGroup33",
- "description": "A description...",
- "enabled": false
- }
-}</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/tenants';
-ns1:Response/ns1:tenant/ns1:id = "JGroup33" and ns1:Response/ns1:tenant/ns1:enabled="false" and ns1:Response/ns1:tenant/ns1:description="A description..."</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant No Enable"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant No Enable" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "id": "JGroup65",
- "description": "A description..."
- }
-}</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/tenants';
-ns1:Response/ns1:tenant/ns1:id = "JGroup65" and ns1:Response/ns1:tenant/ns1:description = "A description..."</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant No ID"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant No ID" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "description": "A description...",
- "enabled" : true
- }
-}</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>400</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>badRequest</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant no Description"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant no Description" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "id": "JGroup95",
- "enabled": true
- }
-}</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>400</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>badRequest</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="POST - createTenant - New Tenant Bad Enabled"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant Bad Enabled" mediaType="application/json" postQueryString="false" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>{"tenant":
- {
- "id": "JGroup95",
- "description" : "A description...",
- "enabled": "true"
- }
-}</con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>400</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains"><con:configuration><token>badRequest</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Get Tenants" searchProperties="true" id="3465716c-ff9c-4dea-8444-ae70e8144571"><con:settings/><con:testStep type="restrequest" name="GET - getTenants"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="GET - getTenants" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenants" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-count(//ns1:tenant)</path><content>8</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenants (JSON)"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="GET - getTenants" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenants (JSON)" mediaType="application/xml" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/tenants';
-count(//ns1:e)</path><content>8</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:properties/><con:reportParameters/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Get Tenant" searchProperties="true" id="e66665ad-46b4-45d2-a8e4-761dbb12fd1c"><con:settings/><con:testStep type="restrequest" name="GET - getTenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant - Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-ns1:tenant/@id</path><content>1234</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath (enabled and description)"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@enabled and /ns1:tenant/ns1:description</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="1234"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant (JSON)"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant (JSON)" mediaType="application/xml" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/tenants/1234';
-ns1:Response/ns1:tenant/ns1:id</path><content>1234</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath (enabled and description)"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/tenants/1234';
-/ns1:Response/ns1:tenant/ns1:enabled and /ns1:Response/ns1:tenant/ns1:description</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="1234"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant, Not Found"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant, Not Found" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains itemNotFound"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="88273666219200"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:properties/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Delete Tenant" searchProperties="true" id="65633524-fcae-4006-b838-e02a1077e3f7"><con:settings/><con:testStep type="restrequest" name="POST - createTenant - New Tenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" id="to_delete"
- xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>To Be Deleted&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@enabled = "true" and /ns1:tenant/@id="to_delete" and /ns1:tenant/ns1:description = "To Be Deleted"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="Copy of GET - getTenant" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-ns1:tenant/@id</path><content>to_delete</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath (enabled and description)"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@enabled and /ns1:tenant/ns1:description</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_delete"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="DELETE - deleteTenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="DELETE - deleteTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="DELETE - deleteTenant - Request 1" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="GroovyScriptAssertion" name="Script Assertion"><con:configuration><scriptText>assert(context.response == null)</scriptText></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_delete"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant, Not Found"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="Copy of GET - getTenant, Not Found" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains itemNotFound"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_delete"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="DELETE - deleteTenant, not empty - user"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="DELETE - deleteTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="DELETE - deleteTenant, not empty - user" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains" name="Contains - forbidden"><con:configuration><token>forbidden</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains - 403"><con:configuration><token>403</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="1234"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="DELETE - deleteTenant, not empty - group"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="DELETE - deleteTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="DELETE - deleteTenant, not empty - group" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Simple Contains" name="Contains - forbidden"><con:configuration><token>forbidden</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains - 403"><con:configuration><token>403</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="0000"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:properties/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Update Tenant" searchProperties="true" id="60b728bc-d3d5-46f0-84bf-a12d6a443d1a"><con:settings/><con:testStep type="restrequest" name="POST - createTenant - New Tenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants" methodName="POST - createTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="POST - createTenant - New Tenant" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" id="to_update" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>ToUpdate&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@enabled = "true" and /ns1:tenant/@id="to_update" and /ns1:tenant/ns1:description = "ToUpdate"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="X-Auth-Token" value="999888777666" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "true" and /ns1:tenant/@id="to_update" and /ns1:tenant/ns1:description = "ToUpdate"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="PUT - updateTenant - Description"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="PUT - updateTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="PUT - updateTenant - Description" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>ToUpdate2&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "true" and /ns1:tenant/ns1:description = "ToUpdate2"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant - New Description?"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant - New Description?" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "true" and /ns1:tenant/@id="to_update" and /ns1:tenant/ns1:description = "ToUpdate2"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="PUT - updateTenant - Enabled"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="PUT - updateTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="PUT - updateTenant - Enabled" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="false" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>ToUpdate2&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "false" and /ns1:tenant/ns1:description = "ToUpdate2"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant - New Enable?"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant - New Enable?" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "false" and /ns1:tenant/@id="to_update" and /ns1:tenant/ns1:description = "ToUpdate2"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="PUT - updateTenant - ID, should ignore"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="PUT - updateTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="PUT - updateTenant - ID, should ignore" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant id="boogabooga" enabled="false" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>ToUpdate2&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "false" and /ns1:tenant/ns1:description = "ToUpdate2"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant - New ID ignored?"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant - New ID ignored?" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "false" and /ns1:tenant/@id="to_update" and /ns1:tenant/ns1:description = "ToUpdate2"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="PUT - updateTenant - Enabled and Description"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="PUT - updateTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="PUT - updateTenant - Enabled and Description" mediaType="application/xml" postQueryString="false" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request>&lt;v1:tenant enabled="true" xmlns:v1="http://docs.openstack.org/identity/api/v2.0">
- &lt;v1:description>ToUpdate3&lt;/v1:description>
-&lt;/v1:tenant></con:request><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "true" and /ns1:tenant/ns1:description = "ToUpdate3"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getTenant - New Changes?"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="GET - getTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getTenant - New Changes?" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/identity/api/v2.0';
-/ns1:tenant/@id="to_update" and /ns1:tenant/@enabled = "true" and /ns1:tenant/@id="to_update" and /ns1:tenant/ns1:description = "ToUpdate3"</path><content>true</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="DELETE - deleteTenant"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/tenants/{tenantId}" methodName="DELETE - deleteTenant" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="DELETE - deleteTenant" mediaType="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;entry key="Accept" value="application/xml" xmlns="http://eviware.com/soapui/config"/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="GroovyScriptAssertion" name="Script Assertion"><con:configuration><scriptText>assert(context.response == null)</scriptText></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters>
- <con:entry key="tenantId" value="to_update"/>
- <con:entry key="X-Auth-Token" value="999888777666"/>
-</con:parameters></con:restRequest></con:config></con:testStep><con:properties/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Extensions" searchProperties="true" id="038f320e-bf1f-42e6-a953-33c166d7619e"><con:settings/><con:testStep type="restrequest" name="GET - getExtensions"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/extensions" methodName="GET - getExtensions" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getExtensions" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/common/api/v1.0';
-count(/ns1:extensions)</path><content>1</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getExtensions (JSON)"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/extensions" methodName="GET - getExtensions" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getExtensions (JSON)" mediaType="application/xml" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0/extensions';
-count(//ns1:extensions)</path><content>1</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getExtension"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/extensions/{alias}" methodName="GET - getExtension" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getExtension - Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains itemNotFound"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="alias" value="RAX-TEST" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getExtension (JSON)"><con:settings/><con:config service="Keystone" resourcePath="/v1.0/extensions/{alias}" methodName="GET - getExtension" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getExtension (JSON)" mediaType="application/xml" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains"><con:configuration><token>404</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:assertion type="Simple Contains" name="Contains itemNotFound"><con:configuration><token>itemNotFound</token><ignoreCase>false</ignoreCase><useRegEx>false</useRegEx></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters><entry key="alias" value="RAX-TEST" xmlns="http://eviware.com/soapui/config"/></con:parameters></con:restRequest></con:config></con:testStep><con:properties/></con:testCase><con:testCase failOnError="true" failTestCaseOnErrors="true" keepSession="false" maxResults="0" name="Version Info" searchProperties="true" id="99db3dab-53de-44f5-93cd-099c8850fd97"><con:settings/><con:testStep type="restrequest" name="GET - getVersionInfo"><con:settings/><con:config service="Keystone" resourcePath="/v1.0" methodName="GET - getVersionInfo" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getVersionInfo - Request 1" mediaType="application/xml" accept="application/xml"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://docs.openstack.org/common/api/v1.0';
-count(//ns1:version)</path><content>1</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:testStep type="restrequest" name="GET - getVersionInfo (JSON)"><con:settings/><con:config service="Keystone" resourcePath="/v1.0" methodName="GET - getVersionInfo" xsi:type="con:RestRequestStep" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"><con:restRequest name="GET - getVersionInfo (JSON)" mediaType="application/xml" accept="application/json"><con:settings><con:setting id="com.eviware.soapui.impl.wsdl.WsdlRequest@request-headers">&lt;xml-fragment/></con:setting></con:settings><con:endpoint>http://localhost:8080</con:endpoint><con:request/><con:assertion type="Schema Compliance" name="Schema Compliance"><con:configuration><definition/></con:configuration></con:assertion><con:assertion type="XPath Match" name="XPath Match"><con:configuration><path>declare namespace ns1='http://localhost/v1.0';
-count(//ns1:version)</path><content>1</content><allowWildcards>false</allowWildcards><ignoreNamspaceDifferences>false</ignoreNamspaceDifferences></con:configuration></con:assertion><con:jmsConfig JMSDeliveryMode="PERSISTENT"/><con:jmsPropertyConfig/><con:parameters/></con:restRequest></con:config></con:testStep><con:properties/></con:testCase><con:properties/><con:reportParameters/></con:testSuite><con:requirements/><con:properties/><con:wssContainer/><con:databaseConnectionContainer/><con:reporting><con:xmlTemplates/><con:parameters/></con:reporting></con:soapui-project> \ No newline at end of file
diff --git a/keystone/test/__init__.py b/keystone/test/__init__.py
deleted file mode 100644
index 26c4d9b3..00000000
--- a/keystone/test/__init__.py
+++ /dev/null
@@ -1,723 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# All Rights Reserved.
-#
-# 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.
-
-# Colorizer Code is borrowed from Twisted:
-# Copyright (c) 2001-2010 Twisted Matrix Laboratories.
-#
-# Permission is hereby granted, free of charge, to any person obtaining
-# a copy of this software and associated documentation files (the
-# "Software"), to deal in the Software without restriction, including
-# without limitation the rights to use, copy, modify, merge, publish,
-# distribute, sublicense, and/or sell copies of the Software, and to
-# permit persons to whom the Software is furnished to do so, subject to
-# the following conditions:
-#
-# The above copyright notice and this permission notice shall be
-# included in all copies or substantial portions of the Software.
-#
-# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-#
-# Code copied from Nova and other OpenStack projects:
-# Colorizers
-# Classes starting with Nova
-# other setup and initialization code
-#
-""" Module that handles starting the Keystone server and running
-test suites"""
-
-import heapq
-import logging
-from nose import config as noseconfig
-from nose import core
-from nose import result
-import optparse
-import os
-import sys
-import tempfile
-import time
-import unittest
-
-import keystone
-import keystone.server
-import keystone.version
-from keystone import config as config_module
-from keystone.common import config
-from keystone.test import utils
-from keystone.test import client as client_tests
-from keystone import utils as main_utils
-
-TEST_DIR = os.path.abspath(os.path.dirname(__file__))
-BASE_DIR = os.path.abspath(os.path.join(TEST_DIR, os.pardir, os.pardir))
-TEST_CERT = os.path.join(BASE_DIR, 'examples/ssl/certs/middleware-key.pem')
-
-logger = logging.getLogger(__name__)
-
-CONF = config_module.CONF
-
-
-class _AnsiColorizer(object):
- """
- A colorizer is an object that loosely wraps around a stream, allowing
- callers to write text to the stream in a particular color.
-
- Colorizer classes must implement C{supported()} and C{write(text, color)}.
- """
- _colors = dict(black=30, red=31, green=32, yellow=33,
- blue=34, magenta=35, cyan=36, white=37)
-
- def __init__(self, stream):
- self.stream = stream
-
- def supported(cls, stream=sys.stdout):
- """
- A class method that returns True if the current platform supports
- coloring terminal output using this method. Returns False otherwise.
- """
- if not stream.isatty():
- return False # auto color only on TTYs
- try:
- import curses
- except ImportError:
- return False
- else:
- try:
- try:
- return curses.tigetnum("colors") > 2
- except curses.error:
- curses.setupterm()
- return curses.tigetnum("colors") > 2
- except:
- raise
- # guess false in case of error
- return False
- supported = classmethod(supported)
-
- def write(self, text, color):
- """
- Write the given text to the stream in the given color.
-
- @param text: Text to be written to the stream.
-
- @param color: A string label for a color. e.g. 'red', 'white'.
- """
- color = self._colors[color]
- self.stream.write('\x1b[%s;1m%s\x1b[0m' % (color, text))
-
-
-class _Win32Colorizer(object):
- """
- See _AnsiColorizer docstring.
- """
- def __init__(self, stream):
- from win32console import GetStdHandle, STD_OUT_HANDLE, \
- FOREGROUND_RED, FOREGROUND_BLUE, FOREGROUND_GREEN, \
- FOREGROUND_INTENSITY
- red, green, blue, bold = (FOREGROUND_RED, FOREGROUND_GREEN,
- FOREGROUND_BLUE, FOREGROUND_INTENSITY)
- self.stream = stream
- self.screenBuffer = GetStdHandle(STD_OUT_HANDLE)
- self._colors = {
- 'normal': red | green | blue,
- 'red': red | bold,
- 'green': green | bold,
- 'blue': blue | bold,
- 'yellow': red | green | bold,
- 'magenta': red | blue | bold,
- 'cyan': green | blue | bold,
- 'white': red | green | blue | bold
- }
-
- def supported(cls, stream=sys.stdout):
- try:
- import win32console
- screenBuffer = win32console.GetStdHandle(
- win32console.STD_OUT_HANDLE)
- except ImportError:
- return False
- import pywintypes
- try:
- screenBuffer.SetConsoleTextAttribute(
- win32console.FOREGROUND_RED |
- win32console.FOREGROUND_GREEN |
- win32console.FOREGROUND_BLUE)
- except pywintypes.error:
- return False
- else:
- return True
- supported = classmethod(supported)
-
- def write(self, text, color):
- color = self._colors[color]
- self.screenBuffer.SetConsoleTextAttribute(color)
- self.stream.write(text)
- self.screenBuffer.SetConsoleTextAttribute(self._colors['normal'])
-
-
-class _NullColorizer(object):
- """
- See _AnsiColorizer docstring.
- """
- def __init__(self, stream):
- self.stream = stream
-
- def supported(cls, stream=sys.stdout):
- return True
- supported = classmethod(supported)
-
- def write(self, text, color):
- self.stream.write(text)
-
-
-def get_elapsed_time_color(elapsed_time):
- if elapsed_time > 1.0:
- return 'red'
- elif elapsed_time > 0.25:
- return 'yellow'
- else:
- return 'green'
-
-
-class NovaTestResult(result.TextTestResult):
- def __init__(self, *args, **kw):
- self.show_elapsed = kw.pop('show_elapsed')
- result.TextTestResult.__init__(self, *args, **kw)
- self.num_slow_tests = 5
- self.slow_tests = [] # this is a fixed-sized heap
- self._last_case = None
- self.colorizer = None
- # NOTE(vish): reset stdout for the terminal check
- stdout = sys.stdout
- sys.stdout = sys.__stdout__
- for colorizer in [_Win32Colorizer, _AnsiColorizer, _NullColorizer]:
- if colorizer.supported():
- self.colorizer = colorizer(self.stream)
- break
- sys.stdout = stdout
-
- # NOTE(lorinh): Initialize start_time in case a sqlalchemy-migrate
- # error results in it failing to be initialized later. Otherwise,
- # _handleElapsedTime will fail, causing the wrong error message to
- # be outputted.
- self.start_time = time.time()
-
- def getDescription(self, test):
- return str(test)
-
- def _handleElapsedTime(self, test):
- self.elapsed_time = time.time() - self.start_time
- item = (self.elapsed_time, test)
- # Record only the n-slowest tests using heap
- if len(self.slow_tests) >= self.num_slow_tests:
- heapq.heappushpop(self.slow_tests, item)
- else:
- heapq.heappush(self.slow_tests, item)
-
- def _writeElapsedTime(self, test):
- color = get_elapsed_time_color(self.elapsed_time)
- self.colorizer.write(" %.2f" % self.elapsed_time, color)
-
- def _writeResult(self, test, long_result, color, short_result, success):
- if self.showAll:
- self.colorizer.write(long_result, color)
- if self.show_elapsed and success:
- self._writeElapsedTime(test)
- self.stream.writeln()
- elif self.dots:
- self.stream.write(short_result)
- self.stream.flush()
-
- # NOTE(vish): copied from unittest with edit to add color
- def addSuccess(self, test):
- unittest.TestResult.addSuccess(self, test)
- self._handleElapsedTime(test)
- self._writeResult(test, 'OK', 'green', '.', True)
-
- # NOTE(vish): copied from unittest with edit to add color
- def addFailure(self, test, err):
- unittest.TestResult.addFailure(self, test, err)
- self._handleElapsedTime(test)
- self._writeResult(test, 'FAIL', 'red', 'F', False)
-
- # NOTE(vish): copied from nose with edit to add color
- def addError(self, test, err):
- """Overrides normal addError to add support for
- errorClasses. If the exception is a registered class, the
- error will be added to the list for that class, not errors.
- """
- self._handleElapsedTime(test)
- stream = getattr(self, 'stream', None)
- ec, ev, tb = err
- try:
- exc_info = self._exc_info_to_string(err, test)
- except TypeError:
- # 2.3 compat
- exc_info = self._exc_info_to_string(err)
- for cls, (storage, label, isfail) in self.errorClasses.items():
- if result.isclass(ec) and issubclass(ec, cls):
- if isfail:
- test.passed = False
- storage.append((test, exc_info))
- # Might get patched into a streamless result
- if stream is not None:
- if self.showAll:
- message = [label]
- detail = result._exception_detail(err[1])
- if detail:
- message.append(detail)
- stream.writeln(": ".join(message))
- elif self.dots:
- stream.write(label[:1])
- return
- self.errors.append((test, exc_info))
- test.passed = False
- if stream is not None:
- self._writeResult(test, 'ERROR', 'red', 'E', False)
-
- def startTest(self, test):
- unittest.TestResult.startTest(self, test)
- self.start_time = time.time()
- current_case = test.test.__class__.__name__
-
- if self.showAll:
- if current_case != self._last_case:
- self.stream.writeln(current_case)
- self._last_case = current_case
-
- self.stream.write(
- ' %s' % str(test.test._testMethodName).ljust(60))
- self.stream.flush()
-
-
-class NovaTestRunner(core.TextTestRunner):
- def __init__(self, *args, **kwargs):
- self.show_elapsed = kwargs.pop('show_elapsed')
- core.TextTestRunner.__init__(self, *args, **kwargs)
-
- def _makeResult(self):
- return NovaTestResult(self.stream,
- self.descriptions,
- self.verbosity,
- self.config,
- show_elapsed=self.show_elapsed)
-
- def _writeSlowTests(self, result_):
- # Pare out 'fast' tests
- slow_tests = [item for item in result_.slow_tests
- if get_elapsed_time_color(item[0]) != 'green']
- if slow_tests:
- slow_total_time = sum(item[0] for item in slow_tests)
- self.stream.writeln("Slowest %i tests took %.2f secs:"
- % (len(slow_tests), slow_total_time))
- for elapsed_time, test in sorted(slow_tests, reverse=True):
- time_str = "%.2f" % elapsed_time
- self.stream.writeln(" %s %s" % (time_str.ljust(10), test))
-
- def run(self, test):
- result_ = core.TextTestRunner.run(self, test)
- if self.show_elapsed:
- self._writeSlowTests(result_)
- return result_
-
-
-class KeystoneTest(object):
- """Primary test class for invoking keystone tests. Controls
- initialization of environment with temporary configuration files,
- starts keystone admin and service API WSIG servers, and then uses
- :py:mod:`unittest2` to discover and iterate over existing tests.
-
- :py:class:`keystone.test.KeystoneTest` is expected to be
- subclassed and invoked in ``run_tests.py`` where subclasses define
- a config_name (that matches a template existing in
- ``keystone/test/etc``) and test_files (that are cleared at the
- end of test execution from the temporary space used to run these
- tests).
- """
- config_params = {'test_dir': TEST_DIR, 'base_dir': BASE_DIR}
- isSsl = False
- hpidmDisabled = False
- config_name = None
- test_files = None
- server = None
- admin_server = None
- conf_fp = None
- directory_base = None
-
- def clear_database(self):
- """Remove any test databases or files generated by previous tests."""
- if self.test_files:
- for fname in self.test_files:
- paths = [os.path.join(os.curdir, fname),
- os.path.join(os.getcwd(), fname),
- os.path.join(TEST_DIR, fname)]
- for fpath in paths:
- if os.path.exists(fpath):
- logger.debug("Removing test file %s" % fname)
- os.unlink(fpath)
-
- def construct_temp_conf_file(self):
- """Populates a configuration template, and writes to a file pointer."""
- template_fpath = os.path.join(TEST_DIR, 'etc', self.config_name)
- conf_contents = open(template_fpath).read()
- self.config_params['service_port'] = utils.get_unused_port()
- logger.debug("Assigned port %s to service" %
- self.config_params['service_port'])
- self.config_params['admin_port'] = utils.get_unused_port()
- logger.debug("Assigned port %s to admin" %
- self.config_params['admin_port'])
-
- conf_contents = conf_contents % self.config_params
- self.conf_fp = tempfile.NamedTemporaryFile()
- self.conf_fp.write(conf_contents)
- self.conf_fp.flush()
- logger.debug("Create test configuration file: %s" % self.conf_fp.name)
- client_tests.TEST_CONFIG_FILE_NAME = self.conf_fp.name
-
- def setUp(self):
- pass
-
- def startServer(self):
- """ Starts a Keystone server on random ports for testing """
- self.server = None
- self.admin_server = None
-
- self.construct_temp_conf_file()
-
- # Set client certificate for test client
- if self.isSsl:
- logger.debug("SSL testing will use cert_file %s" % TEST_CERT)
- os.environ['cert_file'] = TEST_CERT
- else:
- if 'cert_file' in os.environ:
- del os.environ['cert_file']
-
- # indicating HP-IDM is disabled
- if self.hpidmDisabled:
- logger.debug("HP-IDM extensions is disabled")
- os.environ['HP-IDM_Disabled'] = 'True'
- else:
- if 'HP-IDM_Disabled' in os.environ:
- del os.environ['HP-IDM_Disabled']
-
- # run the keystone server
- logger.info("Starting the keystone server...")
-
- class SilentOptParser(optparse.OptionParser):
- """ Class used to prevent OptionParser from exiting when it detects
- options coming in for nose/testing """
- def exit():
- pass
-
- def error(self, msg):
- pass
-
- parser = SilentOptParser(version='%%prog %s' %
- keystone.version.version())
- common_group = config.add_common_options(parser)
- config.add_log_options(parser)
-
- # Handle a special argument to support starting two endpoints
- common_group.add_option(
- '-a', '--admin-port', dest="admin_port", metavar="PORT",
- help="specifies port for Admin API to listen "
- "on (default is 35357)")
-
- # Parse arguments and load config
- (options, args) = config.parse_options(parser)
- options['config_file'] = self.conf_fp.name
-
- # Populate the CONF module
- CONF.reset()
- CONF(config_files=[self.conf_fp.name])
-
- try:
- # Load Service API Server
- service = keystone.server.Server(name="Service API",
- config_name='keystone-legacy-auth',
- args=args)
- service.start(wait=False)
-
- # Client tests will use these globals to find out where
- # the server is
- client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL = service.protocol
- client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS = service.host
- client_tests.TEST_TARGET_SERVER_SERVICE_PORT = service.port
-
- except RuntimeError, e:
- logger.exception(e)
- raise e
-
- try:
- # Load Admin API server
- port = int(CONF.admin_port or
- client_tests.TEST_TARGET_SERVER_ADMIN_PORT)
- host = (CONF.admin_host or
- client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS)
- admin = keystone.server.Server(name='Admin API',
- config_name='admin', args=args)
- admin.start(host=host, port=port, wait=False)
-
- # Client tests will use these globals to find out where
- # the server is
- client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL = admin.protocol
- client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS = admin.host
- client_tests.TEST_TARGET_SERVER_ADMIN_PORT = admin.port
-
- except RuntimeError, e:
- logger.exception(e)
- raise e
-
- self.server = service
- self.admin_server = admin
-
- # Load bootstrap data
- from keystone import manage
- manage_args = ['--config-file', self.conf_fp.name]
- manage.parse_args(args=manage_args)
-
- #TODO(zns): this should end up being run by a 'bootstrap' script
- fixtures = [
- ('role', 'add', CONF.keystone_admin_role),
- ('user', 'add', 'admin', 'secrete'),
- ('role', 'grant', CONF.keystone_admin_role, 'admin'),
- ('role', 'add', CONF.keystone_service_admin_role),
- ('role', 'add', 'Member'),
- ]
- for cmd in fixtures:
- manage.process(*cmd)
-
- def tearDown(self):
- try:
- if self.server is not None:
- print "Stopping the Service API..."
- self.server.stop()
- self.server = None
- if self.admin_server is not None:
- print "Stopping the Admin API..."
- self.admin_server.stop()
- self.admin_server = None
- if self.conf_fp:
- self.conf_fp.close()
- self.conf_fp = None
- except Exception as e:
- logger.exception(e)
- print "Error cleaning up %s" % e
- raise e
- finally:
- self.clear_database()
- if 'cert_file' in os.environ:
- del os.environ['cert_file']
- if 'HP-IDM_Disabled' in os.environ:
- del os.environ['HP-IDM_Disabled']
- reload(client_tests)
-
- def run(self, args=None):
- try:
- print 'Running test suite: %s' % self.__class__.__name__
-
- self.setUp()
-
- # discover and run tests
-
- # If any argument looks like a test name but doesn't have
- # "keystone.test" in front of it, automatically add that so we
- # don't have to type as much
- show_elapsed = True
- argv = []
- if args is None:
- args = sys.argv
- has_base = False
- for x in args:
- if x.startswith(('functional', 'unit', 'client')):
- argv.append('keystone.test.%s' % x)
- has_base = True
- elif x.startswith('--hide-elapsed'):
- show_elapsed = False
- elif x.startswith('-'):
- argv.append(x)
- else:
- argv.append(x)
- if x != args[0]:
- has_base = True
-
- if not has_base and self.directory_base is not None:
- argv.append(self.directory_base)
- argv = ['--no-path-adjustment'] + argv[1:]
- logger.debug("Running set of tests with args=%s" % argv)
-
- c = noseconfig.Config(stream=sys.stdout,
- env=os.environ,
- verbosity=3,
- workingDir=TEST_DIR,
- plugins=core.DefaultPluginManager(),
- args=argv)
-
- runner = NovaTestRunner(stream=c.stream,
- verbosity=c.verbosity,
- config=c,
- show_elapsed=show_elapsed)
-
- result = not core.run(config=c, testRunner=runner, argv=argv)
- return int(result) # convert to values applicable to sys.exit()
- except Exception, exc:
- logger.exception(exc)
- raise exc
- finally:
- self.tearDown()
-
-
-def runtests():
- """This function can be called from 'python setup.py test'."""
- return SQLTest().run()
-
-
-class UnitTests(KeystoneTest):
- """ Class that runs unit tests """
- directory_base = 'unit'
-
- def run(self):
- """ Run unit tests
-
- Filters arguments and leaves only ones relevant to unit tests
- """
-
- argv = []
- scoped_to_unit = False
- for x in sys.argv:
- if x.startswith(('functional', 'client')):
- # Skip, since we're not running unit tests
- return
- elif x.startswith('unit'):
- argv.append('keystone.test.%s' % x)
- scoped_to_unit = True
- else:
- argv.append(x)
-
- if not scoped_to_unit:
- argv.append('keystone.test.unit')
-
- return super(UnitTests, self).run(args=argv)
-
-
-class ClientTests(KeystoneTest):
- """ Class that runs client tests
-
- Client tests are the tests that need a running http[s] server running
- and make web service calls to that server
-
- """
- config_name = 'sql.conf.template'
- directory_base = 'client'
-
- def run(self):
- """ Run client tests
-
- Filters arguments and leaves only ones relevant to client tests
- """
-
- argv = []
- scoped_to_client = False
- for x in sys.argv:
- if x.startswith(('functional', 'unit')):
- # Skip, since we're not running client tests
- return
- elif x.startswith('client'):
- argv.append('keystone.test.%s' % x)
- scoped_to_client = True
- else:
- argv.append(x)
-
- if not scoped_to_client:
- argv.append('keystone.test.client')
-
- self.startServer()
-
- return super(ClientTests, self).run(args=argv)
-
-
-class SQLTest(KeystoneTest):
- """Test defined using only SQLAlchemy back-end"""
- config_name = 'sql.conf.template'
- test_files = ('keystone.sqltest.db',)
- directory_base = 'functional'
-
- def run(self):
- """ Run client tests
-
- Filters arguments and leaves only ones relevant to client tests
- """
-
- argv = []
- scoped_to_functional = False
- for x in sys.argv:
- if x.startswith(('client', 'unit')):
- # Skip, since we're not running functional tests
- return
- elif x.startswith('functional'):
- argv.append('keystone.test.%s' % x)
- scoped_to_functional = True
- else:
- argv.append(x)
-
- if not scoped_to_functional:
- argv.append('keystone.test.functional')
-
- return super(SQLTest, self).run(args=argv)
-
- def clear_database(self):
- # Disconnect the database before deleting
- from keystone.backends import sqlalchemy
- sqlalchemy.unregister_models()
-
- super(SQLTest, self).clear_database()
-
-
-class SSLTest(ClientTests):
- config_name = 'ssl.conf.template'
- isSsl = True
- test_files = ('keystone.ssltest.db',)
-
-
-class MemcacheTest(SQLTest):
- """Test defined using only SQLAlchemy and Memcache back-end"""
- config_name = 'memcache.conf.template'
- test_files = ('keystone.memcachetest.db',)
-
-
-class LDAPTest(SQLTest):
- """Test defined using only SQLAlchemy and LDAP back-end"""
- config_name = 'ldap.conf.template'
- test_files = ('keystone.ldaptest.db', 'ldap.db', 'ldap.db.db',)
-
- def clear_database(self):
- super(LDAPTest, self).clear_database()
- from keystone.backends.ldap.fakeldap import FakeShelve
- db = FakeShelve().get_instance()
- db.clear()
-
-
-class ClientWithoutHPIDMTest(ClientTests):
- """Test with HP-IDM disabled to make sure it is backward compatible"""
- config_name = 'sql_no_hpidm.conf.template'
- hpidmDisabled = True
- test_files = ('keystone.nohpidm.db',)
diff --git a/keystone/test/client/__init__.py b/keystone/test/client/__init__.py
deleted file mode 100644
index 99f61885..00000000
--- a/keystone/test/client/__init__.py
+++ /dev/null
@@ -1,39 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-""" Client Tests
-
-Client tests are tests that use HTTP(S) calls to a Keystone server to exercise
-request/response test cases.
-
-In order to avoid port conflicts, client tests use the global settings below
-to know which server to talk to.
-
-When a server is started for testing purposes (usually by the
-keystone.test.KeystoneTest class) it will update these values so client tests
-know where to find the server
-
-"""
-TEST_TARGET_SERVER_ADMIN_PROTOCOL = 'http'
-TEST_TARGET_SERVER_ADMIN_ADDRESS = '127.0.0.1'
-TEST_TARGET_SERVER_ADMIN_PORT = 35357
-
-TEST_TARGET_SERVER_SERVICE_PROTOCOL = 'http'
-TEST_TARGET_SERVER_SERVICE_ADDRESS = '127.0.0.1'
-TEST_TARGET_SERVER_SERVICE_PORT = 5000
-
-TEST_CONFIG_FILE_NAME = None
diff --git a/keystone/test/client/test_client.py b/keystone/test/client/test_client.py
deleted file mode 100644
index 6e95d443..00000000
--- a/keystone/test/client/test_client.py
+++ /dev/null
@@ -1,101 +0,0 @@
-import unittest
-
-import keystone.common.exception
-import keystone.client
-from keystone.test.functional.common import isSsl
-from keystone.test import client as client_tests
-
-
-class TestAdminClient(unittest.TestCase):
- """
- Quick functional tests for the Keystone HTTP admin client.
- """
- use_server = True
-
- def setUp(self):
- """
- Run before each test.
- """
- cert_file = isSsl()
- self.client = keystone.client.AdminClient(
- client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
- port=client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
- is_ssl=(cert_file is not None),
- cert_file=cert_file,
- admin_name="admin",
- admin_pass="secrete")
-
- def test_admin_validate_token(self):
- """
- Test that our admin token is valid. (HTTP GET)
- """
- token = self.client.admin_token
- result = self.client.validate_token(token)
- self.assertEquals("admin",
- result["access"]["user"]["name"])
-
- def test_admin_check_token(self):
- """
- Test that our admin token is valid. (HTTP HEAD)
- """
- token = self.client.admin_token
- self.assertTrue(self.client.check_token(token))
-
- def test_admin_validate_token_fail(self):
- """
- Test that validating an invalid token results in None. (HTTP GET)
- """
- token = "bad_token"
- self.assertTrue(self.client.validate_token(token) is None)
-
- def test_admin_check_token_fail(self):
- """
- Test that checking an invalid token results in False. (HTTP HEAD)
- """
- token = "bad_token"
- self.assertFalse(self.client.check_token(token))
-
- def test_admin_get_token(self):
- """
- Test that we can generate a token given correct credentials.
- """
- token = self.client.get_token("admin", "secrete")
- self.assertEquals(self.client.admin_token, token)
-
- def test_admin_get_token_bad_auth(self):
- """
- Test incorrect credentials generates a client error.
- """
- self.assertRaises(keystone.common.exception.ClientError,
- self.client.get_token, "bad_user", "bad_pass")
-
-
-class TestServiceClient(unittest.TestCase):
- """
- Quick functional tests for the Keystone HTTP service client.
- """
-
- def setUp(self):
- """
- Run before each test.
- """
- cert_file = isSsl()
- self.client = keystone.client.ServiceClient(
- client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
- port=client_tests.TEST_TARGET_SERVER_SERVICE_PORT,
- is_ssl=(cert_file is not None),
- cert_file=cert_file)
-
- def test_admin_get_token(self):
- """
- Test that we can generate a token given correct credentials.
- """
- token = self.client.get_token("admin", "secrete")
- self.assertTrue(36, len(token))
-
- def test_admin_get_token_bad_auth(self):
- """
- Test incorrect credentials generates a client error.
- """
- self.assertRaises(keystone.common.exception.ClientError,
- self.client.get_token, "bad_user", "bad_pass")
diff --git a/keystone/test/client/test_d5_compat_calls.py b/keystone/test/client/test_d5_compat_calls.py
deleted file mode 100644
index 865bc46d..00000000
--- a/keystone/test/client/test_d5_compat_calls.py
+++ /dev/null
@@ -1,169 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-
-from keystone.test.functional import common
-
-
-class D5_AuthenticationTest(common.FunctionalTestCase):
- """ Tests the functionality of the D5 compat module """
- use_server = True
-
- def setUp(self, *args, **kwargs):
- super(D5_AuthenticationTest, self).setUp(*args, **kwargs)
-
- password = common.unique_str()
- self.tenant = self.create_tenant().json['tenant']
- self.user = self.create_user(user_password=password,
- tenant_id=self.tenant['id']).json['user']
- self.user['password'] = password
-
- self.services = {}
- self.endpoint_templates = {}
- self.services = self.fixture_create_service()
- self.endpoint_templates = self.create_endpoint_template(
- name=self.services['name'],
- type=self.services['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates['id'])
-
- def test_validate_unscoped_token(self):
- """Admin should be able to validate a user's token"""
- # Authenticate as user to get a token
- self.service_token = self.post_token(as_json={
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}).\
- json['auth']['token']['id']
-
- # In the real world, the service user would then pass his/her token
- # to some service that depends on keystone, which would then need to
- # use keystone to validate the provided token.
-
- # Admin independently validates the user token
- r = self.get_token(self.service_token)
- self.assertEqual(r.json['auth']['token']['id'], self.service_token)
- self.assertTrue(r.json['auth']['token']['expires'])
- self.assertEqual(r.json['auth']['user']['username'],
- self.user['name'])
- self.assertEqual(r.json['auth']['user']['roleRefs'], [])
-
- def test_validate_scoped_token(self):
- """Admin should be able to validate a user's scoped token"""
- # Authenticate as user to get a token
- self.service_token = self.post_token(as_json={
- 'passwordCredentials': {
- 'tenantId': self.tenant['id'],
- 'username': self.user['name'],
- 'password': self.user['password']}}).\
- json['auth']['token']['id']
-
- # In the real world, the service user would then pass his/her token
- # to some service that depends on keystone, which would then need to
- # use keystone to validate the provided token.
-
- # Admin independently validates the user token
- r = self.get_token(self.service_token)
- self.assertEqual(r.json['auth']['token']['id'], self.service_token)
- self.assertEqual(r.json['auth']['token']['tenantId'],
- self.tenant['id'])
- self.assertTrue(r.json['auth']['token']['expires'])
- self.assertEqual(r.json['auth']['user']['username'],
- self.user['name'])
- self.assertEqual(r.json['auth']['user']['roleRefs'], [])
-
- def test_authenticate_for_a_tenant(self):
- r = self.authenticate_D5(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=200)
-
- self.assertIsNotNone(r.json['auth']['token'])
- service_catalog = r.json['auth']['serviceCatalog']
- self.assertIsNotNone(service_catalog)
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials xmlns="%s" tenantId="%s"'
- ' username="%s" password="%s" '
- '/>') % (
- self.xmlns, self.tenant['id'],
- self.user['name'], self.user['password'])
- r = self.post_token(as_xml=data, assert_status=200)
-
- self.assertEquals(r.xml.tag, '{%s}auth' % self.xmlns)
- service_catalog = r.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_for_a_tenant_on_admin_api(self):
- r = self.authenticate_D5(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=200, request_type='admin')
-
- self.assertIsNotNone(r.json['auth']['token'])
- self.assertIsNotNone(r.json['auth']['serviceCatalog'])
- service_catalog = r.json['auth']['serviceCatalog']
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml_on_admin_api(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials xmlns="%s" tenantId="%s"'
- ' username="%s" password="%s" '
- '/>') % (
- self.xmlns, self.tenant['id'],
- self.user['name'], self.user['password'])
- r = self.post_token(as_xml=data, assert_status=200,
- request_type='admin')
-
- self.assertEquals(r.xml.tag, '{%s}auth' % self.xmlns)
- service_catalog = r.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_user_disabled(self):
- self.disable_user(self.user['id'])
- self.authenticate_D5(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=403)
-
- def test_authenticate_user_wrong(self):
- data = {"passwordCredentials": {
- "username-field-completely-wrong": self.user['name'],
- "password": self.user['password'],
- "tenantId": self.tenant['id']}}
- self.post_token(as_json=data, assert_status=400)
-
- def test_authenticate_user_wrong_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials '
- 'xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'usernamefieldcompletelywrong="%s" '
- 'password="%s" '
- 'tenantId="%s"/>') % (
- self.user['name'], self.user['password'], self.tenant['id'])
-
- self.post_token(as_xml=data, assert_status=400)
-
- def check_urls_for_regular_user(self, service_catalog):
- self.assertIsNotNone(service_catalog)
- for k in service_catalog.keys():
- endpoints = service_catalog[k]
- for endpoint in endpoints:
- for key in endpoint:
- #Checks whether adminURL is not present.
- self.assertNotEquals(key, 'adminURL')
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/client/test_extensions.py b/keystone/test/client/test_extensions.py
deleted file mode 100644
index bb5d40a8..00000000
--- a/keystone/test/client/test_extensions.py
+++ /dev/null
@@ -1,68 +0,0 @@
-import os
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestExtensions(common.FunctionalTestCase):
- use_server = True
-
- def test_extensions_json(self):
- r = self.service_request(path='/extensions.json')
- self.assertTrue('json' in r.getheader('Content-Type'))
- content = r.json
- self.assertIsNotNone(content['extensions'])
- self.assertIsNotNone(content['extensions']['values'])
-
- def test_extensions_xml(self):
- r = self.service_request(path='/extensions.xml')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
-
-class TestAdminExtensions(common.ApiTestCase):
- use_server = True
-
- def test_extensions_json(self):
- r = self.admin_request(path='/extensions.json')
- self.assertTrue('json' in r.getheader('Content-Type'))
- content = r.json
- self.assertIsNotNone(content['extensions'])
- self.assertIsNotNone(content['extensions']['values'])
- found_osksadm = False
- found_oskscatalog = False
- found_hpidm = False
- for value in content['extensions']['values']:
- if value['extension']['alias'] == 'OS-KSADM':
- found_osksadm = True
- if value['extension']['alias'] == 'OS-KSCATALOG':
- found_oskscatalog = True
- if value['extension']['alias'] == 'HP-IDM':
- found_hpidm = True
- self.assertTrue(found_osksadm, "Missing OS-KSADM extension.")
- self.assertTrue(found_oskscatalog, "Missing OS-KSCATALOG extension.")
- if not common.isSsl() and 'HP-IDM_Disabled' not in os.environ:
- self.assertTrue(found_hpidm, "Missing HP-IDM extension.")
-
- def test_extensions_xml(self):
- r = self.admin_request(path='/extensions.xml')
- self.assertTrue('xml' in r.getheader('Content-Type'))
- content = r.xml
- extensions = content.findall(
- "{http://docs.openstack.org/common/api/v1.0}extension")
- found_osksadm = False
- found_oskscatalog = False
- found_hpidm = False
- for extension in extensions:
- if extension.get("alias") == 'OS-KSADM':
- found_osksadm = True
- if extension.get("alias") == 'OS-KSCATALOG':
- found_oskscatalog = True
- if extension.get("alias") == 'HP-IDM':
- found_hpidm = True
- self.assertTrue(found_osksadm, "Missing OS-KSADM extension.")
- self.assertTrue(found_oskscatalog, "Missing OS-KSCATALOG extension.")
- if not common.isSsl() and 'HP-IDM_Disabled' not in os.environ:
- self.assertTrue(found_hpidm, "Missing HP-IDM extension.")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/client/test_frontends.py b/keystone/test/client/test_frontends.py
deleted file mode 100644
index 636f6607..00000000
--- a/keystone/test/client/test_frontends.py
+++ /dev/null
@@ -1,38 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class LegacyAuthenticationTest(common.FunctionalTestCase):
- use_server = True
-
- def setUp(self, *args, **kwargs):
- super(LegacyAuthenticationTest, self).setUp(*args, **kwargs)
-
- password = common.unique_str()
- self.tenant = self.create_tenant().json['tenant']
- self.user = self.create_user(user_password=password,
- tenant_id=self.tenant['id']).json['user']
- self.user['password'] = password
-
- self.services = {}
- self.endpoint_templates = {}
- for x in range(5):
- self.services[x] = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates[x] = self.create_endpoint_template(
- name=self.services[x]['name'], \
- type=self.services[x]['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates[x]['id'])
-
- def test_authenticate_legacy(self):
- r = self.service_request(version='1.0', assert_status=204, headers={
- "X-Auth-User": self.user['name'],
- "X-Auth-Key": self.user['password']})
-
- self.assertIsNotNone(r.getheader('x-auth-token'))
- for service in self.services.values():
- self.assertIsNotNone(r.getheader('x-' + service['name']))
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/client/test_keystone_manage.py b/keystone/test/client/test_keystone_manage.py
deleted file mode 100644
index d60e8a5c..00000000
--- a/keystone/test/client/test_keystone_manage.py
+++ /dev/null
@@ -1,54 +0,0 @@
-import os
-import subprocess
-import sys
-import unittest2 as unittest
-
-import keystone.test.client as client_tests
-from keystone.test import sampledata
-from keystone import manage
-
-# Calculate root path so ewe call files in bin
-possible_topdir = os.path.normpath(os.path.join(os.path.abspath(__file__),
- os.pardir,
- os.pardir,
- os.pardir,
- os.pardir))
-
-
-class TestKeystoneManage(unittest.TestCase):
- """
- Tests for the keystone-manage client.
- """
-
- def test_check_can_call_keystone_manage(self):
- """
- Test that we can call keystone-manage
- """
- cmd = [
- os.path.join(possible_topdir, 'bin', 'keystone-manage'),
- '--help',
- ]
- process = subprocess.Popen(cmd, stdout=subprocess.PIPE)
- result = process.communicate()[0]
- self.assertIn('usage', result.lower())
-
- def test_keystone_manage_calls(self):
- """
- Test that we can call keystone-manage and all sampledata calls work
- """
- cmd = [
- os.path.join(possible_topdir, 'bin', 'keystone-manage'),
- '-c', client_tests.TEST_CONFIG_FILE_NAME,
- '--log-file', os.path.join(possible_topdir, 'bin', 'keystone.log'),
- 'service', 'list'
- ]
- # This will init backends
- manage.parse_args(cmd[1:])
-
- # Loop through and try sampledata calls
- sampledata_calls = sampledata.DEFAULT_FIXTURE
- for call in sampledata_calls:
- manage.process(*call)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/client/test_middleware.py b/keystone/test/client/test_middleware.py
deleted file mode 100644
index 543e0b70..00000000
--- a/keystone/test/client/test_middleware.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import unittest2 as unittest
-import uuid
-
-import keystone.common.exception
-import keystone.backends.api as db_api
-from keystone.test.functional import common
-from keystone.test import client as client_tests
-
-#
-# Auth Token
-#
-from keystone.middleware import auth_token
-
-
-class TestAuthTokenMiddleware(common.MiddlewareTestCase):
- """
- Tests for Keystone WSGI middleware: Auth Token
- """
-
- def setUp(self):
- super(TestAuthTokenMiddleware, self).setUp(auth_token)
-
-
-class TestAuthTokenMiddlewareWithNoAdminToken(common.MiddlewareTestCase):
- """
- Tests for Keystone WSGI middleware: Auth Token
- """
-
- def setUp(self):
- settings = {'delay_auth_decision': '0',
- 'auth_host': client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
- 'auth_port': client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
- 'auth_protocol':
- client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL,
- 'auth_uri': ('%s://%s:%s/' % \
- (client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
- client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
- client_tests.TEST_TARGET_SERVER_SERVICE_PORT)),
- 'admin_user': self.admin_username,
- 'admin_password': self.admin_password}
- super(TestAuthTokenMiddlewareWithNoAdminToken, self).setUp(auth_token,
- settings)
-
-#
-# Glance
-#
-try:
- from keystone.middleware import glance_auth_token
-except ImportError as e:
- print 'Could not load glance_auth_token: %s' % e
-
-
-@unittest.skipUnless('glance_auth_token' in vars(),
- "Glance Auth Token not imported")
-class TestGlanceMiddleware(common.MiddlewareTestCase):
- """
- Tests for Keystone WSGI middleware: Glance
- """
-
- def setUp(self):
- super(TestGlanceMiddleware, self).setUp(
- (auth_token, glance_auth_token))
-
-
-#
-# Quantum
-#
-from keystone.middleware import quantum_auth_token
-
-
-class TestQuantumMiddleware(common.MiddlewareTestCase):
- """
- Tests for Keystone WSGI middleware: Glance
- """
-
- def setUp(self):
- access = self.authenticate(self.admin_username, self.admin_password).\
- json['access']
- self.admin_token = access['token']['id']
- settings = {'delay_auth_decision': '0',
- 'auth_host': client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
- 'auth_port': client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
- 'auth_protocol':
- client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL,
- 'auth_uri': ('%s://%s:%s/' % \
- (client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
- client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
- client_tests.TEST_TARGET_SERVER_SERVICE_PORT)),
- 'auth_version': '2.0',
- 'admin_token': self.admin_token,
- 'admin_user': self.admin_username,
- 'admin_password': self.admin_password}
- super(TestQuantumMiddleware, self).setUp(quantum_auth_token, settings)
-
-
-#
-# Swift
-#
-try:
- from keystone.middleware import swift_auth
-except ImportError as e:
- print 'Could not load swift_auth: %s' % e
-
-#TODO(Ziad): find out how to disable swift logging
-#@unittest.skipUnless('swift_auth' in vars(),
-# "swift_auth not imported")
-#class TestSwiftMiddleware(common.MiddlewareTestCase):
-# """
-# Tests for Keystone WSGI middleware: Glance
-# """
-#
-# def setUp(self):
-# settings = {'delay_auth_decision': '0',
-# 'auth_host': '127.0.0.1',
-# 'auth_port': '35357',
-# 'auth_protocol': 'http',
-# 'auth_uri': 'http://localhost:35357/',
-# 'admin_token': self.admin_token,
-# 'set log_facility': 'LOG_NULL'}
-# super(TestSwiftMiddleware, self).setUp(swift_auth, settings)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/client/test_request_specs.py b/keystone/test/client/test_request_specs.py
deleted file mode 100644
index 39118a07..00000000
--- a/keystone/test/client/test_request_specs.py
+++ /dev/null
@@ -1,124 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestResponseHeaders(common.FunctionalTestCase):
- """Tests API's response headers"""
- use_server = True
-
- def test_vary_header_on_error(self):
- """A Vary header should be provided to support caching responses."""
- r = self.admin_request(path='/tokens/not-a-valid-token',
- assert_status=404)
- self.assertIn('X-Auth-Token', r.getheader('Vary'))
-
- def test_vary_header_on_admin(self):
- """A Vary header should be provided to support caching responses."""
- r = self.admin_request(path='/tokens/%s' % self.admin_token)
- self.assertIn('X-Auth-Token', r.getheader('Vary'))
-
- def test_vary_header_on_service(self):
- """A Vary header should be provided to support caching responses."""
- r = self.service_request(path='/tenants')
- self.assertIn('X-Auth-Token', r.getheader('Vary'))
-
- def test_vary_header_on_legacy(self):
- """A Vary header should be provided to support caching responses."""
- r = self.admin_request('1.1/tenants')
- self.assertIn('X-Auth-Token', r.getheader('Vary'))
-
- def test_vary_header_on_static(self):
- """A Vary header should not be provided on a static request."""
- r = self.service_request('2.0/')
- self.assertEqual(None, r.getheader('Vary'))
-
-
-class TestUrlHandling(common.FunctionalTestCase):
- """Tests API's global URL handling behaviors"""
- use_server = True
-
- def test_optional_trailing_slash(self):
- """Same response returned regardless of a trailing slash in the url."""
- r1 = self.service_request(path='/')
- r2 = self.service_request(path='')
- self.assertEqual(r1.read(), r2.read())
-
-
-class TestContentTypes(common.FunctionalTestCase):
- """Tests API's Content-Type handling"""
- use_server = True
-
- def test_default_content_type(self):
- """Service returns JSON without being asked to"""
- r = self.service_request()
- self.assertTrue('application/json' in r.getheader('Content-Type'))
-
- def test_xml_extension(self):
- """Service responds to .xml URL extension"""
- r = self.service_request(path='.xml')
- self.assertTrue('application/xml' in r.getheader('Content-Type'))
-
- def test_json_extension(self):
- """Service responds to .json URL extension"""
- r = self.service_request(path='.json')
- self.assertTrue('application/json' in r.getheader('Content-Type'))
-
- def test_xml_accept_header(self):
- """Service responds to xml Accept header"""
- r = self.service_request(headers={'Accept': 'application/xml'})
- self.assertTrue('application/xml' in r.getheader('Content-Type'))
-
- def test_json_accept_header(self):
- """Service responds to json Accept header"""
- r = self.service_request(headers={'Accept': 'application/json'})
- self.assertTrue('application/json' in r.getheader('Content-Type'))
-
- def test_versioned_xml_accept_header(self):
- """Service responds to versioned xml Accept header"""
- r = self.service_request(headers={
- 'Accept': 'application/vnd.openstack.identity-v2.0+xml'})
- self.assertTrue('application/xml' in r.getheader('Content-Type'))
-
- def test_versioned_json_accept_header(self):
- """Service responds to versioned json Accept header"""
- r = self.service_request(headers={
- 'Accept': 'application/vnd.openstack.identity-v2.0+json'})
- self.assertTrue('application/json' in r.getheader('Content-Type'))
-
- def test_xml_extension_overrides_conflicting_header(self):
- """Service returns XML when Accept header conflicts with extension"""
- r = self.service_request(path='.xml',
- headers={'Accept': 'application/json'})
-
- self.assertTrue('application/xml' in r.getheader('Content-Type'))
-
- def test_json_extension_overrides_conflicting_header(self):
- """Service returns JSON when Accept header conflicts with extension"""
- r = self.service_request(path='.json',
- headers={'Accept': 'application/xml'})
-
- self.assertTrue('application/json' in r.getheader('Content-Type'))
-
- def test_xml_content_type_on_404(self):
- """Content-Type should be honored even on 404 errors (Issue #13)"""
- r = self.service_request(path='/completely-invalid-path',
- headers={'Accept': 'application/xml'},
- assert_status=404)
-
- # Commenting this assertion out, as it currently fails
- self.assertTrue('application/xml' in r.getheader('Content-Type'),
- 'application/xml not in %s' % r.getheader('Content-Type'))
-
- def test_json_content_type_on_404(self):
- """Content-Type should be honored even on 404 errors (Issue #13)"""
- r = self.service_request(path='/completely-invalid-path',
- headers={'Accept': 'application/json'},
- assert_status=404)
-
- # Commenting this assertion out, as it currently fails
- self.assertTrue('application/json' in r.getheader('Content-Type'),
- 'application/json not in %s' % r.getheader('Content-Type'))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/client/test_static_files.py b/keystone/test/client/test_static_files.py
deleted file mode 100644
index df3bc620..00000000
--- a/keystone/test/client/test_static_files.py
+++ /dev/null
@@ -1,94 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestStaticFiles(common.ApiTestCase):
- use_server = True
-
- def test_pdf_contract(self):
- if not common.isSsl():
- #TODO(ziad): Caller hangs in SSL (but works with cURL)
- r = self.service_request(path='/identitydevguide.pdf')
- self.assertTrue('pdf' in r.getheader('Content-Type'))
-
- def test_wadl_contract(self):
- r = self.service_request(path='/identity.wadl')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_wadl_common(self):
- r = self.service_request(path='/common.ent')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_xsd_contract(self):
- r = self.service_request(path='/xsd/api.xsd')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_xsd_atom_contract(self):
- r = self.service_request(path='/xsd/atom/atom.xsd')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_xslt(self):
- r = self.service_request(path='/xslt/schema.xslt')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_js(self):
- r = self.service_request(path='/js/shjs/sh_java.js')
- self.assertTrue('javascript' in r.getheader('Content-Type'))
-
- def test_xml_sample(self):
- r = self.service_request(path='/samples/auth.xml')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_json_sample(self):
- r = self.service_request(path='/samples/auth.json')
- self.assertTrue('json' in r.getheader('Content-Type'))
-
- def test_stylesheet(self):
- r = self.service_request(path='/style/shjs/sh_acid.css')
- self.assertTrue('css' in r.getheader('Content-Type'))
-
-
-class TestAdminStaticFiles(common.FunctionalTestCase):
- use_server = True
-
- def test_pdf_contract(self):
- if not common.isSsl():
- #TODO(ziad): Caller hangs in SSL (but works with cURL)
- r = self.admin_request(path='/identityadminguide.pdf')
- self.assertTrue('pdf' in r.getheader('Content-Type'))
-
- def test_wadl_contract(self):
- r = self.admin_request(path='/identity-admin.wadl')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_xsd_contract(self):
- r = self.admin_request(path='/xsd/api.xsd')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_xsd_atom_contract(self):
- r = self.admin_request(path='/xsd/atom/atom.xsd')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_xslt(self):
- r = self.admin_request(path='/xslt/schema.xslt')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_js(self):
- r = self.admin_request(path='/js/shjs/sh_java.js')
- self.assertTrue('javascript' in r.getheader('Content-Type'))
-
- def test_xml_sample(self):
- r = self.admin_request(path='/samples/auth.xml')
- self.assertTrue('xml' in r.getheader('Content-Type'))
-
- def test_json_sample(self):
- r = self.admin_request(path='/samples/auth.json')
- self.assertTrue('json' in r.getheader('Content-Type'))
-
- def test_stylesheet(self):
- r = self.admin_request(path='/style/shjs/sh_acid.css')
- self.assertTrue('css' in r.getheader('Content-Type'))
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/etc/ldap.conf.template b/keystone/test/etc/ldap.conf.template
deleted file mode 100644
index 385afc93..00000000
--- a/keystone/test/etc/ldap.conf.template
+++ /dev/null
@@ -1,60 +0,0 @@
-[DEFAULT]
-verbose = False
-debug = False
-default_store = sqlite
-log_file = %(test_dir)s/keystone.log
-log_dir = %(test_dir)s
-backends = keystone.backends.sqlalchemy,keystone.backends.ldap
-extensions= osksadm, oskscatalog, hpidm
-service-header-mappings = {
- 'nova' : 'X-Server-Management-Url',
- 'swift' : 'X-Storage-Url',
- 'cdn' : 'X-CDN-Management-Url'}
-service_host = 0.0.0.0
-service_port = %(service_port)s
-service_ssl = False
-admin_host = 0.0.0.0
-admin_port = %(admin_port)s
-admin_ssl = False
-keystone-admin-role = Admin
-keystone-service-admin-role = KeystoneServiceAdmin
-hash-password = True
-
-[keystone.backends.sqlalchemy]
-sql_connection = sqlite://
-sql_idle_timeout = 30
-backend_entities = ['Endpoints', 'Credentials', 'EndpointTemplates', 'Token', 'Service']
-
-[keystone.backends.ldap]
-ldap_url = fake://memory
-ldap_user = cn=Admin
-ldap_password = password
-backend_entities = ['Tenant', 'User', 'UserRoleAssociation', 'Role']
-
-[pipeline:admin]
-pipeline =
- urlnormalizer
- d5_compat
- admin_api
-
-[pipeline:keystone-legacy-auth]
-pipeline =
- urlnormalizer
- legacy_auth
- d5_compat
- service_api
-
-[app:service_api]
-paste.app_factory = keystone.server:service_app_factory
-
-[app:admin_api]
-paste.app_factory = keystone.server:admin_app_factory
-
-[filter:urlnormalizer]
-paste.filter_factory = keystone.frontends.normalizer:filter_factory
-
-[filter:d5_compat]
-paste.filter_factory = keystone.frontends.d5_compat:filter_factory
-
-[filter:legacy_auth]
-paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
diff --git a/keystone/test/etc/memcache.conf.template b/keystone/test/etc/memcache.conf.template
deleted file mode 100644
index 6cb434ac..00000000
--- a/keystone/test/etc/memcache.conf.template
+++ /dev/null
@@ -1,58 +0,0 @@
-[DEFAULT]
-verbose = False
-debug = False
-default_store = sqlite
-log_file = %(test_dir)s/keystone.log
-log_dir = %(test_dir)s
-backends = keystone.backends.sqlalchemy,keystone.backends.memcache
-extensions= osksadm, oskscatalog, hpidm
-service-header-mappings = {
- 'nova' : 'X-Server-Management-Url',
- 'swift' : 'X-Storage-Url',
- 'cdn' : 'X-CDN-Management-Url'}
-service_host = 0.0.0.0
-service_port = %(service_port)s
-service_ssl = False
-admin_host = 0.0.0.0
-admin_port = %(admin_port)s
-admin_ssl = False
-keystone-admin-role = Admin
-keystone-service-admin-role = KeystoneServiceAdmin
-
-[keystone.backends.sqlalchemy]
-sql_connection = sqlite://
-sql_idle_timeout = 30
-backend_entities = ['Endpoints', 'Credentials', 'EndpointTemplates', 'Tenant', 'User', 'UserRoleAssociation', 'Role', 'Service']
-
-[keystone.backends.memcache]
-memcache_hosts = 127.0.0.1:11211
-backend_entities = ['Token']
-cache_time = 86400
-
-[pipeline:admin]
-pipeline =
- urlnormalizer
- d5_compat
- admin_api
-
-[pipeline:keystone-legacy-auth]
-pipeline =
- urlnormalizer
- legacy_auth
- d5_compat
- service_api
-
-[app:service_api]
-paste.app_factory = keystone.server:service_app_factory
-
-[app:admin_api]
-paste.app_factory = keystone.server:admin_app_factory
-
-[filter:urlnormalizer]
-paste.filter_factory = keystone.frontends.normalizer:filter_factory
-
-[filter:d5_compat]
-paste.filter_factory = keystone.frontends.d5_compat:filter_factory
-
-[filter:legacy_auth]
-paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
diff --git a/keystone/test/etc/sql.conf.template b/keystone/test/etc/sql.conf.template
deleted file mode 100644
index c8b7b4b0..00000000
--- a/keystone/test/etc/sql.conf.template
+++ /dev/null
@@ -1,54 +0,0 @@
-[DEFAULT]
-verbose = False
-debug = False
-default_store = sqlite
-log_file = %(test_dir)s/keystone.log
-log_dir = %(test_dir)s
-backends = keystone.backends.sqlalchemy
-extensions= osksadm, oskscatalog, hpidm
-service-header-mappings = {
- 'nova' : 'X-Server-Management-Url',
- 'swift' : 'X-Storage-Url',
- 'cdn' : 'X-CDN-Management-Url'}
-service_host = 0.0.0.0
-service_port = %(service_port)s
-service_ssl = False
-admin_host = 0.0.0.0
-admin_port = %(admin_port)s
-admin_ssl = False
-keystone-admin-role = Admin
-keystone-service-admin-role = KeystoneServiceAdmin
-hash-password = True
-
-[keystone.backends.sqlalchemy]
-sql_connection = sqlite://
-sql_idle_timeout = 30
-backend_entities = ['Endpoints', 'Credentials', 'EndpointTemplates', 'Tenant', 'User', 'UserRoleAssociation', 'Role', 'Token', 'Service']
-
-[pipeline:admin]
-pipeline =
- urlnormalizer
- d5_compat
- admin_api
-
-[pipeline:keystone-legacy-auth]
-pipeline =
- urlnormalizer
- legacy_auth
- d5_compat
- service_api
-
-[app:service_api]
-paste.app_factory = keystone.server:service_app_factory
-
-[app:admin_api]
-paste.app_factory = keystone.server:admin_app_factory
-
-[filter:urlnormalizer]
-paste.filter_factory = keystone.frontends.normalizer:filter_factory
-
-[filter:d5_compat]
-paste.filter_factory = keystone.frontends.d5_compat:filter_factory
-
-[filter:legacy_auth]
-paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
diff --git a/keystone/test/etc/sql_no_hpidm.conf.template b/keystone/test/etc/sql_no_hpidm.conf.template
deleted file mode 100644
index 2f5cefa4..00000000
--- a/keystone/test/etc/sql_no_hpidm.conf.template
+++ /dev/null
@@ -1,54 +0,0 @@
-[DEFAULT]
-verbose = False
-debug = False
-default_store = sqlite
-log_file = %(test_dir)s/keystone.log
-log_dir = %(test_dir)s
-backends = keystone.backends.sqlalchemy
-extensions= osksadm, oskscatalog
-service-header-mappings = {
- 'nova' : 'X-Server-Management-Url',
- 'swift' : 'X-Storage-Url',
- 'cdn' : 'X-CDN-Management-Url'}
-service_host = 0.0.0.0
-service_port = %(service_port)s
-service_ssl = False
-admin_host = 0.0.0.0
-admin_port = %(admin_port)s
-admin_ssl = False
-keystone-admin-role = Admin
-keystone-service-admin-role = KeystoneServiceAdmin
-hash-password = True
-
-[keystone.backends.sqlalchemy]
-sql_connection = sqlite://
-sql_idle_timeout = 30
-backend_entities = ['Endpoints', 'Credentials', 'EndpointTemplates', 'Tenant', 'User', 'UserRoleAssociation', 'Role', 'Token', 'Service']
-
-[pipeline:admin]
-pipeline =
- urlnormalizer
- d5_compat
- admin_api
-
-[pipeline:keystone-legacy-auth]
-pipeline =
- urlnormalizer
- legacy_auth
- d5_compat
- service_api
-
-[app:service_api]
-paste.app_factory = keystone.server:service_app_factory
-
-[app:admin_api]
-paste.app_factory = keystone.server:admin_app_factory
-
-[filter:urlnormalizer]
-paste.filter_factory = keystone.frontends.normalizer:filter_factory
-
-[filter:d5_compat]
-paste.filter_factory = keystone.frontends.d5_compat:filter_factory
-
-[filter:legacy_auth]
-paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
diff --git a/keystone/test/etc/ssl.conf.template b/keystone/test/etc/ssl.conf.template
deleted file mode 100644
index 1889c7d6..00000000
--- a/keystone/test/etc/ssl.conf.template
+++ /dev/null
@@ -1,58 +0,0 @@
-[DEFAULT]
-verbose = False
-debug = False
-default_store = sqlite
-log_file = %(test_dir)s/keystone.log
-log_dir = %(test_dir)s
-backends = keystone.backends.sqlalchemy
-extensions= osksadm, oskscatalog, hpidm
-service-header-mappings = {
- 'nova' : 'X-Server-Management-Url',
- 'swift' : 'X-Storage-Url',
- 'cdn' : 'X-CDN-Management-Url'}
-service_host = 0.0.0.0
-service_port = %(service_port)s
-service_ssl = True
-admin_host = 0.0.0.0
-admin_port = %(admin_port)s
-admin_ssl = True
-keystone-admin-role = Admin
-keystone-service-admin-role = KeystoneServiceAdmin
-hash-password = True
-certfile = %(base_dir)s/examples/ssl/certs/keystone.pem
-keyfile = %(base_dir)s/examples/ssl/private/keystonekey.pem
-ca_certs = %(base_dir)s/examples/ssl/certs/ca.pem
-cert_required = True
-
-[keystone.backends.sqlalchemy]
-sql_connection = sqlite://
-sql_idle_timeout = 30
-backend_entities = ['Endpoints', 'Credentials', 'EndpointTemplates', 'Tenant', 'User', 'UserRoleAssociation', 'Role', 'Token', 'Service']
-
-[pipeline:admin]
-pipeline =
- urlnormalizer
- d5_compat
- admin_api
-
-[pipeline:keystone-legacy-auth]
-pipeline =
- urlnormalizer
- legacy_auth
- d5_compat
- service_api
-
-[app:service_api]
-paste.app_factory = keystone.server:service_app_factory
-
-[app:admin_api]
-paste.app_factory = keystone.server:admin_app_factory
-
-[filter:urlnormalizer]
-paste.filter_factory = keystone.frontends.normalizer:filter_factory
-
-[filter:d5_compat]
-paste.filter_factory = keystone.frontends.d5_compat:filter_factory
-
-[filter:legacy_auth]
-paste.filter_factory = keystone.frontends.legacy_token_auth:filter_factory
diff --git a/keystone/test/functional/__init__.py b/keystone/test/functional/__init__.py
deleted file mode 100644
index df704bbe..00000000
--- a/keystone/test/functional/__init__.py
+++ /dev/null
@@ -1,25 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-""" Functional Tests
-
-Functional tests are tests that run calls through the core logic modues of
-Keystone through to the backends. The backend components will eventually be
-tested separately, but have not been stubbed out yet.
-
-They do not test http(s) calls or run a server on a TCP/IP port.
-"""
diff --git a/keystone/test/functional/common.py b/keystone/test/functional/common.py
deleted file mode 100644
index 80a10819..00000000
--- a/keystone/test/functional/common.py
+++ /dev/null
@@ -1,1738 +0,0 @@
-import datetime
-import httplib
-import json
-import logging
-import os
-import random
-import unittest2 as unittest
-import uuid
-from webob import Request, Response
-from xml.etree import ElementTree
-
-from keystone import server
-import keystone.backends.api as db_api
-from keystone.test import client as client_tests
-from keystone import utils
-
-logger = logging.getLogger(__name__)
-
-
-def isSsl():
- """ See if we are testing with SSL. If cert is non-empty, we are! """
- if 'cert_file' in os.environ:
- return os.environ['cert_file']
- return None
-
-
-class HttpTestCase(unittest.TestCase):
- """Performs generic HTTP request testing.
-
- Defines a ``request`` method for use in test cases that makes
- HTTP requests, and two new asserts:
-
- * assertResponseSuccessful
- * assertResponseStatus
- """
-
- def request(self, host='127.0.0.1', protocol='http', port=80, method='GET',
- path='/', headers=None, body=None, assert_status=None):
- """Perform request and fetch httplib.HTTPResponse from the server"""
-
- # Initialize headers dictionary
- headers = {} if not headers else headers
-
- logger.debug("Connecting to %s://%s:%s", protocol, host, port)
- if protocol == 'https':
- cert_file = isSsl()
- connection = httplib.HTTPSConnection(host, port,
- cert_file=cert_file,
- timeout=20)
- else:
- connection = httplib.HTTPConnection(host, port, timeout=20)
-
- # Perform the request
- connection.request(method, path, body, headers)
-
- # Retrieve the response so can go ahead and close the connection
- response = connection.getresponse()
- logger.debug("%s %s returned %s", method, path, response.status)
-
- response.body = response.read()
- if response.status != httplib.OK:
- logger.debug("Response Body:")
- for line in response.body.split("\n"):
- logger.debug(line)
-
- # Close the connection
- connection.close()
-
- # Automatically assert HTTP status code
- if assert_status:
- self.assertResponseStatus(response, assert_status)
- else:
- self.assertResponseSuccessful(response)
-
- # Contains the response headers, body, etc
- return response
-
- def assertResponseSuccessful(self, response):
- """Asserts that a status code lies inside the 2xx range
-
- :param response: :py:class:`httplib.HTTPResponse` to be
- verified to have a status code between 200 and 299.
-
- example::
-
- >>> self.assertResponseSuccessful(response, 203)
- """
- self.assertTrue(response.status >= 200 and response.status <= 299,
- 'Status code %d is outside of the expected range (2xx)\n\n%s' %
- (response.status, response.body))
-
- def assertResponseStatus(self, response, assert_status):
- """Asserts a specific status code on the response
-
- :param response: :py:class:`httplib.HTTPResponse`
- :param assert_status: The specific ``status`` result expected
-
- example::
-
- >>> self.assertResponseStatus(response, 203)
- """
- self.assertEqual(response.status, assert_status,
- 'Status code %s is not %s, as expected)\n\n%s' %
- (response.status, assert_status, response.body))
-
-
-class RestfulTestCase(HttpTestCase):
- """Performs restful HTTP request testing"""
-
- def restful_request(self, headers=None, as_json=None, as_xml=None,
- **kwargs):
- """Encodes and decodes (JSON & XML) HTTP requests and responses.
-
- Dynamically encodes json or xml as request body if one is provided.
-
- .. WARNING::
-
- * Existing Content-Type header will be overwritten.
- * If both as_json and as_xml are provided, as_xml is ignored.
- * If either as_json or as_xml AND a body is provided, the body
- is ignored.
-
- Dynamically returns 'as_json' or 'as_xml' attribute based on the
- detected response type, and fails the current test case if
- unsuccessful.
-
- response.as_json: standard python dictionary
-
- response.as_xml: as_etree.ElementTree
- """
-
- # Initialize headers dictionary
- headers = {} if not headers else headers
-
- # Attempt to encode JSON and XML automatically, if requested
- if as_json:
- body = RestfulTestCase._encode_json(as_json)
- headers['Content-Type'] = 'application/json'
- elif as_xml:
- body = as_xml
- headers['Content-Type'] = 'application/xml'
-
- # Assume the client wants xml back if it didn't specify
- if 'Accept' not in headers:
- headers['Accept'] = 'application/xml'
- elif 'body' in kwargs:
- body = kwargs.pop('body')
- else:
- body = None
-
- # Perform the HTTP request/response
- response = self.request(headers=headers, body=body, **kwargs)
-
- # Attempt to parse JSON and XML automatically, if detected
- response = self._decode_response_body(response)
-
- # Contains the decoded response as_json/as_xml, etc
- return response
-
- @staticmethod
- def _encode_json(data):
- """Returns a JSON-encoded string of the given python dictionary
-
- :param data: python object to be encoded into JSON
- :returns: string of JSON encoded data
- """
- return json.dumps(data)
-
- def _decode_response_body(self, response):
- """Detects response body type, and attempts to decode it
-
- :param response: :py:class:`httplib.HTTPResponse`
- :returns: response object with additions:
-
- If context type is application/json, the response will have an
- additional attribute ``json`` that will have the decoded JSON
- result (typically a dict)
-
- If context type is application/xml, the response will have an
- additional attribute ``xml`` that will have the an ElementTree
- result.
- """
- if response.body is not None and response.body.strip():
- if 'application/json' in response.getheader('Content-Type', ''):
- response.json = self._decode_json(response.body)
- elif 'application/xml' in response.getheader('Content-Type', ''):
- response.xml = self._decode_xml(response.body)
- return response
-
- @staticmethod
- def _decode_json(json_str):
- """Returns a dict of the given JSON string"""
- return json.loads(json_str)
-
- @staticmethod
- def _decode_xml(xml_str):
- """Returns an ElementTree of the given XML string"""
- return ElementTree.XML(xml_str)
-
-
-class ApiTestCase(RestfulTestCase):
- """Abstracts REST verbs & resources of the service & admin API."""
- use_server = False
-
- admin_role_name = 'Admin'
- service_admin_role_name = 'KeystoneServiceAdmin'
- member_role_name = 'Member'
-
- # Same as KeystoneTest settings
- admin_username = 'admin'
- admin_password = 'secrete'
-
- service_token = None
- admin_token = None
-
- service_api = None
- admin_api = None
-
- """
- Dict of configuration options to pass to the API controller
- """
- options = {
- 'backends': "keystone.backends.sqlalchemy",
- 'keystone.backends.sqlalchemy': {
- # in-memory db
- 'sql_connection': 'sqlite://',
- 'verbose': False,
- 'debug': False,
- 'backend_entities':
- "['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant', "
- "'Tenant', 'User', 'Credentials', 'EndpointTemplates', "
- "'Token', 'Service']",
- },
- 'extensions': 'osksadm, oskscatalog, hpidm',
- 'keystone-admin-role': 'Admin',
- 'keystone-service-admin-role': 'KeystoneServiceAdmin',
- 'hash-password': 'True',
- }
- # Populate the CONF module with these values
- utils.set_configuration(options)
-
- def fixture_create_role(self, **kwargs):
- """
- Creates a role fixture.
-
- :params \*\*kwargs: Attributes of the role to create
- """
- values = kwargs.copy()
- role = db_api.ROLE.create(values)
- logger.debug("Created role fixture %s (id=%s)", role.name, role.id)
- return role
-
- def fixture_create_token(self, **kwargs):
- """
- Creates a token fixture.
-
- :params \*\*kwargs: Attributes of the token to create
- """
- values = kwargs.copy()
- token = db_api.TOKEN.create(values)
- logger.debug("Created token fixture %s", token.id)
- return token
-
- def fixture_create_tenant(self, **kwargs):
- """
- Creates a tenant fixture.
-
- :params \*\*kwargs: Attributes of the tenant to create
- """
- values = kwargs.copy()
- tenant = db_api.TENANT.create(values)
- logger.debug("Created tenant fixture %s (id=%s)", tenant.name,
- tenant.id)
- return tenant
-
- def fixture_create_user(self, **kwargs):
- """
- Creates a user fixture. If the user's tenant ID is set, and the tenant
- does not exist in the database, the tenant is created.
-
- :params \*\*kwargs: Attributes of the user to create
- """
- values = kwargs.copy()
- tenant_name = values.get('tenant_name')
- if tenant_name:
- if not db_api.TENANT.get_by_name(tenant_name):
- tenant = db_api.TENANT.create({'name': tenant_name,
- 'enabled': True,
- 'desc': tenant_name})
- values['tenant_id'] = tenant.id
- user = db_api.USER.create(values)
- logger.debug("Created user fixture %s (id=%s)", user.name, user.id)
- return user
-
- def fixture_create_service(self, service_name=None, service_type=None,
- service_description=None, **kwargs):
- """
- Creates a service fixture.
-
- :params \*\*kwargs: Additional attributes of the service to create
- """
- values = kwargs.copy()
- service_name = optional_str(service_name)
- if service_type is None:
- service_type = ['compute', 'identity', 'image-service',
- 'object-store', 'ext:extension-service'
- ][random.randrange(5)]
- service_description = optional_str(service_description)
- values["name"] = service_name
- values["type"] = service_type
- values["description"] = service_description
-
- service = db_api.SERVICE.create(values)
- logger.debug("Created service fixture %s (id=%s)", service.name,
- service.id)
- return service
-
- def setUp(self):
- super(ApiTestCase, self).setUp()
- if self.use_server:
- return
-
- self.service_api = server.ServiceApi()
- self.admin_api = server.AdminApi()
-
- # ADMIN ROLE
- self.admin_role = self.fixture_create_role(
- name=self.admin_role_name)
-
- # ADMIN
- password = unique_str()
- self.admin_user = self.fixture_create_user(
- name="admin-user-%s" % uuid.uuid4().hex, enabled=True,
- password=password)
- self.admin_user['password'] = password
- self.admin_password = password
- self.admin_username = self.admin_user['name']
-
- obj = {}
- obj['role_id'] = self.admin_role['id']
- obj['user_id'] = self.admin_user['id']
- obj['tenant_id'] = None
- result = db_api.USER.user_role_add(obj)
- logger.debug("Created grant fixture %s", result.id)
-
- # SERVICE ADMIN ROLE
- self.service_admin_role = self.fixture_create_role(
- name=self.service_admin_role_name)
-
- # MEMBER ROLE
- self.member_role = self.fixture_create_role(
- name='Member')
-
- def tearDown(self):
- super(ApiTestCase, self).tearDown()
- # Explicitly release these to limit memory use.
- self.service_api = self.admin_api = self.admin_role = None
- self.admin_user = self.admin_password = self.admin_username = None
- self.service_admin_role = self.member_role = None
-
- def request(self, host='127.0.0.1', protocol='http', port=80, method='GET',
- path='/', headers=None, body=None, assert_status=None,
- server=None):
- """Overrides HttpTestCase and uses local calls"""
- if self.use_server:
- # Call a real server (bypass the override)
- return super(ApiTestCase, self).request(host=host, port=port,
- protocol=protocol, method=method,
- path=path, headers=headers, body=body,
- assert_status=assert_status)
-
- req = Request.blank(path)
- req.method = method
- req.headers = headers
- if isinstance(body, unicode):
- req.body = body.encode('utf-8')
- else:
- req.body = body
-
- res = req.get_response(server)
- logger.debug("%s %s returned %s", req.method, req.path_qs,
- res.status)
- if res.status_int != httplib.OK:
- logger.debug("Response Body:")
- for line in res.body.split("\n"):
- logger.debug(line)
-
- # Automatically assert HTTP status code
- if assert_status:
- self.assertEqual(res.status_int, assert_status,
- 'Status code %s is not %s, as expected)\n\n%s' %
- (res.status_int, assert_status, res.body))
- else:
- self.assertTrue(299 >= res.status_int >= 200,
- 'Status code %d is outside of the expected range (2xx)\n\n%s' %
- (res.status_int, res.body))
-
- # Contains the response headers, body, etc
- return res
-
- def _decode_response_body(self, response):
- """Override to support webob.Response.
- """
- if self.use_server:
- # Call a real server (bypass the override)
- return super(ApiTestCase, self)._decode_response_body(response)
-
- if response.body is not None and response.body.strip():
- if 'application/json' in response.content_type:
- response.json = self._decode_json(response.body)
- elif 'application/xml' in response.content_type:
- response.xml = self._decode_xml(response.body)
- return response
-
- def assertResponseSuccessful(self, response):
- """Asserts that a status code lies inside the 2xx range
-
- :param response: :py:class:`webob.Response` to be
- verified to have a status code between 200 and 299.
-
- example::
-
- >>> self.assertResponseSuccessful(response, 203)
- """
- if self.use_server:
- # Call a real server (bypass the override)
- return super(ApiTestCase, self).assertResponseSuccessful(response)
-
- self.assertTrue(response.status_int >= 200 and
- response.status_int <= 299,
- 'Status code %d is outside of the expected range (2xx)\n\n%s' %
- (response.status_int, response.body))
-
- def assertResponseStatus(self, response, assert_status):
- """Asserts a specific status code on the response
-
- :param response: :py:class:`webob.Response`
- :param assert_status: The specific ``status`` result expected
-
- example::
-
- >>> self.assertResponseStatus(response, 203)
- """
- if self.use_server:
- # Call a real server (bypass the override)
- return super(ApiTestCase, self).assertResponseStatus(response,
- assert_status)
-
- self.assertEqual(response.status_int, assert_status,
- 'Status code %s is not %s, as expected)\n\n%s' %
- (response.status_int, assert_status, response.body))
-
- def service_request(self, version='2.0', path='', port=None, headers=None,
- host=None, protocol=None, **kwargs):
- """Returns a request to the service API"""
-
- # Initialize headers dictionary
- headers = {} if not headers else headers
-
- if self.use_server:
- path = ApiTestCase._version_path(version, path)
- if port is None:
- port = client_tests.TEST_TARGET_SERVER_SERVICE_PORT or 5000
- if host is None:
- host = (client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS
- or '127.0.0.1')
- if protocol is None:
- protocol = (client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL
- or 'http')
-
- if 'use_token' in kwargs:
- headers['X-Auth-Token'] = kwargs.pop('use_token')
- elif self.service_token:
- headers['X-Auth-Token'] = self.service_token
- elif self.admin_token:
- headers['X-Auth-Token'] = self.admin_token
-
- return self.restful_request(host=host, protocol=protocol, port=port,
- path=path, headers=headers, server=self.service_api, **kwargs)
-
- def admin_request(self, version='2.0', path='', port=None, headers=None,
- host=None, protocol=None, **kwargs):
- """Returns a request to the admin API"""
-
- # Initialize headers dictionary
- headers = {} if not headers else headers
-
- if self.use_server:
- path = ApiTestCase._version_path(version, path)
- if port is None:
- port = client_tests.TEST_TARGET_SERVER_ADMIN_PORT or 35357
- if host is None:
- host = (client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS
- or '127.0.0.1')
- if protocol is None:
- protocol = (client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL
- or 'http')
-
- if 'use_token' in kwargs:
- headers['X-Auth-Token'] = kwargs.pop('use_token')
- elif self.admin_token:
- headers['X-Auth-Token'] = self.admin_token
-
- return self.restful_request(host=host, protocol=protocol, port=port,
- path=path, headers=headers, server=self.admin_api, **kwargs)
-
- @staticmethod
- def _version_path(version, path):
- """Prepend the given path with the API version.
-
- An empty version results in no version being prepended."""
- if version:
- return '/v' + str(version) + str(path)
- else:
- return str(path)
-
- def post_token(self, **kwargs):
- """POST /tokens"""
- #Setting service call as the default behavior."""
- if 'request_type' in kwargs and \
- kwargs.pop('request_type') == 'admin':
- return self.admin_request(method='POST',
- path='/tokens', **kwargs)
- else:
- return self.service_request(method='POST',
- path='/tokens', **kwargs)
-
- def get_token(self, token_id, **kwargs):
- """GET /tokens/{token_id}"""
- return self.admin_request(method='GET',
- path='/tokens/%s' % (token_id,), **kwargs)
-
- def get_token_belongsto(self, token_id, tenant_id, **kwargs):
- """GET /tokens/{token_id}?belongsTo={tenant_id}"""
- return self.admin_request(method='GET',
- path='/tokens/%s?belongsTo=%s' % (token_id, tenant_id), **kwargs)
-
- def check_token(self, token_id, **kwargs):
- """HEAD /tokens/{token_id}"""
- return self.admin_request(method='HEAD',
- path='/tokens/%s' % (token_id,), **kwargs)
-
- def check_token_belongs_to(self, token_id, tenant_id, **kwargs):
- """HEAD /tokens/{token_id}?belongsTo={tenant_id}"""
- return self.admin_request(method='HEAD',
- path='/tokens/%s?belongsTo=%s' % (token_id, tenant_id), **kwargs)
-
- def delete_token(self, token_id, **kwargs):
- """DELETE /tokens/{token_id}"""
- return self.admin_request(method='DELETE',
- path='/tokens/%s' % (token_id,), **kwargs)
-
- def post_tenant(self, **kwargs):
- """POST /tenants"""
- return self.admin_request(method='POST', path='/tenants', **kwargs)
-
- def get_tenants(self, **kwargs):
- """GET /tenants"""
- if 'request_type' in kwargs and \
- kwargs.pop('request_type') == 'service':
- return self.service_request(method='GET',
- path='/tenants', **kwargs)
- else:
- return self.admin_request(method='GET', path='/tenants', **kwargs)
-
- def get_tenant(self, tenant_id, **kwargs):
- """GET /tenants/{tenant_id}"""
- return self.admin_request(method='GET',
- path='/tenants/%s' % (tenant_id,), **kwargs)
-
- def get_tenant_by_name(self, tenant_name, **kwargs):
- """GET /tenants?name=tenant_name"""
- return self.admin_request(method='GET',
- path='/tenants?name=%s' % (tenant_name,), **kwargs)
-
- def post_tenant_for_update(self, tenant_id, **kwargs):
- """GET /tenants/{tenant_id}"""
- return self.admin_request(method='POST',
- path='/tenants/%s' % (tenant_id,), **kwargs)
-
- def get_tenant_users(self, tenant_id, **kwargs):
- """GET /tenants/{tenant_id}/users"""
- return self.admin_request(method='GET',
- path='/tenants/%s/users' % (tenant_id,), **kwargs)
-
- def get_tenant_users_by_role(self, tenant_id, role_id, **kwargs):
- """GET /tenants/{tenant_id}/users?roleId={roleId}"""
- return self.admin_request(method='GET',
- path='/tenants/%s/users?roleId=%s' % (\
- tenant_id, role_id), **kwargs)
-
- def delete_tenant(self, tenant_id, **kwargs):
- """DELETE /tenants/{tenant_id}"""
- return self.admin_request(method='DELETE',
- path='/tenants/%s' % (tenant_id,), **kwargs)
-
- def post_user(self, **kwargs):
- """POST /users"""
- return self.admin_request(method='POST', path='/users', **kwargs)
-
- def get_users(self, **kwargs):
- """GET /users"""
- return self.admin_request(method='GET', path='/users', **kwargs)
-
- def get_user(self, user_id, **kwargs):
- """GET /users/{user_id}"""
- return self.admin_request(method='GET',
- path='/users/%s' % (user_id,), **kwargs)
-
- def query_user(self, user_name, **kwargs):
- """GET /users?name={user_name}"""
- return self.admin_request(method='GET',
- path='/users?name=%s' % (user_name,), **kwargs)
-
- def post_user_for_update(self, user_id, **kwargs):
- """POST /users/{user_id}"""
- return self.admin_request(method='POST',
- path='/users/%s' % (user_id,), **kwargs)
-
- def put_user_password(self, user_id, **kwargs):
- """PUT /users/{user_id}/OS-KSADM/password"""
- return self.admin_request(method='PUT',
- path='/users/%s/OS-KSADM/password' % (user_id,), **kwargs)
-
- def put_user_tenant(self, user_id, **kwargs):
- """PUT /users/{user_id}/OS-KSADM/tenant"""
- return self.admin_request(method='PUT',
- path='/users/%s/OS-KSADM/tenant' % (user_id,), **kwargs)
-
- def put_user_enabled(self, user_id, **kwargs):
- """PUT /users/{user_id}/OS-KSADM/enabled"""
- return self.admin_request(method='PUT',
- path='/users/%s/OS-KSADM/enabled' % (user_id,), **kwargs)
-
- def delete_user(self, user_id, **kwargs):
- """DELETE /users/{user_id}"""
- return self.admin_request(method='DELETE',
- path='/users/%s' % (user_id,), **kwargs)
-
- def get_user_roles(self, user_id, **kwargs):
- """GET /users/{user_id}/roles"""
- return self.admin_request(method='GET',
- path='/users/%s/roles' % (user_id,), **kwargs)
-
- def put_user_role(self, user_id, role_id, tenant_id, **kwargs):
- if tenant_id is None:
- # PUT /users/{user_id}/roles/OS-KSADM/{role_id}
- return self.admin_request(method='PUT',
- path='/users/%s/roles/OS-KSADM/%s' %
- (user_id, role_id), **kwargs)
- else:
- # PUT /tenants/{tenant_id}/users/{user_id}/
- # roles/OS-KSADM/{role_id}
- return self.admin_request(method='PUT',
- path='/tenants/%s/users/%s/roles/OS-KSADM/%s' % (tenant_id,
- user_id, role_id,), **kwargs)
-
- def delete_user_role(self, user_id, role_id, tenant_id, **kwargs):
- """DELETE /users/{user_id}/roles/{role_id}"""
- if tenant_id is None:
- return self.admin_request(method='DELETE',
- path='/users/%s/roles/OS-KSADM/%s'
- % (user_id, role_id), **kwargs)
- else:
- return self.admin_request(method='DELETE',
- path='/tenants/%s/users/%s/roles/OS-KSADM/%s' %
- (tenant_id, user_id, role_id), **kwargs)
-
- def post_role(self, **kwargs):
- """POST /roles"""
- return self.admin_request(method='POST',
- path='/OS-KSADM/roles', **kwargs)
-
- def get_roles(self, **kwargs):
- """GET /OS-KSADM/roles"""
- return self.admin_request(method='GET',
- path='/OS-KSADM/roles', **kwargs)
-
- def get_roles_by_service(self, service_id, **kwargs):
- """GET /OS-KSADM/roles"""
- return self.admin_request(method='GET', path=(
- '/OS-KSADM/roles?serviceId=%s')
- % (service_id),
- **kwargs)
-
- def get_role(self, role_id, **kwargs):
- """GET /roles/{role_id}"""
- return self.admin_request(method='GET',
- path='/OS-KSADM/roles/%s' % (role_id,), **kwargs)
-
- def get_role_by_name(self, role_name, **kwargs):
- """GET /roles?name={role_name}"""
- return self.admin_request(method='GET',
- path='/OS-KSADM/roles?name=%s' % (role_name,), **kwargs)
-
- def delete_role(self, role_id, **kwargs):
- """DELETE /roles/{role_id}"""
- return self.admin_request(method='DELETE',
- path='/OS-KSADM/roles/%s' % (role_id,), **kwargs)
-
- def get_endpoint_templates(self, **kwargs):
- """GET /OS-KSCATALOG/endpointTemplates"""
- return self.admin_request(method='GET',
- path='/OS-KSCATALOG/endpointTemplates',
- **kwargs)
-
- def get_endpoint_templates_by_service(self, service_id, **kwargs):
- """GET /OS-KSCATALOG/endpointTemplates"""
- return self.admin_request(method='GET', path=(
- '/OS-KSCATALOG/endpointTemplates?serviceId=%s')
- % (service_id),
- **kwargs)
-
- def post_endpoint_template(self, **kwargs):
- """POST /OS-KSCATALOG/endpointTemplates"""
- return self.admin_request(method='POST',
- path='/OS-KSCATALOG/endpointTemplates',
- **kwargs)
-
- def put_endpoint_template(self, endpoint_template_id, **kwargs):
- """PUT /OS-KSCATALOG/endpointTemplates/{endpoint_template_id}"""
- return self.admin_request(method='PUT',
- path='/OS-KSCATALOG/endpointTemplates/%s'
- % (endpoint_template_id,),
- **kwargs)
-
- def get_endpoint_template(self, endpoint_template_id, **kwargs):
- """GET /OS-KSCATALOG/endpointTemplates/{endpoint_template_id}"""
- return self.admin_request(method='GET',
- path='/OS-KSCATALOG/endpointTemplates/%s'
- % (endpoint_template_id,),
- **kwargs)
-
- def delete_endpoint_template(self, endpoint_template_id, **kwargs):
- """DELETE /OS-KSCATALOG/endpointTemplates/{endpoint_template_id}"""
- return self.admin_request(method='DELETE',
- path='/OS-KSCATALOG/endpointTemplates/%s' %
- (endpoint_template_id,),
- **kwargs)
-
- def get_tenant_endpoints(self, tenant_id, **kwargs):
- """GET /tenants/{tenant_id}/OS-KSCATALOG/endpoints"""
- return self.admin_request(method='GET',
- path='/tenants/%s/OS-KSCATALOG/endpoints' %
- (tenant_id,),
- **kwargs)
-
- def post_tenant_endpoint(self, tenant_id, **kwargs):
- """POST /tenants/{tenant_id}/OS-KSCATALOG/endpoints"""
- return self.admin_request(method='POST',
- path='/tenants/%s/OS-KSCATALOG/endpoints' %
- (tenant_id,), **kwargs)
-
- def delete_tenant_endpoint(self, tenant_id, endpoint_id, **kwargs):
- """DELETE /tenants/{tenant_id}/OS-KSCATALOG/endpoints/{endpoint_id}"""
- return self.admin_request(method='DELETE',
- path='/tenants/%s/OS-KSCATALOG/endpoints/%s' %
- (tenant_id, endpoint_id,),
- **kwargs)
-
- def get_token_endpoints(self, token_id, **kwargs):
- """GET /tokens/{token_id}/endpoints"""
- return self.admin_request(method='GET',
- path='/tokens/%s/endpoints' %
- (token_id,),
- **kwargs)
-
- def post_service(self, **kwargs):
- """POST /services"""
- return self.admin_request(method='POST',
- path='/OS-KSADM/services', **kwargs)
-
- def get_services(self, **kwargs):
- """GET /services"""
- return self.admin_request(method='GET',
- path='/OS-KSADM/services', **kwargs)
-
- def get_service(self, service_id, **kwargs):
- """GET /services/{service_id}"""
- return self.admin_request(method='GET',
- path='/OS-KSADM/services/%s' % (service_id,), **kwargs)
-
- def get_service_by_name(self, service_name, **kwargs):
- """GET /services?name={service_name}"""
- return self.admin_request(method='GET',
- path='/OS-KSADM/services?name=%s' % (service_name,), **kwargs)
-
- def delete_service(self, service_id, **kwargs):
- """DELETE /services/{service_id}"""
- return self.admin_request(method='DELETE',
- path='/OS-KSADM/services/%s' % (service_id,), **kwargs)
-
- def get_root(self, **kwargs):
- """GET /"""
- return self.service_request(method='GET', path='/', **kwargs)
-
- def get_extensions(self, **kwargs):
- """GET /extensions"""
- return self.service_request(method='GET', path='/extensions', **kwargs)
-
- def get_admin_guide(self, **kwargs):
- """GET /identityadminguide.pdf"""
- return self.service_request(method='GET',
- path='/identityadminguide.pdf', **kwargs)
-
- def get_admin_wadl(self, **kwargs):
- """GET /identity-admin.wadl"""
- return self.service_request(method='GET', path='/identity-admin.wadl',
- **kwargs)
-
- def get_common_ent(self, **kwargs):
- """GET /common.ent"""
- return self.service_request(method='GET', path='/common.ent',
- **kwargs)
-
- def get_xsd(self, filename, **kwargs):
- """GET /xsd/{xsd}"""
- return self.service_request(method='GET', path='/xsd/%s' % (filename,),
- **kwargs)
-
- def get_xsd_atom(self, filename, **kwargs):
- """GET /xsd/atom/{xsd}"""
- return self.service_request(method='GET',
- path='/xsd/atom/%s' % (filename,), **kwargs)
-
- def get_xslt(self, filename, **kwargs):
- """GET /xslt/{file:.*}"""
- return self.service_request(method='GET',
- path='/xslt/%s' % (filename,), **kwargs)
-
- def get_javascript(self, filename, **kwargs):
- """GET /js/{file:.*}"""
- return self.service_request(method='GET', path='/js/%s' % (filename,),
- **kwargs)
-
- def get_style(self, filename, **kwargs):
- """GET /style/{file:.*}"""
- return self.service_request(method='GET',
- path='/style/%s' % (filename,), **kwargs)
-
- def get_sample(self, filename, **kwargs):
- """GET /samples/{file:.*}"""
- return self.service_request(method='GET',
- path='/samples/%s' % (filename,), **kwargs)
-
- def get_user_credentials(self, user_id, **kwargs):
- """GET /users/{user_id}/OS-KSADM/credentials"""
- return self.admin_request(method='GET',
- path='/users/%s/OS-KSADM/credentials' % (user_id,), **kwargs)
-
- def get_user_credentials_by_type(self,
- user_id, credentials_type, **kwargs):
- """GET /users/{user_id}/OS-KSADM/credentials/{credentials_type}"""
- return self.admin_request(method='GET',
- path='/users/%s/OS-KSADM/credentials/%s'\
- % (user_id, credentials_type,), **kwargs)
-
- def post_credentials(self, user_id, **kwargs):
- """POST /users/{user_id}/OS-KSADM/credentials"""
- return self.admin_request(method='POST',
- path='/users/%s/OS-KSADM/credentials' % (user_id,), **kwargs)
-
- def post_credentials_by_type(self, user_id, credentials_type, **kwargs):
- """POST /users/{user_id}/OS-KSADM/credentials/{credentials_type}"""
- return self.admin_request(method='POST',
- path='/users/%s/OS-KSADM/credentials/%s' %\
- (user_id, credentials_type), **kwargs)
-
- def delete_user_credentials_by_type(self, user_id,
- credentials_type, **kwargs):
- """DELETE /users/{user_id}/OS-KSADM/credentials/{credentials_type}"""
- return self.admin_request(method='DELETE',
- path='/users/%s/OS-KSADM/credentials/%s' %\
- (user_id, credentials_type,), **kwargs)
-
-
-def unique_str():
- """Generates and return a unique string"""
- return str(uuid.uuid4())
-
-
-def unique_email():
- """Generates and return a unique email"""
- return "%s@openstack.org" % unique_str()
-
-
-def unique_url():
- """Generates and return a unique email"""
- return "http://%s" % unique_str()
-
-
-def optional_str(val):
- """Automatically populates optional string fields"""
- return val if val is not None else unique_str()
-
-
-def optional_email(val):
- """Automatically populates optional email fields"""
- return val if val is not None else unique_email()
-
-
-def optional_url(val):
- """Automatically populates optional url fields"""
- return val if val is not None else unique_url()
-
-
-class FunctionalTestCase(ApiTestCase):
- """Abstracts functional CRUD of the identity API"""
- admin_user_id = None
-
- admin_token = None
- service_token = None
- expired_admin_token = None
- disabled_admin_token = None
- service_admin_token = None
-
- user = None
- user_token = None
- service_user = None
-
- tenant = None
- tenant_user = None # user with default tenant
- tenant_user_token = None
-
- disabled_tenant = None
- disabled_user = None
-
- xmlns = 'http://docs.openstack.org/identity/api/v2.0'
- xmlns_ksadm = 'http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0'
- xmlns_kscatalog = "http://docs.openstack.org/identity/api/ext"\
- + "/OS-KSCATALOG/v1.0"
-
- def setUp(self):
- """Prepare keystone for system tests"""
- super(FunctionalTestCase, self).setUp()
-
- # Authenticate as admin user to establish admin_token
- access = self.authenticate(self.admin_username, self.admin_password).\
- json['access']
-
- self.admin_token = access['token']['id']
- self.admin_user_id = access['user']['id']
-
- def fixture_create_service_admin(self):
- if self.service_user:
- return
- # SERVICE ADMIN
- password = unique_str()
- self.service_user = self.fixture_create_user(
- name="service-user-%s" % uuid.uuid4().hex, enabled=True,
- password=password)
- self.service_user['password'] = password
-
- self.service_admin_role = self.fetch_role_by_name(
- self.service_admin_role_name,
- assert_status=200).json['role']
- self.grant_global_role_to_user(self.service_user['id'],
- self.service_admin_role['id'],
- assert_status=201)
-
- self.service_user_token = self.authenticate(self.service_user['name'],
- self.service_user['password']).\
- json['access']['token']
- self.service_admin_token = self.service_user_token['id']
-
- def fixture_create_normal_tenant(self):
- if self.tenant:
- return
- # TENANT
- self.tenant = self.fixture_create_tenant(
- name="tenant-%s" % uuid.uuid4().hex, enabled=True)
-
- def fixture_create_disabled_tenant(self):
- if self.disabled_tenant:
- return
- # DISABLED TENANT
- self.disabled_tenant = self.fixture_create_tenant(
- name="disabled-tenant-%s" % uuid.uuid4().hex, enabled=False)
-
- def fixture_create_normal_user(self):
- if self.user:
- return
- # USER
- password = unique_str()
- self.user = self.fixture_create_user(
- name="user-%s" % uuid.uuid4().hex, enabled=True,
- password=password)
- self.user['password'] = password
-
- self.user_token = self.authenticate(self.user['name'],
- self.user['password']).\
- json['access']['token']
-
- def fixture_create_tenant_user(self):
- if self.tenant_user:
- return
- self.fixture_create_tenant()
- # USER with DEFAULT TENANT
- password = unique_str()
- self.tenant_user = self.fixture_create_user(
- name="user_in_tenant-%s" % uuid.uuid4().hex, enabled=True,
- tenant_id=self.tenant.id, password=password)
- self.tenant_user['password'] = password
-
- self.tenant_user_token = self.authenticate(self.tenant_user['name'],
- self.tenant_user['password'],
- self.tenant.id).\
- json['access']['token']
-
- def fixture_create_disabled_user_and_token(self):
- if self.disabled_user:
- return
- self.fixture_create_normal_tenant()
- # DISABLED USER
- self.disabled_user = self.fixture_create_user(
- name="disabled_user-%s" % uuid.uuid4().hex, enabled=False)
-
- # TOKEN for DISABLED user
- token = self.fixture_create_token(
- id="disabled-user-tenant-token-%s" % uuid.uuid4().hex,
- user_id=self.disabled_user.id,
- tenant_id=self.tenant.id,
- expires=datetime.datetime.now() + datetime.timedelta(1))
- self.disabled_admin_token = token.id
-
- def fixture_create_expired_token(self):
- if self.expired_admin_token:
- return
- self.fixture_create_normal_tenant()
- # EXPIRED token (for enabled user)
- token = self.fixture_create_token(
- id="expired-admin-token-%s" % uuid.uuid4().hex,
- user_id=self.admin_user_id,
- tenant_id=self.tenant.id,
- expires=datetime.datetime.now() - datetime.timedelta(1))
- self.expired_admin_token = token.id
-
- def authenticate(self, user_name=None, user_password=None, tenant_id=None,
- **kwargs):
- user_name = optional_str(user_name)
- user_password = optional_str(user_password)
-
- data = {
- "auth": {
- "passwordCredentials": {
- "username": user_name,
- "password": user_password}}}
- if tenant_id:
- data["auth"]["tenantId"] = tenant_id
-
- return self.post_token(as_json=data, **kwargs)
-
- def authenticate_D5(self, user_name=None, user_password=None,
- tenant_id=None, **kwargs):
- user_name = optional_str(user_name)
- user_password = optional_str(user_password)
-
- data = {"passwordCredentials": {
- "username": user_name,
- "password": user_password}}
- if tenant_id:
- data["passwordCredentials"]["tenantId"] = tenant_id
-
- return self.post_token(as_json=data, **kwargs)
-
- def authenticate_using_token(self, token, tenant_id=None,
- **kwargs):
-
- data = {
- "auth": {
- "token": {
- "id": token}}}
-
- if tenant_id:
- data["auth"]["tenantId"] = tenant_id
-
- return self.post_token(as_json=data, **kwargs)
-
- def validate_token(self, token_id=None, tenant_id=None, **kwargs):
- token_id = optional_str(token_id)
-
- if tenant_id:
- # validate scoped token
- return self.get_token_belongsto(token_id, tenant_id, **kwargs)
- else:
- # validate unscoped token
- return self.get_token(token_id, **kwargs)
-
- def remove_token(self, token_id=None, **kwargs):
- token_id = optional_str(token_id)
- return self.delete_token(token_id, **kwargs)
-
- def create_tenant(self, tenant_name=None, tenant_description=None,
- tenant_enabled=True, **kwargs):
- """Creates a tenant for testing
-
- The tenant name and description are generated from UUIDs.
- """
- tenant_name = optional_str(tenant_name)
- tenant_description = optional_str(tenant_description)
-
- data = {
- "tenant": {
- "name": tenant_name,
- "description": tenant_description,
- "enabled": tenant_enabled}}
-
- return self.post_tenant(as_json=data, **kwargs)
-
- def list_tenants(self, **kwargs):
- return self.get_tenants(**kwargs)
-
- def fetch_tenant(self, tenant_id=None, **kwargs):
- tenant_id = optional_str(tenant_id)
- return self.get_tenant(tenant_id, **kwargs)
-
- def fetch_tenant_by_name(self, tenant_name=None, **kwargs):
- tenant_name = optional_str(tenant_name)
- if tenant_name:
- return self.get_tenant_by_name(tenant_name, **kwargs)
-
- def update_tenant(self, tenant_id=None, tenant_name=None,
- tenant_description=None, tenant_enabled=True, **kwargs):
- tenant_id = optional_str(tenant_id)
- tenant_description = optional_str(tenant_description)
-
- data = {"tenant": {}}
-
- if tenant_name is not None:
- data['tenant']['name'] = tenant_name
-
- data['tenant']['description'] = tenant_description
-
- if tenant_enabled is not None:
- data['tenant']['enabled'] = tenant_enabled
-
- return self.post_tenant_for_update(tenant_id, as_json=data, **kwargs)
-
- def list_tenant_users(self, tenant_id, role_id=None, **kwargs):
- tenant_id = optional_str(tenant_id)
- if role_id:
- return self.get_tenant_users_by_role(tenant_id, role_id, **kwargs)
- else:
- return self.get_tenant_users(tenant_id, **kwargs)
-
- def remove_tenant(self, tenant_id=None, **kwargs):
- tenant_id = optional_str(tenant_id)
- return self.delete_tenant(tenant_id, **kwargs)
-
- def create_user(self, user_name=None, user_password=None, user_email=None,
- tenant_id=None, user_enabled=True, **kwargs):
- """Creates a user for testing
-
- The user name is generated from UUIDs.
- """
- user_name = optional_str(user_name)
- user_password = optional_str(user_password)
- user_email = optional_email(user_email)
-
- data = {
- "user": {
- "password": user_password,
- "name": user_name,
- "tenantId": tenant_id,
- "email": user_email,
- "enabled": user_enabled}}
-
- return self.post_user(as_json=data, **kwargs)
-
- def create_user_with_known_password(self, **kwargs):
- """Manually injects the new user's password into the response data"""
-
- password = unique_str()
- r = self.create_user(user_password=password, **kwargs)
- r.json['user']['password'] = password
- return r
-
- def list_users(self, **kwargs):
- return self.get_users(**kwargs)
-
- def fetch_user(self, user_id=None, **kwargs):
- user_id = optional_str(user_id)
- return self.get_user(user_id, **kwargs)
-
- def fetch_user_by_name(self, user_name=None, **kwargs):
- user_name = optional_str(user_name)
- return self.query_user(user_name, **kwargs)
-
- def update_user(self, user_id=None, user_email=None, user_enabled=None,
- user_name=None, **kwargs):
- user_id = optional_str(user_id)
-
- data = {"user": {}}
-
- if user_email is not None:
- data['user']['email'] = user_email
-
- if user_enabled is not None:
- data['user']['enabled'] = user_enabled
- if user_name is not None:
- data['user']['name'] = user_name
- return self.post_user_for_update(user_id, as_json=data, **kwargs)
-
- def update_user_password(self, user_id=None, user_password=None, **kwargs):
- user_id = optional_str(user_id)
- user_password = optional_str(user_password)
-
- data = {"user": {"password": user_password}}
- return self.put_user_password(user_id, as_json=data, **kwargs)
-
- def update_user_tenant(self, user_id=None, tenant_id=None, **kwargs):
- user_id = optional_str(user_id)
- tenant_id = optional_str(tenant_id)
-
- data = {"user": {"tenantId": tenant_id}}
- return self.put_user_tenant(user_id, as_json=data, **kwargs)
-
- def _enable_disable_user(self, user_id, user_enabled, **kwargs):
- """Private function to enable and disable a user.
-
- Use enable_user() and disable_user() instead."""
- data = {"user": {"enabled": user_enabled}}
-
- return self.put_user_enabled(user_id, as_json=data, **kwargs)
-
- def enable_user(self, user_id=None, **kwargs):
- user_id = optional_str(user_id)
- return self._enable_disable_user(user_id, True, **kwargs)
-
- def disable_user(self, user_id=None, **kwargs):
- user_id = optional_str(user_id)
- return self._enable_disable_user(user_id, False, **kwargs)
-
- def remove_user(self, user_id=None, **kwargs):
- user_id = optional_str(user_id)
- return self.delete_user(user_id, **kwargs)
-
- def grant_role_to_user(self, user_id=None, role_id=None, tenant_id=None,
- **kwargs):
- user_id = optional_str(user_id)
- role_id = optional_str(role_id)
- tenant_id = optional_str(tenant_id)
- return self.put_user_role(user_id, role_id, tenant_id, **kwargs)
-
- def grant_global_role_to_user(self, user_id=None, role_id=None,
- **kwargs):
- user_id = optional_str(user_id)
- role_id = optional_str(role_id)
- return self.put_user_role(user_id, role_id, None, **kwargs)
-
- def revoke_global_role_from_user(self,
- user_id=None, role_id=None, **kwargs):
- user_id = optional_str(user_id)
- role_id = optional_str(role_id)
- return self.delete_user_role(user_id, role_id, **kwargs)
-
- def revoke_role_from_user(self,
- user_id=None, role_id=None, tenant_id=None, **kwargs):
- user_id = optional_str(user_id)
- role_id = optional_str(role_id)
- tenant_id = optional_str(tenant_id)
- return self.delete_user_role(user_id, tenant_id, **kwargs)
-
- def create_role(self, role_name=None, role_description=None,
- service_id=None, service_name=None, **kwargs):
- """Creates a role for testing
-
- The role name and description are generated from UUIDs.
- """
- if service_name and not role_name:
- role_name = "%s:%s" % (service_name, optional_str(role_name))
- else:
- role_name = optional_str(role_name)
- role_description = optional_str(role_description)
-
- data = {
- "role": {
- "name": role_name,
- "description": role_description}}
-
- if service_id is not None:
- data['role']['serviceId'] = service_id
-
- return self.post_role(as_json=data, **kwargs)
-
- def list_roles(self, service_id=None, **kwargs):
- if service_id is None:
- return self.get_roles(**kwargs)
- else:
- return self.get_roles_by_service(service_id, **kwargs)
-
- def fetch_role(self, role_id=None, **kwargs):
- role_id = optional_str(role_id)
- return self.get_role(role_id, **kwargs)
-
- def fetch_role_by_name(self, role_name=None, **kwargs):
- role_name = optional_str(role_name)
- return self.get_role_by_name(role_name, **kwargs)
-
- def remove_role(self, role_id=None, **kwargs):
- role_id = optional_str(role_id)
- return self.delete_role(role_id, **kwargs)
-
- def create_service(self, service_name=None, service_type=None,
- service_description=None, **kwargs):
- service_name = optional_str(service_name)
- if service_type is None:
- service_type = ['compute', 'identity', 'image-service',
- 'object-store', 'ext:extension-service'
- ][random.randrange(5)]
- service_description = optional_str(service_description)
- data = {
- "OS-KSADM:service": {
- "name": service_name,
- "type": service_type,
- "description": service_description}}
- return self.post_service(as_json=data, **kwargs)
-
- def list_services(self, **kwargs):
- return self.get_services(**kwargs)
-
- def fetch_service(self, service_id=None, **kwargs):
- service_id = optional_str(service_id)
- return self.get_service(service_id, **kwargs)
-
- def fetch_service_by_name(self, service_name=None, **kwargs):
- service_name = optional_str(service_name)
- return self.get_service_by_name(service_name, **kwargs)
-
- def remove_service(self, service_id=None, **kwargs):
- service_id = optional_str(service_id)
- self.delete_service(service_id, **kwargs)
-
- def create_endpoint_for_tenant(self, tenant_id=None,
- endpoint_template_id=None, **kwargs):
- tenant_id = optional_str(tenant_id)
- endpoint_template_id = optional_str(endpoint_template_id)
-
- data = {"OS-KSCATALOG:endpointTemplate": {"id": endpoint_template_id}}
-
- return self.post_tenant_endpoint(tenant_id, as_json=data, **kwargs)
-
- def list_tenant_endpoints(self, tenant_id=None, **kwargs):
- tenant_id = optional_str(tenant_id)
- return self.get_tenant_endpoints(tenant_id, **kwargs)
-
- def remove_endpoint_from_tenant(self, tenant_id=None, endpoint_id=None,
- **kwargs):
- tenant_id = optional_str(tenant_id)
- endpoint_id = optional_str(endpoint_id)
-
- """TODO: Should this be an 'endpoint_id' or 'endpoint_template_id'??"""
- return self.delete_tenant_endpoint(tenant_id, endpoint_id, **kwargs)
-
- def remove_tenant_endpoint(self, tenant_id=None, endpoint_id=None,
- **kwargs):
- tenant_id = optional_str(tenant_id)
- endpoint_id = optional_str(endpoint_id)
-
- """TODO: Should this be an 'endpoint_id' or 'endpoint_template_id'??"""
- return self.delete_tenant_endpoint(tenant_id, endpoint_id, **kwargs)
-
- def list_endpoint_templates(self, service_id=None, **kwargs):
- if service_id is None:
- return self.get_endpoint_templates(**kwargs)
- else:
- return self.get_endpoint_templates_by_service(service_id, **kwargs)
-
- def create_endpoint_template(self, region=None, name=None, type=None,
- public_url=None, admin_url=None, internal_url=None, enabled=True,
- is_global=True, version_id=None,
- version_list=None, version_info=None, **kwargs):
-
- region = optional_str(region)
- name = optional_str(name)
- type = optional_str(type)
- public_url = optional_url(public_url)
- admin_url = optional_url(admin_url)
- internal_url = optional_url(internal_url)
- version_id = optional_str(version_id)[:20]
- version_list = optional_str(version_list)
- version_info = optional_str(version_info)
-
- data = {
- "OS-KSCATALOG:endpointTemplate": {
- "region": region,
- "name": name,
- "type": type,
- "publicURL": public_url,
- "adminURL": admin_url,
- "internalURL": internal_url,
- "enabled": enabled,
- "global": is_global,
- "versionId": version_id,
- "versionInfo": version_info,
- "versionList": version_list}}
- return self.post_endpoint_template(as_json=data, **kwargs)
-
- def remove_endpoint_template(self, endpoint_template_id=None, **kwargs):
- endpoint_template_id = optional_str(endpoint_template_id)
- return self.delete_endpoint_template(endpoint_template_id, **kwargs)
-
- def fetch_endpoint_template(self, endpoint_template_id, **kwargs):
- endpoint_template_id = optional_str(endpoint_template_id)
- return self.get_endpoint_template(endpoint_template_id, **kwargs)
-
- def update_endpoint_template(self, endpoint_template_id=None, region=None,
- name=None, type=None, public_url=None, admin_url=None,
- internal_url=None, enabled=None, is_global=None,
- version_id=None, version_list=None, version_info=None, **kwargs):
-
- data = {"OS-KSCATALOG:endpointTemplate": {}}
-
- if region is not None:
- data['OS-KSCATALOG:endpointTemplate']['region'] = region
-
- if name is not None:
- data['OS-KSCATALOG:endpointTemplate']['name'] = name
-
- if type is not None:
- data['OS-KSCATALOG:endpointTemplate']['type'] = type
-
- if public_url is not None:
- data['OS-KSCATALOG:endpointTemplate']['publicURL'] = public_url
-
- if admin_url is not None:
- data['OS-KSCATALOG:endpointTemplate']['adminURL'] = admin_url
-
- if internal_url is not None:
- data['OS-KSCATALOG:endpointTemplate']['internalURL'] = internal_url
-
- if enabled is not None:
- data['OS-KSCATALOG:endpointTemplate']['enabled'] = enabled
-
- if is_global is not None:
- data['OS-KSCATALOG:endpointTemplate']['global'] = is_global
-
- if version_id is not None:
- data['OS-KSCATALOG:endpointTemplate']['versionId'] = version_id
-
- if version_list is not None:
- data['OS-KSCATALOG:endpointTemplate']['versionList'] = version_list
-
- if version_info is not None:
- data['OS-KSCATALOG:endpointTemplate']['versionInfo'] = version_info
-
- return self.put_endpoint_template(endpoint_template_id, as_json=data,
- **kwargs)
-
- def fetch_user_credentials(self, user_id=None, **kwargs):
- user_id = optional_str(user_id)
- return self.get_user_credentials(user_id, **kwargs)
-
- def fetch_password_credentials(self, user_id=None, **kwargs):
- user_id = optional_str(user_id)
- return self.get_user_credentials_by_type(
- user_id, 'passwordCredentials', **kwargs)
-
- def create_password_credentials(self, user_id, user_name,
- password=None, **kwargs):
- user_id = optional_str(user_id)
- password = optional_str(password)
- data = {
- "passwordCredentials": {
- "username": user_name,
- "password": password}}
- return self.post_credentials(user_id, as_json=data, **kwargs)
-
- def update_password_credentials(self, user_id, user_name,
- password=None, **kwargs):
- user_id = optional_str(user_id)
- password = optional_str(password)
- data = {
- "passwordCredentials": {
- "username": user_name,
- "password": password}}
- return self.post_credentials_by_type(
- user_id, 'passwordCredentials', as_json=data, **kwargs)
-
- def delete_password_credentials(self, user_id, **kwargs):
- user_id = optional_str(user_id)
- return self.delete_user_credentials_by_type(
- user_id, 'passwordCredentials', **kwargs)
-
- def check_urls_for_regular_user(self, service_catalog):
- self.assertIsNotNone(service_catalog)
- for x in range(0, len(service_catalog)):
- endpoints = service_catalog[x]['endpoints']
- for y in range(0, len(endpoints)):
- endpoint = endpoints[y]
- for key in endpoint:
- #Checks whether adminURL is not present.
- self.assertNotEquals(key, 'adminURL')
-
- def check_urls_for_regular_user_xml(self, service_catalog):
- self.assertIsNotNone(service_catalog)
- services = service_catalog.findall('{%s}service' % self.xmlns)
- self.assertIsNotNone(services)
- for service in services:
- endpoints = service.findall('{%s}endpoint' % self.xmlns)
- self.assertIsNotNone(endpoints)
- for endpoint in endpoints:
- #Checks whether adminURL is not present.
- self.assertIsNone(endpoint.get('adminURL'))
- self.assertIsNotNone(service_catalog)
-
- def check_urls_for_admin_user(self, service_catalog):
- self.assertIsNotNone(service_catalog)
- for x in range(0, len(service_catalog)):
- endpoints = service_catalog[x]['endpoints']
- is_admin__url_present = None
- for y in range(0, len(endpoints)):
- endpoint = endpoints[y]
- for key in endpoint:
- if key == 'adminURL':
- is_admin__url_present = True
- self.assertTrue(is_admin__url_present,
- "Admin API does not return admin URL")
-
- def check_urls_for_admin_user_xml(self, service_catalog):
- self.assertIsNotNone(service_catalog)
- services = service_catalog.findall('{%s}service' % self.xmlns)
- self.assertIsNotNone(services)
- is_admin_url_present = None
- for service in services:
- endpoints = service.findall('{%s}endpoint' % self.xmlns)
- self.assertIsNotNone(endpoints)
- for endpoint in endpoints:
- if endpoint.get('adminURL'):
- is_admin_url_present = True
- self.assertTrue(is_admin_url_present,
- "Admin API does not return admin URL")
-
-
-class HeaderApp(object):
- """
- Dummy WSGI app the returns HTTP headers in the body
-
- This is useful for making sure the headers we want
- aer being passwed down to the downstream WSGI app.
- """
- def __init__(self):
- pass
-
- def __call__(self, env, start_response):
- self.request = Request.blank('', environ=env)
- body = ''
- for key in env:
- if key.startswith('HTTP_'):
- body += '%s: %s\n' % (key, env[key])
- return Response(status="200 OK",
- body=body)(env, start_response)
-
-
-class BlankApp(object):
- """
- Dummy WSGI app - does not do anything
- """
- def __init__(self):
- pass
-
- def __call__(self, env, start_response):
- self.request = Request.blank('', environ=env)
- return Response(status="200 OK",
- body={})(env, start_response)
-
-
-class MiddlewareTestCase(FunctionalTestCase):
- """
- Base class to run tests for Keystone WSGI middleware.
- """
- use_server = True
-
- def _setup_test_middleware(self):
- test_middleware = None
- if isinstance(self.middleware, tuple):
- test_middleware = HeaderApp()
- for filter in self.middleware:
- test_middleware = \
- filter.filter_factory(self.settings)(test_middleware)
- else:
- test_middleware = \
- self.middleware.filter_factory(self.settings)(HeaderApp())
- return test_middleware
-
- def setUp(self, middleware, settings=None):
- super(MiddlewareTestCase, self).setUp()
- if settings is None:
- settings = {'delay_auth_decision': '0',
- 'auth_host': client_tests.TEST_TARGET_SERVER_ADMIN_ADDRESS,
- 'auth_port': client_tests.TEST_TARGET_SERVER_ADMIN_PORT,
- 'auth_protocol':
- client_tests.TEST_TARGET_SERVER_ADMIN_PROTOCOL,
- 'auth_uri': ('%s://%s:%s/' % \
- (client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
- client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
- client_tests.TEST_TARGET_SERVER_SERVICE_PORT)),
- 'admin_token': self.admin_token,
- 'admin_user': self.admin_username,
- 'admin_password': self.admin_password}
- cert_file = isSsl()
- if cert_file:
- settings['certfile'] = cert_file
- self.settings = settings
- self.middleware = middleware
- self.test_middleware = self._setup_test_middleware()
-
- name = unique_str()
- r = self.create_tenant(tenant_name=name, assert_status=201)
- self.tenant = r.json.get('tenant')
-
- user_name = unique_str()
- password = unique_str()
- r = self.create_user(user_name=user_name,
- user_password=password,
- tenant_id=self.tenant['id'])
- self.tenant_user = r.json.get('user')
- self.tenant_user['password'] = password
-
- access = self.authenticate(user_name, password).\
- json['access']
- self.tenant_user_token = access['token']
-
- self.services = {}
- self.endpoint_templates = {}
- for x in range(0, 5):
- self.services[x] = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates[x] = self.create_endpoint_template(
- name=self.services[x]['name'], \
- type=self.services[x]['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates[x]['id'])
-
- @unittest.skipIf(isSsl() or 'HP-IDM_Disabled' in os.environ,
- "Skipping SSL or HP-IDM tests")
- def test_with_service_id(self):
- if isSsl() or ('HP-IDM_Disabled' in os.environ):
- # TODO(zns): why is this not skipping with the decorator?!
- raise unittest.SkipTest("Skipping SSL or HP-IDM tests")
- # create a service role so the scope token validation will succeed
- role_resp = self.create_role(service_name=self.services[0]['name'])
- role = role_resp.json['role']
- self.grant_role_to_user(self.tenant_user['id'],
- role['id'], self.tenant['id'])
- auth_resp = self.authenticate(self.tenant_user['name'],
- self.tenant_user['password'],
- self.tenant['id'], assert_status=200)
- user_token = auth_resp.json['access']['token']['id']
- self.settings['service_ids'] = "%s" % self.services[0]['id']
- test_middleware = self._setup_test_middleware()
- resp = Request.blank('/',
- headers={'X-Auth-Token': user_token}) \
- .get_response(test_middleware)
- self.assertEquals(resp.status_int, 200)
-
- # now give it a bogus service ID to make sure we get a 401
- self.settings['service_ids'] = "boguzz"
- test_middleware = self._setup_test_middleware()
- resp = Request.blank('/',
- headers={'X-Auth-Token': user_token}) \
- .get_response(test_middleware)
- self.assertEquals(resp.status_int, 401)
-
- @unittest.skipUnless(not isSsl() and 'HP-IDM_Disabled' in os.environ,
- "Skipping since HP-IDM is enabled")
- def test_with_service_id_with_hpidm_disabled(self):
- # create a service role so the scope token validation will succeed
- role_resp = self.create_role(service_name=self.services[0]['name'])
- role = role_resp.json['role']
- self.grant_role_to_user(self.tenant_user['id'],
- role['id'], self.tenant['id'])
- auth_resp = self.authenticate(self.tenant_user['name'],
- self.tenant_user['password'],
- self.tenant['id'], assert_status=200)
- user_token = auth_resp.json['access']['token']['id']
- self.settings['service_ids'] = "%s" % self.services[0]['id']
- test_middleware = self._setup_test_middleware()
- resp = Request.blank('/',
- headers={'X-Auth-Token': user_token}) \
- .get_response(test_middleware)
- self.assertEquals(resp.status_int, 200)
-
- # now give it a bogus service ID to make sure it got ignored
- self.settings['service_ids'] = "boguzz"
- test_middleware = self._setup_test_middleware()
- resp = Request.blank('/',
- headers={'X-Auth-Token': user_token}) \
- .get_response(test_middleware)
- self.assertEquals(resp.status_int, 200)
-
- def test_401_without_token(self):
- resp = Request.blank('/').get_response(self.test_middleware)
- self.assertEquals(resp.status_int, 401)
- headers = resp.headers
- self.assertTrue("WWW-Authenticate" in headers)
- self.assertEquals(headers['WWW-Authenticate'],
- "Keystone uri='%s://%s:%s/'" % \
- (client_tests.TEST_TARGET_SERVER_SERVICE_PROTOCOL,
- client_tests.TEST_TARGET_SERVER_SERVICE_ADDRESS,
- client_tests.TEST_TARGET_SERVER_SERVICE_PORT))
-
- def test_401_bad_token(self):
- resp = Request.blank('/',
- headers={'X-Auth-Token': 'MADE_THIS_UP'}) \
- .get_response(self.test_middleware)
- self.assertEquals(resp.status_int, 401)
-
- def test_200_good_token(self):
- resp = Request.blank('/',
- headers={'X-Auth-Token': self.tenant_user_token['id']}) \
- .get_response(self.test_middleware)
-
- self.assertEquals(resp.status_int, 200)
-
- headers = resp.body.split('\n')
-
- header = "HTTP_X_IDENTITY_STATUS: Confirmed"
- self.assertTrue(header in headers, "Missing %s" % header)
-
- header = "HTTP_X_USER_ID: %s" % self.tenant_user['id']
- self.assertTrue(header in headers, "Missing %s" % header)
-
- header = "HTTP_X_USER_NAME: %s" % self.tenant_user['name']
- self.assertTrue(header in headers, "Missing %s" % header)
-
- header = "HTTP_X_TENANT_ID: %s" % self.tenant['id']
- self.assertTrue(header in headers, "Missing %s" % header)
-
- header = "HTTP_X_TENANT_NAME: %s" % self.tenant['name']
- self.assertTrue(header in headers, "Missing %s" % header)
-
- # These are here for legacy support and should be removed by F
- header = "HTTP_X_TENANT: %s" % self.tenant['id']
- self.assertTrue(header in headers, "Missing %s" % header)
-
- header = "HTTP_X_USER: %s" % self.tenant_user['id']
- self.assertTrue(header in headers, "Missing %s" % header)
diff --git a/keystone/test/functional/test_auth.py b/keystone/test/functional/test_auth.py
deleted file mode 100644
index 661901fd..00000000
--- a/keystone/test/functional/test_auth.py
+++ /dev/null
@@ -1,494 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestAdminAuthentication(common.FunctionalTestCase):
- """Test admin-side user authentication"""
-
- def test_bootstrapped_admin_user(self):
- """Bootstrap script should create an 'admin' user with 'Admin' role"""
- # Authenticate as admin
- unscoped = self.authenticate(self.admin_username,
- self.admin_password).json['access']
-
- # Assert we get back a token with an expiration date
- self.assertTrue(unscoped['token']['id'])
- self.assertTrue(unscoped['token']['expires'])
-
- # Make sure there's no default tenant going on
- self.assertIsNone(unscoped['token'].get('tenant'))
- self.assertIsNone(unscoped['user'].get('tenantId'))
-
-
-class TestAdminAuthenticationNegative(common.FunctionalTestCase):
- """Negative test admin-side user authentication"""
-
- def test_admin_user_scoping_to_tenant_with_role(self):
- """A Keystone Admin SHOULD be able to retrieve a scoped token...
-
- But only if the Admin has some Role on the Tenant other than Admin.
-
- Formerly:
- test_admin_user_trying_to_scope_to_tenant_with_established_role
- """
- tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
-
- self.grant_role_to_user(self.admin_user_id, role['id'], tenant['id'])
-
- # Try to authenticate for this tenant
- access = self.post_token(as_json={
- 'auth': {
- 'token': {
- 'id': self.admin_token},
- 'tenantId': tenant['id']}}).json['access']
-
- self.assertEqual(access['token']['tenant']['id'], tenant['id'])
-
- def test_admin_user_trying_to_scope_to_tenant(self):
- """A Keystone Admin should NOT be able to retrieve a scoped token"""
- tenant = self.create_tenant().json['tenant']
-
- # Try (and fail) to authenticate for this tenant
- self.post_token(as_json={
- 'auth': {
- 'token': {
- 'id': self.admin_token},
- 'tenantId': tenant['id']}}, assert_status=401)
-
- def test_service_token_as_admin_token(self):
- """Admin actions should fail for mere service tokens"""
-
- # Admin create a user
- password = common.unique_str()
- user = self.create_user(user_password=password).json['user']
- user['password'] = password
-
- # Replace our admin_token with a mere service token
- self.admin_token = self.authenticate(user['name'], user['password']).\
- json['access']['token']['id']
-
- # Try creating another user using the wrong token
- self.create_user(assert_status=401)
-
-
-class TestServiceAuthentication(common.FunctionalTestCase):
- """Test service-side user authentication"""
-
- def setUp(self):
- super(TestServiceAuthentication, self).setUp()
-
- # Create a user
- password = common.unique_str()
- self.user = self.create_user(user_password=password).json['user']
- self.tenant = self.create_tenant().json['tenant']
- self.user['password'] = password
- self.services = {}
- self.endpoint_templates = {}
- self.services = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates = self.create_endpoint_template(
- name=self.services['name'], \
- type=self.services['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates['id'])
-
- def test_authenticate_twice(self):
- """Authenticating twice in a row should not result in a new token
-
- The original token should not have expired and should be provided again
- """
- first_token = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).\
- json['access']['token']['id']
-
- second_token = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).\
- json['access']['token']['id']
-
- self.assertEqual(first_token, second_token)
-
- def test_authenticate_twice_for_tenant(self):
- """Authenticating twice in a row should not result in a new token
-
- The original token should not have expired and should be provided again
- """
- # Additonal setUp
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], self.tenant['id'])
-
- self.service_token = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).\
- json['access']['token']['id']
-
- tenant = self.service_request(method='GET', path='/tenants').\
- json['tenants'][0]
-
- first_token = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantId': tenant['id']}}).json['access']['token']['id']
-
- second_token = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantId': tenant['id']}}).json['access']['token']['id']
-
- # unscoped token should be different than the two scoped tokens
- self.assertNotEqual(self.service_token, first_token)
- self.assertEqual(first_token, second_token)
-
- def test_unscoped_user_auth(self):
- """Admin should be able to validate a user's token"""
- # Authenticate as user to get a token
- self.service_token = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).\
- json['access']['token']['id']
-
- # In the real world, the service user would then pass his/her token
- # to some service that depends on keystone, which would then need to
- # use keystone to validate the provided token.
-
- # Admin independently validates the user token
- r = self.get_token(self.service_token)
- self.assertEqual(r.json['access']['token']['id'], self.service_token)
- self.assertTrue(r.json['access']['token']['expires'])
- self.assertEqual(r.json['access']['user']['id'], self.user['id'])
- self.assertEqual(r.json['access']['user']['name'],
- self.user['name'])
- self.assertEqual(r.json['access']['user']['roles'], [])
-
- def test_user_auth_with_role_on_tenant(self):
- # Additonal setUp
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], self.tenant['id'])
-
- # Create an unscoped token
- unscoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).json['access']
-
- # The token shouldn't be scoped to a tenant nor have roles just yet
- self.assertIsNone(unscoped['token'].get('tenant'))
- self.assertIsNotNone(unscoped.get('user'))
- self.assertIsNotNone(unscoped['user'].get('roles'))
- self.assertEqual(len(unscoped['user']['roles']), 0)
- self.assertEqual(unscoped['user'].get('id'), self.user['id'])
- self.assertEqual(unscoped['user'].get('name'), self.user['name'])
-
- # Request our tenant list as a service user
- self.service_token = unscoped['token']['id']
- tenants = self.service_request(method='GET', path='/tenants').\
- json['tenants']
- self.service_token = None # Should become a service_request() param...
-
- # Our tenant should be the only tenant in the list
- self.assertEqual(len(tenants), 1, tenants)
- self.assertEqual(self.tenant['id'], tenants[0]['id'])
- self.assertEqual(self.tenant['name'], tenants[0]['name'])
- self.assertEqual(self.tenant['description'], tenants[0]['description'])
- self.assertEqual(self.tenant['enabled'], tenants[0]['enabled'])
-
- # We can now get a token scoped to our tenant
- scoped = self.post_token(as_json={
- 'auth': {
- 'token': {
- 'id': unscoped['token']['id']},
- 'tenantId': self.tenant['id']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- self.assertIn('tenants', scoped['token'])
- self.assertEqual(scoped['token']['tenants'][0]['id'],
- self.tenant['id'])
- self.assertEqual(scoped['token']['tenants'][0]['name'],
- self.tenant['name'])
- self.assertEqual(
- scoped['user']['roles'][0]['id'], role['id'])
- self.assertEqual(scoped['user']['roles'][0]['name'], role['name'])
- self.assertEqual(scoped['user']['roles'][0]['tenantId'],
- self.tenant['id'])
-
- # And an admin should be able to validate that our new token is scoped
- r = self.validate_token(scoped['token']['id'], self.tenant['id'])
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(access['token']['tenant']['name'],\
- self.tenant['name'])
-
- def test_user_auth_with_role_on_tenant_xml(self):
- # Additonal setUp
- tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], tenant['id'])
-
- # Create an unscoped token
- r = self.post_token(as_xml='<?xml version="1.0" encoding="UTF-8"?>'
- '<auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"'
- 'xmlns="http://docs.openstack.org/identity/api/v2.0">'
- '<passwordCredentials username="%s" password="%s"/>'
- '</auth>' % (self.user['name'], self.user['password']))
-
- # The token shouldn't be scoped to a tenant nor have roles just yet
- self.assertEqual(r.xml.tag, '{%s}access' % self.xmlns)
-
- token = r.xml.find('{%s}token' % self.xmlns)
- self.assertIsNotNone(token)
- self.assertIsNotNone(token.get('id'))
- self.assertIsNotNone(token.get('expires'))
-
- user = r.xml.find('{%s}user' % self.xmlns)
- self.assertIsNotNone(user)
- self.assertEqual(user.get('id'), self.user['id'])
- self.assertEqual(user.get('name'), self.user['name'])
- self.assertIsNone(user.get('tenantId'))
-
- roles = user.find('{%s}roles' % self.xmlns)
- self.assertIsNotNone(roles)
- self.assertEqual(len(roles), 0)
-
- # Request our tenant list as a service user
- self.service_token = token.get('id')
- r = self.service_request(method='GET', path='/tenants', headers={
- 'Accept': 'application/xml'})
-
- self.assertEqual(r.xml.tag, '{%s}tenants' % self.xmlns)
- tenants = r.xml.findall('{%s}tenant' % self.xmlns)
-
- # Our tenant should be the only tenant in the list
- self.assertEqual(len(tenants), 1, tenants)
- self.assertEqual(tenant['id'], tenants[0].get('id'))
- self.assertEqual(tenant['name'], tenants[0].get('name'))
- self.assertEqual(str(tenant['enabled']).lower(),
- tenants[0].get('enabled'))
- description = tenants[0].find('{%s}description' % self.xmlns)
- self.assertEqual(tenant['description'], description.text)
-
- # We can now get a token scoped to our tenant
- r = self.post_token(as_xml='<?xml version="1.0" encoding="UTF-8"?>'
- '<auth xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" '
- 'xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'tenantId="%s">'
- '<passwordCredentials username="%s" password="%s"/>'
- '</auth>' % (tenant['id'], self.user['name'],
- self.user['password']))
-
- self.assertEqual(r.xml.tag, '{%s}access' % self.xmlns)
-
- token = r.xml.find('{%s}token' % self.xmlns)
- self.assertIsNotNone(token)
- tenant_scope = token.find('{%s}tenant' % self.xmlns)
- self.assertIsNotNone(tenant_scope)
- self.assertEqual(tenant_scope.get('id'), tenant['id'])
- self.assertEqual(tenant_scope.get('name'), tenant['name'])
-
- # And an admin should be able to validate that our new token is scoped
- r = self.validate_token(token.get('id'), tenant['id'], headers={
- 'Accept': 'application/xml'})
- self.assertEqual(r.xml.tag, '{%s}access' % self.xmlns)
-
- token = r.xml.find('{%s}token' % self.xmlns)
- self.assertIsNotNone(token)
- tenant_scope = token.find('{%s}tenant' % self.xmlns)
- self.assertIsNotNone(tenant_scope)
- self.assertEqual(tenant_scope.get('id'), tenant['id'])
- self.assertEqual(tenant_scope.get('name'), tenant['name'])
-
- user = r.xml.find('{%s}user' % self.xmlns)
- self.assertIsNotNone(user)
- self.assertEqual(user.get('id'), self.user['id'])
- self.assertEqual(user.get('name'), self.user['name'])
- self.assertIsNone(user.get('tenantId'))
-
- def test_scope_to_tenant_by_name(self):
- # Additonal setUp
- tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], tenant['id'])
-
- # Create an unscoped token
- unscoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).json['access']
-
- # We can now get a token scoped to our tenant
- scoped = self.post_token(as_json={
- 'auth': {
- 'token': {
- 'id': unscoped['token']['id']},
- 'tenantName': tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'], tenant['name'])
-
- # And an admin should be able to validate that our new token is scoped
- r = self.validate_token(scoped['token']['id'], tenant['id'])
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], tenant['id'])
- self.assertEqual(access['token']['tenant']['name'], tenant['name'])
-
- def test_scope_to_tenant_by_name_with_credentials(self):
- # Additonal setUp
- tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], tenant['id'])
-
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'], tenant['name'])
-
- # And an admin should be able to validate that our new token is scoped
- r = self.validate_token(scoped['token']['id'], tenant['id'])
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], tenant['id'])
- self.assertEqual(access['token']['tenant']['name'], tenant['name'])
-
- def test_user_auth_against_nonexistent_tenant(self):
- # Create an unscoped token
- unscoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).json['access']
-
- # Invalid tenant id
- self.post_token(assert_status=401, as_json={
- 'auth': {
- 'token': {'id': unscoped['token']['id']},
- 'tenantId': common.unique_str()}})
-
- # Invalid tenant name
- self.post_token(assert_status=401, as_json={
- 'auth': {
- 'token': {'id': unscoped['token']['id']},
- 'tenantName': common.unique_str()}})
-
- # Invalid tenant id
- self.post_token(assert_status=401, as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantId': common.unique_str()}})
-
- # Invalid tenant name
- self.post_token(assert_status=401, as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': common.unique_str()}})
-
- def test_scope_to_tenant_by_bad_request(self):
- # Additonal setUp
- tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], tenant['id'])
-
- # Create an unscoped token
- unscoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']}}}).json['access']
-
- # tenant Name & ID should never be provided together
- self.post_token(as_json={
- 'auth': {
- 'tokenId': unscoped['token']['id'],
- 'tenantId': tenant['id'],
- 'tenantName': tenant['name']}}, assert_status=400)
-
- def test_get_request_fails(self):
- """GET /tokens should return a 404 (Github issue #5)"""
- self.service_request(method='GET', path='/tokens', assert_status=404)
-
- def test_user_auth_with_malformed_request_body(self):
- """Authenticating with unnexpected json returns a 400"""
- # Authenticate as user to get a token
- self.post_token(assert_status=400, as_json={
- 'this-is-completely-wrong': {
- 'username': self.user['name'],
- 'password': self.user['password']}})
-
- def test_user_auth_with_wrong_name(self):
- """Authenticating with an unknown username returns a 401"""
- # Authenticate as user to get a token
- self.post_token(assert_status=401, as_json={
- 'auth': {'passwordCredentials': {
- 'username': 'this-is-completely-wrong',
- 'password': self.user['password']}}})
-
- def test_user_auth_with_no_name(self):
- """Authenticating without a username returns a 400"""
- # Authenticate as user to get a token
- self.post_token(assert_status=400, as_json={
- 'auth': {'passwordCredentials': {
- 'password': self.user['password']}}})
-
- def test_user_auth_with_wrong_password(self):
- """Authenticating with an invalid password returns a 401"""
- # Authenticate as user to get a token
- self.post_token(assert_status=401, as_json={
- 'auth': {'passwordCredentials': {
- 'username': self.user['name'],
- 'password': 'this-is-completely-wrong'}}})
-
- def test_user_auth_with_no_password(self):
- """Authenticating with an invalid password returns a 400"""
- # Authenticate as user to get a token
- self.post_token(assert_status=400, as_json={
- 'auth': {'passwordCredentials': {
- 'username': self.user['name'],
- 'password': None}}})
-
- def test_user_auth_with_invalid_tenant(self):
- """Authenticating with an invalid password returns a 401"""
- # Authenticate as user to get a token
- self.post_token(assert_status=401, as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password'],
- },
- 'tenantId': 'this-is-completely-wrong'}})
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_authentication.py b/keystone/test/functional/test_authentication.py
deleted file mode 100644
index a029fbd7..00000000
--- a/keystone/test/functional/test_authentication.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-
-from keystone.test.functional import common
-
-
-class AuthenticationTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(AuthenticationTest, self).setUp(*args, **kwargs)
-
- password = common.unique_str()
- self.tenant = self.create_tenant().json['tenant']
- self.user = self.create_user(user_password=password,
- tenant_id=self.tenant['id']).json['user']
- self.user['password'] = password
-
- self.services = {}
- self.endpoint_templates = {}
- self.services = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates = self.create_endpoint_template(
- name=self.services['name'], \
- type=self.services['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates['id'])
-
- def test_authenticate_for_a_tenant(self):
- response = self.authenticate(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=200)
-
- self.assertIsNotNone(response.json['access']['token'])
- service_catalog = response.json['access']['serviceCatalog']
- self.assertIsNotNone(service_catalog)
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" tenantId="%s">'
- '<passwordCredentials username="%s" password="%s" '
- '/> </auth>') % (
- self.xmlns, self.tenant['id'],
- self.user['name'], self.user['password'])
- response = self.post_token(as_xml=data, assert_status=200)
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_for_a_tenant_on_admin_api(self):
- response = self.authenticate(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=200, request_type='admin')
-
- self.assertIsNotNone(response.json['access']['token'])
- self.assertIsNotNone(response.json['access']['serviceCatalog'])
- service_catalog = response.json['access']['serviceCatalog']
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml_on_admin_api(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" tenantId="%s">'
- '<passwordCredentials username="%s" password="%s" '
- '/> </auth>') % (
- self.xmlns, self.tenant['id'],
- self.user['name'], self.user['password'])
- response = self.post_token(as_xml=data, assert_status=200,
- request_type='admin')
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_user_disabled(self):
- self.disable_user(self.user['id'])
- self.authenticate(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=403)
-
- def test_authenticate_user_wrong(self):
- data = {
- "auth": {
- "passwordCredentials": {
- "username-field-completely-wrong": self.user['name'],
- "password": self.user['password']},
- "tenantId": self.tenant['id']}}
- self.post_token(as_json=data, assert_status=400)
-
- def test_authenticate_user_wrong_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials '
- 'xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'usernamefieldcompletelywrong="%s" '
- 'password="%s" '
- 'tenantId="%s"/>') % (
- self.user['name'], self.user['password'], self.tenant['id'])
-
- self.post_token(as_xml=data, assert_status=400)
-
-
-class AuthenticationUsingTokenTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(AuthenticationUsingTokenTest, self).setUp(*args, **kwargs)
- password = common.unique_str()
- self.tenant = self.create_tenant().json['tenant']
- self.user = self.create_user(user_password=password,
- tenant_id=self.tenant['id']).json['user']
- self.user['password'] = password
-
- self.services = {}
- self.endpoint_templates = {}
- for x in range(0, 5):
- self.services[x] = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates[x] = self.create_endpoint_template(
- name=self.services[x]['name'], \
- type=self.services[x]['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates[x]['id'])
- self.token = self.authenticate(self.user['name'],
- self.user['password']).json['access']['token']['id']
-
- def test_authenticate_for_a_tenant_using_token(self):
- response = self.authenticate_using_token(self.token,
- self.tenant['id'], assert_status=200)
-
- self.assertIsNotNone(response.json['access']['token'])
- service_catalog = response.json['access']['serviceCatalog']
- self.assertIsNotNone(service_catalog)
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" tenantId="%s">'
- '<token id="%s" '
- '/> </auth>') % (
- self.xmlns, self.tenant['id'],
- self.token)
- response = self.post_token(as_xml=data, assert_status=200)
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_for_a_tenant_on_admin_api(self):
- response = self.authenticate_using_token(self.token,
- self.tenant['id'], request_type='admin')
-
- self.assertIsNotNone(response.json['access']['token'])
- self.assertIsNotNone(response.json['access']['serviceCatalog'])
- service_catalog = response.json['access']['serviceCatalog']
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml_on_admin_api(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" tenantId="%s">'
- '<token id="%s" '
- '/> </auth>') % (
- self.xmlns, self.tenant['id'],
- self.token)
- response = self.post_token(as_xml=data, assert_status=200,
- request_type='admin')
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
-
-class UnScopedAuthenticationTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(UnScopedAuthenticationTest, self).setUp(*args, **kwargs)
-
- self.tenant = self.create_tenant().json['tenant']
- self.user = self.create_user_with_known_password(
- tenant_id=self.tenant['id']).json['user']
-
- self.services = {}
- self.endpoint_templates = {}
- for x in range(0, 5):
- self.services[x] = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates[x] = self.create_endpoint_template(
- name=self.services[x]['name'], \
- type=self.services[x]['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates[x]['id'])
-
- def test_authenticate(self):
- response = self.authenticate(self.user['name'], self.user['password'],\
- assert_status=200)
-
- self.assertIsNotNone(response.json['access']['token'])
- service_catalog = response.json['access'].get('serviceCatalog')
- self.assertIsNotNone(service_catalog, response.json)
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" >'
- '<passwordCredentials username="%s" password="%s" '
- '/> </auth>') % (
- self.xmlns, self.user['name'],
- self.user['password'])
- response = self.post_token(as_xml=data, assert_status=200)
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_on_admin_api(self):
- response = self.authenticate(self.user['name'], self.user['password'],
- assert_status=200, request_type='admin')
-
- self.assertIsNotNone(response.json['access'].get('token'),
- response.json)
- self.assertIsNotNone(response.json['access'].get('serviceCatalog'),
- response.json)
- service_catalog = response.json['access']['serviceCatalog']
- self.check_urls_for_regular_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml_on_admin_api(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" tenantId="%s">'
- '<passwordCredentials username="%s" password="%s" '
- '/> </auth>') % (
- self.xmlns, self.tenant['id'],
- self.user['name'], self.user['password'])
- response = self.post_token(as_xml=data,
- assert_status=200, request_type='admin')
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_regular_user_xml(service_catalog)
-
- def test_authenticate_without_default_tenant(self):
- # Create user with no default tenant set (but granted a role)
- self.nodefaultuser = self.create_user_with_known_password()\
- .json['user']
- self.role = self.create_role().json['role']
- self.grant_role_to_user(self.nodefaultuser['id'], self.role['id'],
- self.tenant['id'])
-
- response = self.authenticate(self.nodefaultuser['name'],
- self.nodefaultuser['password'],
- tenant_id=None, assert_status=200)
-
- self.assertIsNotNone(response.json['access']['token'])
- self.assertNotIn('tenant', response.json['access']['token'])
-
-
-class AdminUserAuthenticationTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(AdminUserAuthenticationTest, self).setUp(*args, **kwargs)
-
- password = common.unique_str()
- self.tenant = self.create_tenant().json['tenant']
- self.user = self.create_user(user_password=password,
- tenant_id=self.tenant['id']).json['user']
- self.role = self.get_role_by_name('Admin').json['role']
- self.grant_global_role_to_user(self.user['id'], self.role['id'])
- self.user['password'] = password
-
- self.services = {}
- self.endpoint_templates = {}
- for x in range(0, 5):
- self.services[x] = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates[x] = self.create_endpoint_template(
- name=self.services[x]['name'], \
- type=self.services[x]['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates[x]['id'])
-
- def test_authenticate(self):
- response = self.authenticate(self.user['name'], self.user['password'],\
- assert_status=200)
-
- self.assertIsNotNone(response.json['access']['token'])
- service_catalog = response.json['access']['serviceCatalog']
- self.assertIsNotNone(service_catalog)
- self.check_urls_for_admin_user(service_catalog)
-
- def test_authenticate_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" >'
- '<passwordCredentials username="%s" password="%s" '
- '/> </auth>') % (
- self.xmlns, self.user['name'],
- self.user['password'])
- response = self.post_token(as_xml=data, assert_status=200)
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_admin_user_xml(service_catalog)
-
- def test_authenticate_for_a_tenant(self):
- response = self.authenticate(self.user['name'], self.user['password'],
- self.tenant['id'], assert_status=200)
-
- self.assertIsNotNone(response.json['access']['token'])
- service_catalog = response.json['access']['serviceCatalog']
- self.assertIsNotNone(service_catalog)
- self.check_urls_for_admin_user(service_catalog)
-
- def test_authenticate_for_a_tenant_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<auth xmlns="%s" tenantId="%s">'
- '<passwordCredentials username="%s" password="%s" '
- '/> </auth>') % (
- self.xmlns, self.tenant['id'],
- self.user['name'], self.user['password'])
- response = self.post_token(as_xml=data, assert_status=200)
-
- self.assertEquals(response.xml.tag, '{%s}access' % self.xmlns)
- service_catalog = response.xml.find('{%s}serviceCatalog' % self.xmlns)
- self.check_urls_for_admin_user_xml(service_catalog)
-
-
-class MultiTokenTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(MultiTokenTest, self).setUp(*args, **kwargs)
-
- self.tenants = {}
- self.users = {}
- for x in range(0, 2):
- self.tenants[x] = self.create_tenant().json['tenant']
-
- password = common.unique_str()
- self.users[x] = self.create_user(user_password=password,
- tenant_id=self.tenants[x]['id']).json['user']
- self.users[x]['password'] = password
-
- def test_unassigned_user(self):
- self.authenticate(self.users[1]['name'], self.users[1]['password'],
- self.tenants[0]['id'], assert_status=401)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_credentials.py b/keystone/test/functional/test_credentials.py
deleted file mode 100644
index 2db01579..00000000
--- a/keystone/test/functional/test_credentials.py
+++ /dev/null
@@ -1,231 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestGetCredentials(common.FunctionalTestCase):
- """Test Get credentials operations"""
-
- def setUp(self):
- super(TestGetCredentials, self).setUp()
- self.fixture_create_normal_user()
-
- def test_get_user_credentials(self):
- password_credentials = self.fetch_user_credentials(
- self.user['id']).json['credentials'][0]['passwordCredentials']
- self.assertEquals(password_credentials['username'], self.user['name'])
-
- def test_get_user_credentials_xml(self):
- r = self.fetch_user_credentials(self.user['id'],
- assert_status=200, headers={
- 'Accept': 'application/xml'})
- self.assertEquals(r.xml.tag, '{%s}credentials' % self.xmlns)
- password_credentials =\
- r.xml.find('{%s}passwordCredentials' % self.xmlns)
- self.assertEqual(
- password_credentials.get('username'), self.user['name'])
-
- def test_get_user_credentials_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_user_credentials(self.user['id'], assert_status=403)
-
- def test_get_user_credentials_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_user_credentials(self.user['id'], assert_status=403)
-
- def test_get_user_credentials_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_user_credentials(self.user['name'], assert_status=403)
-
- def test_get_user_credentials_using_missing_token(self):
- self.admin_token = ''
- self.fetch_user_credentials(self.user['id'], assert_status=401)
-
- def test_get_user_credentials_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_user_credentials(self.user['id'], assert_status=401)
-
-
-class TestGetPasswordCredentials(common.FunctionalTestCase):
- """Test get password credentials operations"""
-
- def setUp(self):
- super(TestGetPasswordCredentials, self).setUp()
- self.fixture_create_normal_user()
-
- def test_get_user_credentials(self):
- password_credentials = self.fetch_password_credentials(
- self.user['id']).json['passwordCredentials']
- self.assertEquals(password_credentials['username'], self.user['name'])
-
- def test_get_user_credentials_xml(self):
- r = self.fetch_password_credentials(self.user['id'],
- assert_status=200, headers={
- 'Accept': 'application/xml'})
- password_credentials = r.xml
- self.assertEqual(
- password_credentials.get('username'), self.user['name'])
-
- def test_get_user_credentials_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_password_credentials(self.user['id'], assert_status=403)
-
- def test_get_user_credentials_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_password_credentials(self.user['id'], assert_status=403)
-
- def test_get_user_credentials_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_password_credentials(self.user['name'], assert_status=403)
-
- def test_get_user_credentials_using_missing_token(self):
- self.admin_token = ''
- self.fetch_password_credentials(self.user['id'], assert_status=401)
-
- def test_get_user_credentials_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_password_credentials(self.user['id'], assert_status=401)
-
-
-class TestCreatePasswordCredentials(common.FunctionalTestCase):
- """Test create password credentials operations"""
-
- def setUp(self):
- super(TestCreatePasswordCredentials, self).setUp()
- self.fixture_create_normal_user()
- self.delete_user_credentials_by_type(
- self.user['id'], 'passwordCredentials')
-
- def test_create_password_credentials(self):
- self.create_password_credentials(
- self.user['id'], self.user['name'],
- assert_status=201)
-
- def test_create_password_credentials_using_empty_password(self):
- self.create_password_credentials(
- user_id=self.user['id'], user_name=self.user['name'], password='',\
- assert_status=400)
-
- def test_create_password_credentials_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials xmlns="%s"'
- ' username="%s" password="%s"/>') % (
- self.xmlns, self.user['name'], 'passw0rd')
- self.post_credentials(self.user['id'], as_xml=data, assert_status=201)
-
- def test_create_password_credentials_xml_using_empty_password(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials xmlns="%s"'
- ' username="%s" password="%s"/>') % (
- self.xmlns, self.user['name'], '')
- self.post_credentials(self.user['id'], as_xml=data, assert_status=400)
-
- def test_create_password_credentials_twice(self):
- self.create_password_credentials(self.user['id'], self.user['name'],
- assert_status=201)
- self.create_password_credentials(self.user['id'], self.user['name'],
- assert_status=400)
-
- def test_create_password_credentials_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_password_credentials(self.user['id'], self.user['name'],
- assert_status=403)
-
- def test_create_password_credentials_missing_token(self):
- self.admin_token = ''
- self.create_password_credentials(self.user['id'], self.user['name'],
- assert_status=401)
-
- def test_create_password_credentials_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_password_credentials(self.user['id'], self.user['name'],
- assert_status=401)
-
-
-class TestUpdatePasswordCredentials(common.FunctionalTestCase):
- """Test update password credentials operations"""
-
- def setUp(self):
- super(TestUpdatePasswordCredentials, self).setUp()
- self.fixture_create_normal_user()
-
- def test_update_password_credentials(self):
- self.update_password_credentials(self.user['id'], self.user['name'],
- assert_status=200)
-
- def test_update_password_credentials_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<passwordCredentials xmlns="%s"'
- ' username="%s" password="%s"/>') % (
- self.xmlns, self.user['name'], 'passw0rd')
- self.post_credentials_by_type(self.user['id'], 'passwordCredentials',
- as_xml=data, assert_status=200)
-
- def test_update_password_credentials_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.update_password_credentials(self.user['id'], self.user['name'],
- assert_status=403)
-
- def test_update_password_credentials_missing_token(self):
- self.admin_token = ''
- self.update_password_credentials(self.user['id'], self.user['name'],
- assert_status=401)
-
- def test_update_password_credentials_invalid_token(self):
- self.admin_token = common.unique_str()
- self.update_password_credentials(self.user['id'], self.user['name'],
- assert_status=401)
-
-
-class TestDeletePasswordCredentials(common.FunctionalTestCase):
- """Test delete password credentials operations"""
-
- def setUp(self):
- super(TestDeletePasswordCredentials, self).setUp()
- self.fixture_create_normal_user()
-
- def test_delete_password_credentials(self):
- self.delete_password_credentials(self.user['id'],
- assert_status=204)
-
- def test_delete_password_credentials_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.delete_password_credentials(self.user['id'],
- assert_status=403)
-
- def test_delete_password_credentials_missing_token(self):
- self.admin_token = ''
- self.delete_password_credentials(self.user['id'],
- assert_status=401)
-
- def test_delete_password_credentials_invalid_token(self):
- self.admin_token = common.unique_str()
- self.delete_password_credentials(self.user['id'],
- assert_status=401)
-
-
-class TestAuthentication(common.FunctionalTestCase):
- """Test authentication after a password update."""
- def setUp(self):
- super(TestAuthentication, self).setUp()
- self.fixture_create_normal_user()
-
- def test_authentication_after_password_change(self):
- self.authenticate(self.user['name'], self.user['password'],
- assert_status=200)
- password = common.unique_str()
- self.update_password_credentials(self.user['id'], self.user['name'],
- password=password, assert_status=200)
- self.authenticate(self.user['name'], password,
- assert_status=200)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_endpoints.py b/keystone/test/functional/test_endpoints.py
deleted file mode 100644
index 9f7c989e..00000000
--- a/keystone/test/functional/test_endpoints.py
+++ /dev/null
@@ -1,740 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-from keystone.test.functional import common
-
-
-class EndpointTemplatesTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(EndpointTemplatesTest, self).setUp(*args, **kwargs)
-
- self.service = self.create_service().json['OS-KSADM:service']
-
- self.endpoint_template = self.create_endpoint_template(
- name=self.service['name'], \
- type=self.service['type']).\
- json['OS-KSCATALOG:endpointTemplate']
-
- self.fixture_create_service_admin()
- admin_token = self.admin_token
- self.admin_token = self.service_admin_token
- self.my_service = self.create_service().json['OS-KSADM:service']
- self.admin_token = admin_token
-
-
-class CreateEndpointTemplatesTest(EndpointTemplatesTest):
- def test_create_endpoint_template(self):
- endpoint_template = self.create_endpoint_template(
- name=self.service['name'],
- type=self.service['type'],
- assert_status=201).\
- json['OS-KSCATALOG:endpointTemplate']
-
- self.assertIsNotNone(endpoint_template['id'], endpoint_template)
- self.assertIsNotNone(endpoint_template['name'], endpoint_template)
- self.assertIsNotNone(endpoint_template['type'], endpoint_template)
-
- def test_create_endpoint_template_with_empty_name(self):
- self.create_endpoint_template(
- name=self.service['name'],
- type='',
- assert_status=400)
-
- def test_create_endpoint_template_with_empty_type(self):
- self.create_endpoint_template(
- name='',
- type=self.service['type'],
- assert_status=400)
-
- def test_create_endpoint_template_xml(self):
- region = common.unique_str()
- public_url = common.unique_url()
- admin_url = common.unique_url()
- internal_url = common.unique_url()
- enabled = True
- is_global = True
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate xmlns="%s" region="%s" name="%s" '
- 'type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>'
- ) % (self.xmlns_kscatalog, region, self.service['name'],
- self.service['type'], public_url, admin_url, internal_url,
- enabled, is_global)
- r = self.post_endpoint_template(as_xml=data, assert_status=201)
-
- self.assertEqual(r.xml.tag,
- '{%s}endpointTemplate' % self.xmlns_kscatalog)
-
- self.assertIsNotNone(r.xml.get("id"))
- self.assertEqual(r.xml.get("name"), self.service['name'])
- self.assertEqual(r.xml.get("type"), self.service['type'])
- self.assertEqual(r.xml.get("region"), region)
- self.assertEqual(r.xml.get("publicURL"), public_url)
- self.assertEqual(r.xml.get("adminURL"), admin_url)
- self.assertEqual(r.xml.get("internalURL"), internal_url)
- self.assertEqual(r.xml.get("enabled"), str(enabled).lower())
- self.assertEqual(r.xml.get("global"), str(is_global).lower())
-
- def test_create_endpoint_template_xml_using_empty_type(self):
- region = common.unique_str()
- public_url = common.unique_url()
- admin_url = common.unique_url()
- internal_url = common.unique_url()
- enabled = True
- is_global = True
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate xmlns="%s" region="%s" name="%s" '
- 'type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>'
- ) % (self.xmlns_kscatalog, region, self.service['name'],
- '', public_url, admin_url, internal_url,
- enabled, is_global)
- self.post_endpoint_template(as_xml=data, assert_status=400)
-
- def test_create_endpoint_template_xml_using_empty_name(self):
- region = common.unique_str()
- public_url = common.unique_url()
- admin_url = common.unique_url()
- internal_url = common.unique_url()
- enabled = True
- is_global = True
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate xmlns="%s" region="%s" name="%s" '
- 'type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>'
- ) % (self.xmlns_kscatalog, region, '',
- self.service['type'], public_url, admin_url, internal_url,
- enabled, is_global)
- self.post_endpoint_template(as_xml=data, assert_status=400)
-
- def test_delete_endpoint_template_that_has_dependencies(self):
- tenant = self.create_tenant().json['tenant']
-
- self.create_endpoint_for_tenant(tenant['id'],
- self.endpoint_template['id'], assert_status=201)
-
- self.remove_endpoint_template(self.endpoint_template['id'],
- assert_status=204)
-
- def test_create_endpoint_template_using_service_admin_token(self):
- self.admin_token = self.service_admin_token
- endpoint_template = self.create_endpoint_template(
- name=self.my_service['name'],
- type=self.my_service['type'],
- assert_status=201).\
- json['OS-KSCATALOG:endpointTemplate']
-
- self.assertIsNotNone(endpoint_template['id'])
- self.assertEqual(endpoint_template['name'], self.my_service['name'])
- self.assertEqual(endpoint_template['type'], self.my_service['type'])
-
-
-class GetEndpointTemplatesTest(EndpointTemplatesTest):
- def test_get_endpoint_templates(self):
- r = self.list_endpoint_templates(assert_status=200)
- self.assertIsNotNone(r.json['OS-KSCATALOG:endpointTemplates'])
-
- def test_get_endpoint_templates_using_service_admin_token(self):
- self.admin_token = self.service_admin_token
- r = self.list_endpoint_templates(assert_status=200)
- self.assertIsNotNone(r.json['OS-KSCATALOG:endpointTemplates'])
-
- def test_get_endpoint_templates_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_endpoint_templates(assert_status=403)
-
- def test_get_endpoint_templates_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.list_endpoint_templates(assert_status=403)
-
- def test_get_endpoint_templates_using_missing_auth_token(self):
- self.admin_token = ''
- self.list_endpoint_templates(assert_status=401)
-
- def test_get_endpoint_templates_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.list_endpoint_templates(assert_status=401)
-
- def test_get_endpoint_templates_xml(self):
- r = self.get_endpoint_templates(assert_status=200, headers={
- 'Accept': 'application/xml'})
- self.assertEqual(r.xml.tag,
- "{%s}endpointTemplates" % self.xmlns_kscatalog)
-
- def test_get_endpoint_templates_xml_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_endpoint_templates(assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_endpoint_templates_xml_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_endpoint_templates(assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_endpoint_templates_xml_missing_auth_token(self):
- self.admin_token = ''
- self.get_endpoint_templates(assert_status=401, headers={
- 'Accept': 'application/xml'})
-
- def test_get_endpoint_templates_xml_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.get_endpoint_templates(assert_status=401, headers={
- 'Accept': 'application/xml'})
-
-
-class GetEndpointTemplatesByServiceTest(EndpointTemplatesTest):
- def test_get_endpoint_templates(self):
- r = self.list_endpoint_templates(
- service_id=self.service['id'], assert_status=200)
- self.assertIsNotNone(r.json['OS-KSCATALOG:endpointTemplates'])
- self.assertEquals(len(r.json['OS-KSCATALOG:endpointTemplates']), 1)
- self.assertEquals(r.json['OS-KSCATALOG:endpointTemplates'][0]['name'],
- self.service['name'])
- self.assertEquals(r.json['OS-KSCATALOG:endpointTemplates'][0]['type'],
- self.service['type'])
-
- def test_get_endpoint_templates_using_service_admin_token(self):
- self.admin_token = self.service_admin_token
- r = self.list_endpoint_templates(service_id=self.service['id'],
- assert_status=200)
- self.assertIsNotNone(r.json['OS-KSCATALOG:endpointTemplates'])
- self.assertEquals(len(r.json['OS-KSCATALOG:endpointTemplates']), 1)
- self.assertEquals(r.json['OS-KSCATALOG:endpointTemplates'][0]['name'],
- self.service['name'])
- self.assertEquals(
- r.json['OS-KSCATALOG:endpointTemplates'][0]['type'],
- self.service['type'])
-
- def test_get_endpoint_templates_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_endpoint_templates(
- service_id=self.service['id'], assert_status=403)
-
- def test_get_endpoint_templates_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.list_endpoint_templates(
- service_id=self.service['id'], assert_status=403)
-
- def test_get_endpoint_templates_using_missing_auth_token(self):
- self.admin_token = ''
- self.list_endpoint_templates(service_id=self.service['id'],
- assert_status=401)
-
- def test_get_endpoint_templates_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.list_endpoint_templates(service_id=self.service['id'],
- assert_status=401)
-
- def test_get_endpoint_templates_xml(self):
- r = self.get_endpoint_templates_by_service(
- service_id=self.service['id'],
- assert_status=200, headers={'Accept': 'application/xml'})
- self.assertEqual(r.xml.tag,
- "{%s}endpointTemplates" % self.xmlns_kscatalog)
- endpoint_template = r.xml.find(
- '{%s}endpointTemplate' % self.xmlns_kscatalog)
- self.assertIsNotNone(endpoint_template)
- self.assertEqual(endpoint_template.get('name'), self.service['name'])
- self.assertEqual(endpoint_template.get('type'), self.service['type'])
-
- def test_get_endpoint_templates_xml_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_endpoint_templates_by_service(
- service_id=self.service['id'], assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_endpoint_templates_xml_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_endpoint_templates_by_service(
- service_id=self.service['id'], assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_endpoint_templates_xml_missing_auth_token(self):
- self.admin_token = ''
- self.get_endpoint_templates_by_service(
- service_id=self.service['id'], assert_status=401, headers={
- 'Accept': 'application/xml'})
-
- def test_get_endpoint_templates_xml_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.get_endpoint_templates_by_service(
- service_id=self.service['id'], assert_status=401, headers={
- 'Accept': 'application/xml'})
-
-
-class GetEndpointTemplateTest(EndpointTemplatesTest):
- def test_get_endpoint(self):
- r = self.fetch_endpoint_template(self.endpoint_template['id'])
- self.assertIsNotNone(r.json['OS-KSCATALOG:endpointTemplate'])
-
-# def test_get_endpoint_using_service_admin_token(self):
-# self.admin_token = service_admin_token
-# r = self.fetch_endpoint_template(self.endpoint_template['id'])
-# self.assertIsNotNone(r.json['endpointTemplate'])
-
- def test_get_endpoint_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_endpoint_template(self.endpoint_template['id'],
- assert_status=403)
-
- def test_get_endpoint_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_endpoint_template(self.endpoint_template['id'],
- assert_status=403)
-
- def test_get_endpoint_using_missing_auth_token(self):
- self.admin_token = ''
- self.fetch_endpoint_template(self.endpoint_template['id'],
- assert_status=401)
-
- def test_get_endpoint_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.fetch_endpoint_template(self.endpoint_template['id'],
- assert_status=401)
-
- def test_get_endpoint_xml(self):
- r = self.get_endpoint_template(self.endpoint_template['id'],
- headers={'Accept': 'application/xml'}, assert_status=200)
-
- self.assertEqual(r.xml.tag,
- "{%s}endpointTemplate" % self.xmlns_kscatalog)
-
- def test_non_existent_get_endpoint(self):
- self.fetch_endpoint_template('99999999',
- assert_status=404)
-
-
-class UpdateEndpointTemplateTest(EndpointTemplatesTest):
- def test_update_endpoint(self):
- self.update_endpoint_template(self.endpoint_template['id'],
- name=self.service['name'], type=self.service['type'],
- assert_status=201)
-# self.assertIsNotNone(r.json['endpointTemplate'].get('enabled'), r.json)
-
- def test_update_endpoint_with_empty_name(self):
- self.update_endpoint_template(self.endpoint_template['id'],
- name='', type=self.service['type'],
- assert_status=400)
-
- def test_update_endpoint_with_empty_type(self):
- self.update_endpoint_template(self.endpoint_template['id'],
- name=self.service['name'], type='',
- assert_status=400)
-
- def test_update_endpoint_xml(self):
- region = common.unique_str()
- public_url = common.unique_url()
- admin_url = common.unique_url()
- internal_url = common.unique_url()
- enabled = True
- is_global = True
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate '
- 'xmlns="%s" '
- 'region="%s" name="%s" type="%s"'
- ' publicURL="%s" adminURL="%s"'
- ' internalURL="%s" enabled="%s" global="%s"/>') % (
- self.xmlns_kscatalog, region,
- self.service['name'], self.service['type'],
- public_url, admin_url, internal_url,
- enabled, is_global)
- r = self.put_endpoint_template(self.endpoint_template['id'],
- as_xml=data, assert_status=201, headers={
- 'Accept': 'application/xml'})
-
- self.assertEqual(r.xml.tag,
- '{%s}endpointTemplate' % self.xmlns_kscatalog)
-
- self.assertIsNotNone(r.xml.get("id"))
- self.assertEqual(r.xml.get("name"), self.service['name'])
- self.assertEqual(r.xml.get("type"), self.service['type'])
- self.assertEqual(r.xml.get("region"), region)
- self.assertEqual(r.xml.get("publicURL"), public_url)
- self.assertEqual(r.xml.get("adminURL"), admin_url)
- self.assertEqual(r.xml.get("internalURL"), internal_url)
- self.assertEqual(r.xml.get("enabled"), str(enabled).lower())
- self.assertEqual(r.xml.get("global"), str(is_global).lower())
-
-# def test_update_endpoint_using_service_admin_token(self):
-# self.admin_token = service_admin_token
-# region = common.unique_str()
-# public_url = common.unique_url()
-# admin_url = common.unique_url()
-# internal_url = common.unique_url()
-# enabled = True
-# is_global = True
-#
-# r = self.update_endpoint_template(self.endpoint_template['id'],
-# region, self.service['id'], public_url, admin_url, internal_url,
-# enabled, is_global, assert_status=201)
-#
-# endpoint_template = r.json.get('endpointTemplate')
-#
-# self.assertIsNotNone(endpoint_template.get("id"), r.json)
-# self.assertEqual(endpoint_template.get("serviceId"),
-# self.service['id'])
-# self.assertEqual(endpoint_template.get("region"), region)
-# self.assertEqual(endpoint_template.get("publicURL"), public_url)
-# self.assertEqual(endpoint_template.get("adminURL"), admin_url)
-# self.assertEqual(endpoint_template.get("internalURL"), internal_url)
-# self.assertEqual(endpoint_template.get("enabled"),
-# str(enabled).lower())
-# self.assertEqual(endpoint_template.get("global"),
-# str(is_global).lower())
-
-# def test_update_endpoint_xml_using_service_admin_token(self):
-# self.admin_token = service_admin_token
-#
-# self.test_update_endpoint_xml()
-
- def test_update_endpoint_template_with_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.update_endpoint_template(self.endpoint_template['id'],
- assert_status=403)
-
- def test_update_endpoint_template_with_missing_token(self):
- self.admin_token = ''
- self.update_endpoint_template(self.endpoint_template['id'],
- assert_status=401)
-
- def test_update_endpoint_template_with_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.update_endpoint_template(self.endpoint_template['id'],
- assert_status=403)
-
- def test_update_endpoint_template_with_invalid_token(self):
- self.admin_token = common.unique_str()
- self.update_endpoint_template(self.endpoint_template['id'],
- assert_status=401)
-
- def test_update_invalid_endpoint_template(self):
- self.update_endpoint_template(assert_status=404)
-
-
-class CreateEndpointsTest(EndpointTemplatesTest):
-
- def setUp(self, *args, **kwargs):
- super(CreateEndpointsTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_endpoint_create_json_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_template['id'], assert_status=403)
-
- def test_endpoint_create_json_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_template['id'], assert_status=403)
-
- def test_endpoint_create_json_using_missing_token(self):
- self.admin_token = ''
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_template['id'], assert_status=401)
-
- def test_endpoint_create_json_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_template['id'], assert_status=401)
-
- def test_endpoint_create_json(self):
- endpoint = self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_template['id'], assert_status=201).json['endpoint']
- self.assertEqual(str(endpoint["name"]), str(self.service['name']))
- self.assertEqual(str(endpoint["type"]), str(self.service['type']))
- self.assertEqual(endpoint["region"], self.endpoint_template["region"])
- self.assertEqual(endpoint["publicURL"],
- self.endpoint_template["publicURL"])
- self.assertEqual(endpoint["adminURL"],
- self.endpoint_template["adminURL"])
- self.assertEqual(endpoint["internalURL"],
- self.endpoint_template["internalURL"])
-
-# def test_endpoint_create_using_service_admin_token(self):
-# self.admin_token = service_admin_token
-# self.create_endpoint_template(assert_status=201)
-
- def test_endpoint_create_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate '
- 'xmlns="%s" id="%s">'
- '</endpointTemplate>') % (self.xmlns_kscatalog,
- self.endpoint_template["id"])
- r = self.post_tenant_endpoint(self.tenant['id'],
- as_xml=data, assert_status=201,
- headers={'Accept': 'application/xml'})
-
- self.assertEqual(r.xml.tag,
- '{%s}endpoint' % self.xmlns)
-
- self.assertIsNotNone(r.xml.get("id"))
- self.assertEqual(r.xml.get("name"), self.service['name'])
- self.assertEqual(r.xml.get("type"), self.service['type'])
- self.assertEqual(r.xml.get("region"), self.endpoint_template["region"])
- self.assertEqual(r.xml.get("publicURL"),
- self.endpoint_template["publicURL"])
- self.assertEqual(r.xml.get("adminURL"),
- self.endpoint_template["adminURL"])
- self.assertEqual(r.xml.get("internalURL"),
- self.endpoint_template["internalURL"])
-
- def test_endpoint_create_xml_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate '
- 'xmlns="%s" '
- 'region="%s" name="%s"'
- ' type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>') % (
- self.xmlns_kscatalog,
- common.unique_str(),
- self.service['name'],
- self.service['type'], common.unique_url(),
- common.unique_url(), common.unique_url(), True, True)
- self.post_endpoint_template(as_xml=data, assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_endpoint_create_xml_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate '
- 'xmlns="%s" '
- 'region="%s" name="%s" type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>') % (
- self.xmlns_kscatalog, common.unique_str(),
- self.service['name'],
- self.service['type'], common.unique_url(),
- common.unique_url(), common.unique_url(), True, True)
- self.post_endpoint_template(as_xml=data, assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_endpoint_create_xml_using_missing_token(self):
- self.admin_token = ''
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate '
- 'xmlns="%s" '
- 'region="%s" name="%s" type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>') % (
- self.xmlns_kscatalog,
- common.unique_str(),
- self.service['name'], self.service['type'],
- common.unique_url(),
- common.unique_url(), common.unique_url(), True, True)
- self.post_endpoint_template(as_xml=data, assert_status=401, headers={
- 'Accept': 'application/xml'})
-
- def test_endpoint_create_xml_using_invalid_token(self):
- self.admin_token = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<endpointTemplate '
- 'xmlns="%s" '
- 'region="%s" name="%s" type="%s" publicURL="%s" adminURL="%s" '
- 'internalURL="%s" enabled="%s" global="%s"/>') % (
- self.xmlns_kscatalog, common.unique_str(),
- self.service['name'],
- self.service['type'], common.unique_url(),
- common.unique_url(), common.unique_url(), True, True)
- self.post_endpoint_template(as_xml=data, assert_status=401, headers={
- 'Accept': 'application/xml'})
-
-
-class GetEndpointsTest(EndpointTemplatesTest):
- def setUp(self, *args, **kwargs):
- super(GetEndpointsTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_get_tenant_endpoint_xml(self):
- self.get_tenant_endpoints(self.tenant['id'], assert_status=200,
- headers={"Accept": "application/xml"})
-
- def test_get_tenant_endpoint_xml_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_tenant_endpoints(self.tenant['id'], assert_status=403,
- headers={"Accept": "application/xml"})
-
- def test_get_tenant_endpoint_xml_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_tenant_endpoints(self.tenant['id'], assert_status=403,
- headers={"Accept": "application/xml"})
-
- def test_get_tenant_endpoint_xml_using_missing_auth_token(self):
- self.admin_token = ''
- self.get_tenant_endpoints(self.tenant['id'], assert_status=401,
- headers={"Accept": "application/xml"})
-
- def test_get_tenant_endpoint_xml_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.get_tenant_endpoints(self.tenant['id'], assert_status=401,
- headers={"Accept": "application/xml"})
-
- def test_get_tenant_endpoint_json(self):
- r = self.get_tenant_endpoints(self.tenant['id'], assert_status=200)
- self.assertIsNotNone(r.json.get('endpoints'), r.json)
-
- def test_get_tenant_endpoint_json_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_tenant_endpoints(self.tenant['id'], assert_status=403)
-
- def test_get_endpoint_json_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_tenant_endpoints(self.tenant['id'], assert_status=403)
-
- def test_get_endpoint_json_using_missing_auth_token(self):
- self.admin_token = ''
- self.get_tenant_endpoints(self.tenant['id'], assert_status=401)
-
- def test_get_endpoint_json_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.get_tenant_endpoints(self.tenant['id'], assert_status=401)
-
-
-class DeleteEndpointsTest(EndpointTemplatesTest):
- def setUp(self, *args, **kwargs):
- super(DeleteEndpointsTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_template['id'])
-
- def test_delete_endpoint(self):
- self.delete_tenant_endpoint(self.tenant['id'],
- self.endpoint_template['id'], assert_status=204)
-
- def test_delete_endpoint_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.delete_tenant_endpoint(self.tenant['id'],
- self.endpoint_template['id'], assert_status=403)
-
- def test_delete_endpoint_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.delete_tenant_endpoint(self.tenant['id'],
- self.endpoint_template['id'], assert_status=403)
-
- def test_delete_endpoint_using_missing_auth_token(self):
- self.admin_token = ''
- self.delete_tenant_endpoint(self.tenant['id'],
- self.endpoint_template['id'], assert_status=401)
-
- def test_delete_endpoint_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.delete_tenant_endpoint(self.tenant['id'],
- self.endpoint_template['id'], assert_status=401)
-
-
-class GetEndpointsForTokenTest(EndpointTemplatesTest):
- def setUp(self, *args, **kwargs):
- super(GetEndpointsForTokenTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
-
- self.services = {}
- self.endpoint_templates = {}
- for x in range(0, 5):
- self.services[x] = self.create_service().json['OS-KSADM:service']
- self.endpoint_templates[x] = self.create_endpoint_template(
- name=self.services[x]['name'], \
- type=self.services[x]['type']).\
- json['OS-KSCATALOG:endpointTemplate']
- self.create_endpoint_for_tenant(self.tenant['id'],
- self.endpoint_templates[x]['id'])
-
- def test_get_token_endpoints_xml(self):
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=200,
- headers={"Accept": "application/xml"})
-
- def test_get_token_endpoints_xml_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=403,
- headers={"Accept": "application/xml"})
-
- def test_get_token_endpoints_xml_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=403,
- headers={"Accept": "application/xml"})
-
- def test_get_token_endpoints_xml_using_missing_auth_token(self):
- self.admin_token = ''
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=401,
- headers={"Accept": "application/xml"})
-
- def test_get_token_endpoints_xml_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=401,
- headers={"Accept": "application/xml"})
-
- def test_get_token_endpoints_json(self):
- r = self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=200)
- self.assertIsNotNone(r.json.get('endpoints'), r.json)
-
- def test_get_token_endpoints_json_using_expired_auth_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=403)
-
- def test_get_token_endpoints_json_using_disabled_auth_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=403)
-
- def test_get_token_endpoints_json_using_missing_auth_token(self):
- self.admin_token = ''
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=401)
-
- def test_get_token_endpoints_json_using_invalid_auth_token(self):
- self.admin_token = common.unique_str()
- self.get_token_endpoints(self.tenant_user_token['id'],
- assert_status=401)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_extensions.py b/keystone/test/functional/test_extensions.py
deleted file mode 100644
index ba090bda..00000000
--- a/keystone/test/functional/test_extensions.py
+++ /dev/null
@@ -1,258 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestHPIDMTokensExtension(common.FunctionalTestCase):
- """Test HP-IDM token validation extension"""
-
- def setUp(self):
- super(TestHPIDMTokensExtension, self).setUp()
- password = common.unique_str()
- self.user = self.create_user(user_password=password).json['user']
- self.user['password'] = password
- self.tenant = self.create_tenant().json['tenant']
- self.service = self.create_service().json['OS-KSADM:service']
- r = self.create_role(service_name=self.service['name'])
- self.role = r.json['role']
- self.another_service = self.create_service().json['OS-KSADM:service']
- self.service_with_no_users = self.create_service().\
- json['OS-KSADM:service']
- ar = self.create_role(service_name=self.another_service['name'])
- self.another_role = ar.json['role']
- rnu = self.create_role(service_name=self.service_with_no_users['name'])
- self.role_with_no_users = rnu.json['role']
- rns = self.create_role()
- self.role_with_no_service = rns.json['role']
- self.grant_role_to_user(self.user['id'],
- self.role['id'], self.tenant['id'])
- self.grant_role_to_user(self.user['id'],
- self.role_with_no_service['id'],
- self.tenant['id'])
- self.grant_role_to_user(self.user['id'],
- self.another_role['id'], self.tenant['id'])
- self.global_role = self.create_role().json['role']
- # crete a global role
- self.put_user_role(self.user['id'], self.global_role['id'], None)
-
- def get_token_belongsto(self, token_id, tenant_id, service_ids, **kwargs):
- """GET /tokens/{token_id}?belongsTo={tenant_id}
- [&HP-IDM-serviceId={service_ids}]"""
- serviceId_qs = ""
- if service_ids:
- serviceId_qs = "&HP-IDM-serviceId=%s" % (service_ids)
- return self.admin_request(method='GET',
- path='/tokens/%s?belongsTo=%s%s' % (token_id, tenant_id,
- serviceId_qs), **kwargs)
-
- def check_token_belongs_to(self, token_id, tenant_id, service_ids,
- **kwargs):
- """HEAD /tokens/{token_id}?belongsTo={tenant_id}
- [&HP-IDM-serviceId={service_ids}]"""
- serviceId_qs = ""
- if service_ids:
- serviceId_qs = "&HP-IDM-serviceId=%s" % (service_ids)
- return self.admin_request(method='HEAD',
- path='/tokens/%s?belongsTo=%s%s' % (token_id, tenant_id,
- serviceId_qs), **kwargs)
-
- @unittest.skipIf(common.isSsl(),
- "Skipping SSL tests")
- def test_token_validation_with_serviceId(self):
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': self.tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- # And an admin should be able to validate that our new token is scoped
- r = self.get_token_belongsto(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=self.service['id'])
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(access['token']['tenant']['name'],
- self.tenant['name'])
-
- # make sure only the service roles are returned
- self.assertIsNotNone(access['user'].get('roles'))
- self.assertEqual(len(access['user']['roles']), 1)
- self.assertEqual(access['user']['roles'][0]['name'],
- self.role['name'])
-
- # make sure check token also works
- self.check_token_belongs_to(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=self.service['id'],
- assert_status=200)
-
- @unittest.skipIf(common.isSsl(),
- "Skipping SSL tests")
- def test_token_validation_with_all_serviceId(self):
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': self.tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- # And an admin should be able to validate that our new token is scoped
- service_ids = "%s,%s" % \
- (self.service['id'], self.another_service['id'])
- r = self.get_token_belongsto(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=service_ids)
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(access['token']['tenant']['name'],
- self.tenant['name'])
-
- # make sure only the service roles are returned
- self.assertIsNotNone(access['user'].get('roles'))
- self.assertEqual(len(access['user']['roles']), 2)
- role_names = map(lambda x: x['name'], access['user']['roles'])
- self.assertTrue(self.role['name'] in role_names)
- self.assertTrue(self.another_role['name'] in role_names)
-
- @unittest.skipIf(common.isSsl(),
- "Skipping SSL tests")
- def test_token_validation_with_no_user_service(self):
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': self.tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- # And an admin should be able to validate that our new token is scoped
- service_ids = "%s,%s,%s" % (self.service['id'],
- self.another_service['id'],
- self.service_with_no_users['id'])
- r = self.get_token_belongsto(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=service_ids)
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(access['token']['tenant']['name'],
- self.tenant['name'])
-
- # make sure only the service roles are returned, excluding the one
- # with no users
- self.assertIsNotNone(access['user'].get('roles'))
- self.assertEqual(len(access['user']['roles']), 2)
- role_names = map(lambda x: x['name'], access['user']['roles'])
- self.assertTrue(self.role['name'] in role_names)
- self.assertTrue(self.another_role['name'] in role_names)
-
- # make sure check token also works
- self.check_token_belongs_to(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=service_ids,
- assert_status=200)
-
- @unittest.skipIf(common.isSsl(),
- "Skipping SSL tests")
- def test_token_validation_without_serviceId(self):
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': self.tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- # And an admin should be able to validate that our new token is scoped
- r = self.get_token_belongsto(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=None)
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(access['token']['tenant']['name'],
- self.tenant['name'])
-
- # make sure all the roles are returned
- self.assertIsNotNone(access['user'].get('roles'))
- self.assertEqual(len(access['user']['roles']), 4)
- role_names = map(lambda x: x['name'], access['user']['roles'])
- self.assertTrue(self.role['name'] in role_names)
- self.assertTrue(self.another_role['name'] in role_names)
- self.assertTrue(self.global_role['name'] in role_names)
- self.assertTrue(self.role_with_no_service['name'] in role_names)
-
- @unittest.skipIf(common.isSsl(),
- "Skipping SSL tests")
- def test_token_validation_with_global_service_id(self):
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': self.tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- service_ids = "%s,%s,global" % (self.service['id'],
- self.another_service['id'])
- r = self.get_token_belongsto(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=service_ids)
- access = r.json['access']
-
- self.assertEqual(access['user']['id'], self.user['id'])
- self.assertEqual(access['user']['name'], self.user['name'])
- self.assertEqual(access['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(access['token']['tenant']['name'],
- self.tenant['name'])
-
- # make sure only the service roles are returned
- self.assertIsNotNone(access['user'].get('roles'))
- self.assertEqual(len(access['user']['roles']), 3)
- role_names = map(lambda x: x['name'], access['user']['roles'])
- self.assertTrue(self.role['name'] in role_names)
- self.assertTrue(self.another_role['name'] in role_names)
- self.assertTrue(self.global_role['name'] in role_names)
-
- @unittest.skipIf(common.isSsl(),
- "Skipping SSL tests")
- def test_token_validation_with_bogus_service_id(self):
- scoped = self.post_token(as_json={
- 'auth': {
- 'passwordCredentials': {
- 'username': self.user['name'],
- 'password': self.user['password']},
- 'tenantName': self.tenant['name']}}).json['access']
-
- self.assertEqual(scoped['token']['tenant']['id'], self.tenant['id'])
- self.assertEqual(scoped['token']['tenant']['name'],
- self.tenant['name'])
- service_ids = "%s,%s,boguzzz" % (self.service['id'],
- self.another_service['id'])
- self.get_token_belongsto(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=service_ids,
- assert_status=401)
-
- # make sure check token also works
- self.check_token_belongs_to(token_id=scoped['token']['id'],
- tenant_id=self.tenant['id'], service_ids=service_ids,
- assert_status=401)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_issue_85.py b/keystone/test/functional/test_issue_85.py
deleted file mode 100644
index a44d147c..00000000
--- a/keystone/test/functional/test_issue_85.py
+++ /dev/null
@@ -1,43 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestIssue85(common.FunctionalTestCase):
- """Illustrates github issue #85"""
-
- def test_disabling_tenant_disables_token(self):
- """Disabling a tenant should invalidate previously-issued tokens"""
- # Create a user for a specific tenant
- tenant = self.create_tenant().json['tenant']
- password = common.unique_str()
- user = self.create_user(user_password=password,
- tenant_id=tenant['id']).json['user']
- user['password'] = password
-
- # Authenticate as user to get a token *for a specific tenant*
- user_token = self.authenticate(user['name'], user['password'],
- tenant['id']).json['access']['token']['id']
-
- # Validate and check that token belongs to tenant
- print self.get_token(user_token).body
- tenant_id = self.get_token(user_token).\
- json['access']['token']['tenant']['id']
- self.assertEqual(tenant_id, tenant['id'])
-
- # Disable tenant
- r = self.admin_request(method='POST',
- path='/tenants/%s' % tenant['id'],
- as_json={
- 'tenant': {
- 'name': tenant['name'],
- 'description': 'description',
- 'enabled': False}})
- self.assertEquals(r.json['tenant']['enabled'], False)
-
- # Assert that token belonging to disabled tenant is invalid
- r = self.admin_request(path='/tokens/%s?belongsTo=%s' %
- (user_token, tenant['id']), assert_status=403)
- self.assertTrue(r.json['tenantDisabled'], 'Tenant is disabled')
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_roles.py b/keystone/test/functional/test_roles.py
deleted file mode 100644
index 0444e738..00000000
--- a/keystone/test/functional/test_roles.py
+++ /dev/null
@@ -1,559 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-from keystone.test.functional import common
-
-
-class RolesTest(common.FunctionalTestCase):
- expected_roles = ['Admin', 'Member', 'KeystoneServiceAdmin']
-
- def setUp(self, *args, **kwargs):
- super(RolesTest, self).setUp(*args, **kwargs)
-
- def tearDown(self, *args, **kwargs):
- super(RolesTest, self).tearDown(*args, **kwargs)
-
-
-class CreateRolesTest(RolesTest):
- def test_create_role(self):
- self.create_role(assert_status=201)
-
- def test_create_role_using_blank_name(self):
- self.create_role(role_name='', assert_status=400)
-
- def test_create_role_using_service_token(self):
- user = self.create_user_with_known_password().json['user']
- self.admin_token = self.authenticate(user['name'],
- user['password']).json['access']['token']['id']
- self.create_role(assert_status=401)
-
- def test_create_roles_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_role(assert_status=403)
-
- def test_create_roles_using_missing_token(self):
- self.admin_token = ''
- self.create_role(assert_status=401)
-
- def test_create_roles_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.create_role(assert_status=403)
-
- def test_create_roles_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_role(assert_status=401)
-
- def test_create_role_mapped_to_a_service(self):
- service = self.create_service().json['OS-KSADM:service']
- role_name = service['name'] + ':' + common.unique_str()
- role = self.create_role(role_name=role_name,
- service_id=service['id']).json['role']
- self.assertEqual(role_name, role['name'])
- self.assertEqual(service['id'], role['serviceId'])
-
- def test_create_role_mapped_to_a_service_xml(self):
- service = self.create_service().json['OS-KSADM:service']
- name = service['name'] + ':' + common.unique_str()
- description = common.unique_str()
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<role xmlns="%s" name="%s" description="%s" serviceId="%s"/>') % (
- self.xmlns, name, description, service['id'])
- id = self.post_role(assert_status=201, as_xml=data).xml.get('id')
- self.assertIsNotNone(id)
-
- role = self.fetch_role(id, assert_status=200).json['role']
- self.assertEqual(role['name'], name)
- self.assertEqual(role['description'], description)
- self.assertEqual(role['serviceId'], service['id'])
-
- def test_create__service_role_using_incorrect_role_name(self):
- """ test_create_role_mapped_to_a_service_using_incorrect_role_name """
- self.create_role(common.unique_str(), service_id=common.unique_str(),
- assert_status=400)
-
- def test_create_role_using_empty_name_xml(self):
- name = ''
- description = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<role xmlns="%s" name="%s" description="%s" />') % (
- self.xmlns, name, description)
- self.post_role(assert_status=400, as_xml=data)
-
-
-class DeleteRoleTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(DeleteRoleTest, self).setUp(*args, **kwargs)
-
- self.role = self.create_role().json['role']
-
- def test_delete_roles_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.delete_role(self.role['id'], assert_status=403)
-
- def test_delete_roles_using_missing_token(self):
- self.admin_token = ''
- self.delete_role(self.role['id'], assert_status=401)
-
- def test_delete_roles_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.delete_role(self.role['id'], assert_status=403)
-
- def test_delete_roles_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.delete_role(self.role['id'], assert_status=401)
-
- def test_create_and_delete_role_that_has_references(self):
- tenant = self.create_tenant().json['tenant']
- user = self.create_user(tenant_id=tenant['id']).json['user']
- self.grant_role_to_user(user['id'], self.role['id'], tenant['id'])
- self.remove_role(self.role['id'], assert_status=204)
-
- def test_create_role_mapped_to_a_service(self):
- service = self.create_service().json['OS-KSADM:service']
- role_name = service['name'] + ':' + common.unique_str()
- role = self.create_role(role_name=role_name,
- service_id=service['id']).json['role']
- self.assertEqual(service['id'], role['serviceId'])
-
- def test_create_role_mapped_to_a_service_xml(self):
- service = self.create_service().json['OS-KSADM:service']
- name = service['name'] + ':' + common.unique_str()
- description = common.unique_str()
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<role xmlns="%s" name="%s" description="%s" serviceId="%s"/>') % (
- self.xmlns, name, description, service['id'])
- role_id = self.post_role(assert_status=201, as_xml=data).xml.get('id')
-
- role = self.fetch_role(role_id, assert_status=200).json['role']
- self.assertEqual(role['id'], role_id)
- self.assertEqual(role['serviceId'], service['id'])
-
- def test_create_service_role_using_incorrect_role_name(self):
- """ Formerly:
- test_create_role_mapped_to_a_service_using_incorrect_role_name"""
- self.create_role(common.unique_str(), service_id=common.unique_str(),
- assert_status=400)
-
-
-class GetRolesByServiceTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(GetRolesByServiceTest, self).setUp(*args, **kwargs)
- service = self.create_service().json['OS-KSADM:service']
- role_name = service['name'] + ':' + common.unique_str()
- role = self.create_role(role_name=role_name,
- service_id=service['id']).json['role']
- self.service_id = service['id']
-
- def tearDown(self, *args, **kwargs):
- super(GetRolesByServiceTest, self).tearDown(*args, **kwargs)
-
- def test_get_roles(self):
- r = self.list_roles(assert_status=200, service_id=self.service_id)
- self.assertTrue(len(r.json['roles']))
-
- def test_get_roles_xml(self):
- r = self.get_roles_by_service(assert_status=200, headers={
- 'Accept': 'application/xml'}, service_id=self.service_id,)
- self.assertEquals(r.xml.tag, '{%s}roles' % self.xmlns)
- roles = r.xml.findall('{%s}role' % self.xmlns)
-
- for role in roles:
- self.assertIsNotNone(role.get('id'))
-
- def test_get_roles_exp_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_roles_by_service(
- service_id=self.service_id, assert_status=403)
-
- def test_get_roles_exp_token_xml(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_roles_by_service(
- service_id=self.service_id, assert_status=403, headers={
- 'Accept': 'application/xml'})
-
-
-class GetRolesTest(RolesTest):
- def test_get_roles(self):
- r = self.list_roles(assert_status=200)
- self.assertTrue(len(r.json['roles']))
-
- def test_get_roles_xml(self):
- r = self.get_roles(assert_status=200, headers={
- 'Accept': 'application/xml'})
- self.assertEquals(r.xml.tag, '{%s}roles' % self.xmlns)
- roles = r.xml.findall('{%s}role' % self.xmlns)
-
- for role in roles:
- self.assertIsNotNone(role.get('id'))
-
- def test_get_roles_exp_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_roles(assert_status=403)
-
- def test_get_roles_exp_token_xml(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_roles(assert_status=403, headers={
- 'Accept': 'application/xml'})
-
-
-class GetRoleTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(GetRoleTest, self).setUp(*args, **kwargs)
- self.role = self.create_role().json['role']
-
- def test_get_role(self):
- role = self.fetch_role(self.role['id'], assert_status=200).json['role']
- self.assertEqual(role['id'], self.role['id'])
- self.assertEqual(role['name'], self.role['name'])
- self.assertEqual(role['description'], self.role['description'])
- self.assertEqual(role.get('serviceId'), self.role.get('serviceId'))
-
- def test_get_role_xml(self):
- r = self.get_role(self.role['id'], assert_status=200, headers={
- 'Accept': 'application/xml'})
- self.assertEqual(r.xml.tag, '{%s}role' % self.xmlns)
- self.assertEqual(r.xml.get('id'), self.role['id'])
- self.assertEqual(r.xml.get('name'), self.role['name'])
- self.assertEqual(r.xml.get('description'), self.role['description'])
- self.assertEqual(r.xml.get('serviceId'), self.role.get('serviceId'))
-
- def test_get_role_bad(self):
- self.fetch_role(common.unique_str(), assert_status=404)
-
- def test_get_role_xml_bad(self):
- self.get_role(common.unique_str(), assert_status=404, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_role(self.role['id'], assert_status=403)
-
- def test_get_role_xml_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_role(self.role['id'], assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_role(self.role['id'], assert_status=403)
-
- def test_get_role_xml_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_role(self.role['id'], assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_using_missing_token(self):
- self.admin_token = ''
- self.fetch_role(self.role['id'], assert_status=401)
-
- def test_get_role_xml_using_missing_token(self):
- self.admin_token = ''
- self.get_role(self.role['id'], assert_status=401, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_role(self.role['id'], assert_status=401)
-
- def test_get_role_xml_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.get_role(self.role['id'], assert_status=401, headers={
- 'Accept': 'application/xml'})
-
-
-class GetRoleByNameTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(GetRoleByNameTest, self).setUp(*args, **kwargs)
-
- self.role = self.create_role().json['role']
-
- def test_get_role(self):
- role = self.fetch_role_by_name(
- self.role['name'], assert_status=200).json['role']
- self.assertEqual(role['id'], self.role['id'])
- self.assertEqual(role['name'], self.role['name'])
- self.assertEqual(role['description'], self.role['description'])
- self.assertEqual(role.get('serviceId'), self.role.get('serviceId'))
-
- def test_get_role_xml(self):
- r = self.get_role_by_name(self.role['name'],
- assert_status=200, headers={
- 'Accept': 'application/xml'})
- self.assertEqual(r.xml.tag, '{%s}role' % self.xmlns)
- self.assertEqual(r.xml.get('id'), self.role['id'])
- self.assertEqual(r.xml.get('name'), self.role['name'])
- self.assertEqual(r.xml.get('description'), self.role['description'])
- self.assertEqual(r.xml.get('serviceId'), self.role.get('serviceId'))
-
- def test_get_role_bad(self):
- self.fetch_role_by_name(common.unique_str(), assert_status=404)
-
- def test_get_role_xml_bad(self):
- self.get_role_by_name(common.unique_str(), assert_status=404, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_role_by_name(self.role['name'], assert_status=403)
-
- def test_get_role_xml_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_role_by_name(self.role['name'], assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_role_by_name(self.role['name'], assert_status=403)
-
- def test_get_role_xml_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_role_by_name(self.role['name'], assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_using_missing_token(self):
- self.admin_token = ''
- self.fetch_role_by_name(self.role['name'], assert_status=401)
-
- def test_get_role_xml_using_missing_token(self):
- self.admin_token = ''
- self.get_role_by_name(self.role['name'], assert_status=401, headers={
- 'Accept': 'application/xml'})
-
- def test_get_role_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_role_by_name(self.role['name'], assert_status=401)
-
- def test_get_role_xml_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.get_role_by_name(self.role['name'], assert_status=401, headers={
- 'Accept': 'application/xml'})
-
-
-class CreateRoleAssignmentTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(CreateRoleAssignmentTest, self).setUp(*args, **kwargs)
-
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
-
- self.role = self.create_role().json['role']
-
- def test_grant_role(self):
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=201)
-
-# def test_grant_role_json_using_service_admin_token(self):
-# tenant = self.create_tenant().json['tenant']
-# service_admin = self.create_user_with_known_password().json['user']
-# self.grant_role_to_user(service_admin['id'], 'KeystoneServiceAdmin',
-# tenant['id'], assert_status=201)
-#
-# service_admin_token_id = self.authenticate(service_admin['name'],
-# service_admin['password']).json['auth']['token']['id']
-#
-# user = self.create_user().json['user']
-#
-# role = self.create_role().json['role']
-# self.admin_token = service_admin_token_id
-# self.grant_role_to_user(user['id'], role['id'], tenant['id'],
-# assert_status=201)
-
- def test_grant_role_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=403)
-
- def test_grant_role_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=403)
-
- def test_grant_role_using_missing_token(self):
- self.admin_token = ''
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=401)
-
- def test_grant_role_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=401)
-
- def test_grant_global_role_json(self):
- self.grant_global_role_to_user(
- self.tenant_user['id'], self.role['id'], assert_status=201)
-
-
-class GetRoleAssignmentsTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(GetRoleAssignmentsTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
-
- self.role = self.create_role().json['role']
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'])
-
- def test_get_role_assignments(self):
- r = self.get_user_roles(self.tenant_user['id'], assert_status=200)
- self.assertIsNotNone(r.json['roles'])
-
- def test_get_roler_assignments_xml(self):
- r = self.get_user_roles(self.tenant_user['id'], assert_status=200,
- headers={'Accept': 'application/xml'})
- self.assertEqual(r.xml.tag, "{%s}roles" % self.xmlns)
-
- def test_get_role_assignments_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_user_roles(self.tenant_user['id'], assert_status=403)
-
- def test_get_role_assignments_xml_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_user_roles(self.tenant_user['id'], assert_status=403,
- headers={'Accept': 'application/xml'})
-
- def test_get_role_assignments_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_user_roles(self.tenant_user['id'], assert_status=403)
-
- def test_get_role_assignments_xml_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.get_user_roles(self.tenant_user['id'], assert_status=403,
- headers={'Accept': 'application/xml'})
-
- def test_get_role_assignments_using_missing_token(self):
- self.admin_token = ''
- self.get_user_roles(self.tenant_user['id'], assert_status=401)
-
- def test_get_role_assignments_xml_using_missing_token(self):
- self.admin_token = ''
- self.get_user_roles(self.tenant_user['id'], assert_status=401,
- headers={'Accept': 'application/xml'})
-
- def test_get_role_assignments_json_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.get_user_roles(self.tenant_user['id'], assert_status=401)
-
- def test_get_role_assignments_xml_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.get_user_roles(self.tenant_user['id'], assert_status=401,
- headers={'Accept': 'application/xml'})
-
-
-class DeleteRoleAssignmentsTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(DeleteRoleAssignmentsTest, self).setUp(*args, **kwargs)
-
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
-
- self.role = self.create_role().json['role']
- self.grant_role_to_user(self.tenant_user['id'], self.role['id'],
- self.tenant['id'])
- self.roles = self.get_user_roles(self.tenant_user['id']).\
- json['roles']
-
- def test_delete_role_assignment(self):
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=204)
-
- def test_delete_role_assignment_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=403)
-
- def test_delete_role_assignment_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=403)
-
- def test_delete_role_assignment_using_missing_token(self):
- self.admin_token = ''
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=401)
-
- def test_delete_role_assignment_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- self.tenant['id'], assert_status=401)
-
-
-class DeleteGlobalRoleAssignmentsTest(RolesTest):
- def setUp(self, *args, **kwargs):
- super(DeleteGlobalRoleAssignmentsTest, self).setUp(*args, **kwargs)
-
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
-
- self.role = self.create_role().json['role']
- self.grant_global_role_to_user(self.tenant_user['id'], self.role['id'])
- self.roles = self.get_user_roles(self.tenant_user['id']).\
- json['roles']
-
- def test_delete_role_assignment(self):
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- None, assert_status=204)
-
- def test_delete_role_assignment_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- None, assert_status=403)
-
- def test_delete_role_assignment_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- None, assert_status=403)
-
- def test_delete_role_assignment_using_missing_token(self):
- self.admin_token = ''
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- None, assert_status=401)
-
- def test_delete_role_assignment_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.delete_user_role(self.tenant_user['id'], self.role['id'],
- None, assert_status=401)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_services.py b/keystone/test/functional/test_services.py
deleted file mode 100644
index 276a5c19..00000000
--- a/keystone/test/functional/test_services.py
+++ /dev/null
@@ -1,294 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-import uuid
-
-from keystone.test.functional import common
-
-
-class ServicesTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(ServicesTest, self).setUp(*args, **kwargs)
-
- service = self.create_service(
- service_name="service-%s" % uuid.uuid4().hex,
- service_type='identity',
- service_description='Sample service',
- assert_status=201).json['OS-KSADM:service']
-
- def tearDown(self, *args, **kwargs):
- super(ServicesTest, self).tearDown(*args, **kwargs)
-
-
-class GetServicesTest(ServicesTest):
- def test_get_services_using_keystone_admin_token_json(self):
- services = self.list_services(assert_status=200).\
- json['OS-KSADM:services']
-
- self.assertTrue(len(services))
-
- def test_get_services_using_keystone_admin_token_xml(self):
- r = self.list_services(assert_status=200, headers={
- 'Accept': 'application/xml'})
-
- self.assertEqual(r.xml.tag, "{%s}services" % self.xmlns_ksadm)
- services = r.xml.findall("{%s}service" % self.xmlns_ksadm)
- self.assertTrue(len(services))
-
- def test_get_services_using_service_admin_token(self):
- self.fixture_create_service_admin()
- self.admin_token = self.service_admin_token
- services = self.list_services(assert_status=200).\
- json['OS-KSADM:services']
-
- self.assertTrue(len(services))
-
- def test_get_services_using_service_admin_token_xml(self):
- self.fixture_create_service_admin()
- self.admin_token = self.service_admin_token
- r = self.get_services(assert_status=200, headers={
- 'Accept': 'application/xml'})
-
- self.assertEqual(r.xml.tag, "{%s}services" % self.xmlns_ksadm)
- services = r.xml.findall("{%s}service" % self.xmlns_ksadm)
- self.assertTrue(len(services))
-
- def test_get_services_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.list_services(assert_status=403)
-
- def test_get_services_using_missing_token(self):
- self.admin_token = ''
- self.list_services(assert_status=401)
-
- def test_get_services_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_services(assert_status=403)
-
- def test_get_services_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.list_services(assert_status=401)
-
-
-class GetServiceTest(ServicesTest):
- def setUp(self, *args, **kwargs):
- super(ServicesTest, self).setUp(*args, **kwargs)
-
- self.service = self.create_service().json['OS-KSADM:service']
-
- def test_service_get_json(self):
- service = self.fetch_service(service_id=self.service['id'],
- assert_status=200).json['OS-KSADM:service']
-
- self.assertIsNotNone(service['id'])
- self.assertIsNotNone(service['description'])
-
- def test_service_get_xml(self):
- service = self.fetch_service(service_id=self.service['id'],
- assert_status=200, headers={'Accept': 'application/xml'}).xml
-
- self.assertEqual(service.tag, '{%s}service' % self.xmlns_ksadm)
- self.assertIsNotNone(service.get('id'))
- self.assertIsNotNone(service.get('description'))
-
- def test_get_service_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_service(service_id=self.service['id'], assert_status=403)
-
- def test_get_service_using_missing_token(self):
- self.admin_token = ''
- self.fetch_service(service_id=self.service['id'], assert_status=401)
-
- def test_get_service_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_service(service_id=self.service['id'], assert_status=403)
-
- def test_get_service_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_service(service_id=self.service['id'], assert_status=401)
-
-
-class GetServiceByNameTest(ServicesTest):
- def setUp(self, *args, **kwargs):
- super(GetServiceByNameTest, self).setUp(*args, **kwargs)
- self.service = self.create_service().json['OS-KSADM:service']
-
- def test_service_get_json(self):
- service = self.fetch_service_by_name(service_name=self.service['name'],
- assert_status=200).json['OS-KSADM:service']
-
- self.assertIsNotNone(service['id'])
- self.assertIsNotNone(service['name'])
- self.assertIsNotNone(service['description'])
-
- def test_service_get_xml(self):
- service = self.fetch_service_by_name(service_name=self.service['name'],
- assert_status=200, headers={'Accept': 'application/xml'}).xml
-
- self.assertEqual(service.tag, '{%s}service' % self.xmlns_ksadm)
- self.assertIsNotNone(service.get('id'))
- self.assertIsNotNone(service.get('name'))
- self.assertIsNotNone(service.get('description'))
-
- def test_get_service_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_service_by_name(
- service_name=self.service['name'], assert_status=403)
-
- def test_get_service_using_missing_token(self):
- self.admin_token = ''
- self.fetch_service_by_name(
- service_name=self.service['name'], assert_status=401)
-
- def test_get_service_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_service_by_name(
- service_name=self.service['name'], assert_status=403)
-
- def test_get_service_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_service_by_name(
- service_name=self.service['name'], assert_status=401)
-
-
-class CreateServiceTest(ServicesTest):
- def test_service_create_json(self):
- name = common.unique_str()
- type = common.unique_str()
- description = common.unique_str()
-
- service = self.create_service(service_name=name, service_type=type,
- service_description=description,
- assert_status=201).json['OS-KSADM:service']
-
- self.assertIsNotNone(service.get('id'))
- self.assertEqual(name, service.get('name'))
- self.assertEqual(type, service.get('type'))
- self.assertEqual(description, service.get('description'))
-
- def test_service_create_xml(self):
- name = common.unique_str()
- type = common.unique_str()
- description = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<service xmlns="%s" name="%s" type="%s" description="%s"/>') % (
- self.xmlns_ksadm, name, type, description)
- r = self.post_service(as_xml=data, assert_status=201)
- self.assertEqual(r.xml.tag, "{%s}service" % self.xmlns_ksadm)
- self.assertIsNotNone(r.xml.get('id'))
- self.assertEqual(name, r.xml.get('name'))
- self.assertEqual(type, r.xml.get('type'))
- self.assertEqual(description, r.xml.get('description'))
-
- def test_service_create_duplicate_json(self):
- service_name = common.unique_str()
- self.create_service(service_name=service_name, assert_status=201)
- self.create_service(service_name=service_name, assert_status=409)
-
- def test_service_create_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.create_service(assert_status=403)
-
- def test_service_create_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_service(assert_status=403)
-
- def test_service_create_json_using_missing_token(self):
- self.admin_token = ''
- self.create_service(assert_status=401)
-
- def test_service_create_json_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_service(assert_status=401)
-
- def test_service_create_json_missing_name(self):
- self.create_service(service_name='', assert_status=400)
-
- def test_service_create_json_missing_type(self):
- self.create_service(service_type='', assert_status=400)
-
- def test_service_create_xml_using_missing_name(self):
- name = ''
- type = common.unique_str()
- description = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<service xmlns="%s" name="%s" type="%s" description="%s"/>') % (
- self.xmlns_ksadm, name, type, description)
- self.post_service(as_xml=data, assert_status=400)
-
- def test_service_create_xml_using_empty_type(self):
- name = common.unique_str()
- type = ''
- description = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<service xmlns="%s" name="%s" type="%s" description="%s"/>') % (
- self.xmlns_ksadm, name, type, description)
- self.post_service(as_xml=data, assert_status=400)
-
-
-class DeleteServiceTest(ServicesTest):
- def setUp(self, *args, **kwargs):
- super(DeleteServiceTest, self).setUp(*args, **kwargs)
-
- self.service = self.create_service().json['OS-KSADM:service']
-
- def test_service_delete(self):
- self.remove_service(self.service['id'], assert_status=204)
- self.get_service(self.service['id'], assert_status=404)
-
- def test_delete_service_with_dependencies(self):
- role_id = self.service['name'] + ':' + common.unique_str()
- role = self.create_role(role_id, service_id=self.service['id'],
- assert_status=201).json['role']
-
- tenant = self.create_tenant().json['tenant']
- user = self.create_user(tenant_id=tenant['id']).json['user']
-
- self.grant_role_to_user(user['id'], role['id'], tenant['id'])
- self.create_endpoint_template(name=self.service['name'],
- type=self.service['type'])
- self.remove_service(self.service['id'], assert_status=204)
-
- def test_service_delete_json_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.remove_service(self.service['id'], assert_status=403)
-
- def test_service_delete_json_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.remove_service(self.service['id'], assert_status=403)
-
- def test_service_delete_json_using_missing_token(self):
- self.admin_token = ''
- self.remove_service(self.service['id'], assert_status=401)
-
- def test_service_delete_json_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.remove_service(self.service['id'], assert_status=401)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_static_files.py b/keystone/test/functional/test_static_files.py
deleted file mode 100644
index 75b445f6..00000000
--- a/keystone/test/functional/test_static_files.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TestStaticFiles(common.ApiTestCase):
- def test_pdf_contract(self):
- if not common.isSsl():
- #TODO(ziad): Caller hangs in SSL (but works with cURL)
- r = self.service_request(path='/identitydevguide.pdf')
- self.assertResponseSuccessful(r)
-
- def test_wadl_contract(self):
- r = self.service_request(path='/identity.wadl')
- self.assertResponseSuccessful(r)
-
- def test_wadl_common(self):
- r = self.service_request(path='/common.ent')
- self.assertResponseSuccessful(r)
-
- def test_xsd_contract(self):
- r = self.service_request(path='/xsd/api.xsd')
- self.assertResponseSuccessful(r)
-
- def test_xsd_atom_contract(self):
- r = self.service_request(path='/xsd/atom/atom.xsd')
- self.assertResponseSuccessful(r)
-
- def test_xslt(self):
- r = self.service_request(path='/xslt/schema.xslt')
- self.assertResponseSuccessful(r)
-
- def test_js(self):
- r = self.service_request(path='/js/shjs/sh_java.js')
- self.assertResponseSuccessful(r)
-
- def test_xml_sample(self):
- r = self.service_request(path='/samples/auth.xml')
- self.assertResponseSuccessful(r)
-
- def test_json_sample(self):
- r = self.service_request(path='/samples/auth.json')
- self.assertResponseSuccessful(r)
-
- def test_stylesheet(self):
- r = self.service_request(path='/style/shjs/sh_acid.css')
- self.assertResponseSuccessful(r)
-
-
-class TestAdminStaticFiles(common.FunctionalTestCase):
- def test_pdf_contract(self):
- if not common.isSsl():
- #TODO(ziad): Caller hangs in SSL (but works with cURL)
- r = self.admin_request(path='/identityadminguide.pdf')
- self.assertResponseSuccessful(r)
-
- def test_wadl_contract(self):
- r = self.admin_request(path='/identity-admin.wadl')
- self.assertResponseSuccessful(r)
-
- def test_xsd_contract(self):
- r = self.admin_request(path='/xsd/api.xsd')
- self.assertResponseSuccessful(r)
-
- def test_xsd_atom_contract(self):
- r = self.admin_request(path='/xsd/atom/atom.xsd')
- self.assertResponseSuccessful(r)
-
- def test_xslt(self):
- r = self.admin_request(path='/xslt/schema.xslt')
- self.assertResponseSuccessful(r)
-
- def test_js(self):
- r = self.admin_request(path='/js/shjs/sh_java.js')
- self.assertResponseSuccessful(r)
-
- def test_xml_sample(self):
- r = self.admin_request(path='/samples/auth.xml')
- self.assertResponseSuccessful(r)
-
- def test_json_sample(self):
- r = self.admin_request(path='/samples/auth.json')
- self.assertResponseSuccessful(r)
-
- def test_stylesheet(self):
- r = self.admin_request(path='/style/shjs/sh_acid.css')
- self.assertResponseSuccessful(r)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_tenants.py b/keystone/test/functional/test_tenants.py
deleted file mode 100644
index 708edbab..00000000
--- a/keystone/test/functional/test_tenants.py
+++ /dev/null
@@ -1,598 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-from keystone.test.functional import common
-
-
-class TenantTest(common.FunctionalTestCase):
- def _assertValidTenant(self, tenant):
- self.assertIsNotNone(tenant.get('id'))
- self.assertIsNotNone(tenant.get('name'))
- self.assertIsNotNone(tenant.get('enabled'))
- self.assertRaises(ValueError, int, tenant.get('id'))
- self.assertTrue(0 < len(tenant.get('id')) < 256,
- "ID must be between 1 and 255 characters long")
- self.assertFalse('/' in tenant.get('id'),
- "ID cannot contain / character")
-
- def _assertValidJsonTenant(self, tenant):
- self._assertValidTenant(tenant)
- # TODO(dolph): this is still a valid assertion in some cases
- # self.assertIsNotNone(tenant.get('description'))
- self.assertIn(tenant.get('enabled'), [True, False], tenant)
-
- def _assertValidXmlTenant(self, xml):
- self.assertEquals(xml.tag, '{%s}tenant' % self.xmlns)
- self._assertValidTenant(xml)
- # TODO(zns): this is still a valid assertion in some cases
- # description = xml.find('{%s}description' % self.xmlns)
- # self.assertIsNotNone(description)
- self.assertIn(xml.get('enabled'), ['true', 'false'])
- return xml
-
- def assertValidJsonTenantResponse(self, response):
- tenant = response.json.get('tenant')
- self._assertValidJsonTenant(tenant)
- return tenant
-
- def assertValidXmlTenantResponse(self, response):
- return self._assertValidXmlTenant(response.xml)
-
- def _assertValidTenantList(self, tenants):
- pass
-
- def _assertValidXmlTenantList(self, xml):
- self.assertEquals(xml.tag, '{%s}tenants' % self.xmlns)
- tenants = xml.findall('{%s}tenant' % self.xmlns)
-
- self._assertValidTenantList(tenants)
- for tenant in tenants:
- self._assertValidXmlTenant(tenant)
- return tenants
-
- def _assertValidJsonTenantList(self, tenants):
- self._assertValidTenantList(tenants)
- for tenant in tenants:
- self._assertValidJsonTenant(tenant)
- return tenants
-
- def assertValidXmlTenantListResponse(self, response):
- return self._assertValidXmlTenantList(response.xml)
-
- def assertValidJsonTenantListResponse(self, response):
- tenants = response.json.get('tenants')
- self.assertIsNotNone(tenants)
- return self._assertValidJsonTenantList(tenants)
-
- def setUp(self, *args, **kwargs):
- super(TenantTest, self).setUp(*args, **kwargs)
-
- def tearDown(self, *args, **kwargs):
- super(TenantTest, self).tearDown(*args, **kwargs)
-
-
-class CreateTenantTest(TenantTest):
- def test_create_tenant(self):
- name = common.unique_str()
- description = common.unique_str()
- response = self.create_tenant(tenant_name=name,
- tenant_description=description, assert_status=201)
- tenant = self.assertValidJsonTenantResponse(response)
- self.assertEqual(name, tenant.get('name'))
- self.assertEqual(description, tenant.get('description'))
-
- def test_create_tenant_blank_name(self):
- self.create_tenant(tenant_name='', assert_status=400)
-
- def test_create_tenant_xml(self):
- name = common.unique_str()
- description = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<tenant xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'enabled="true" name="%s"> '
- '<description>%s</description> '
- '</tenant>') % (name, description)
- response = self.post_tenant(as_xml=data, assert_status=201, headers={
- 'Accept': 'application/xml'})
- tenant = self.assertValidXmlTenantResponse(response)
- self.assertEqual(name, tenant.get('name'))
- self.assertEqual(description,
- tenant.find('{%s}description' % self.xmlns).text)
-
- def test_create_tenant_again(self):
- tenant = self.create_tenant().json['tenant']
- self.create_tenant(tenant_name=tenant['name'], assert_status=409)
-
- def test_create_tenant_again_xml(self):
- tenant = self.create_tenant().json['tenant']
-
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<tenant xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'enabled="true" id="%s"> '
- '<description>A description...</description> '
- '</tenant>') % (tenant['name'],)
-
- self.create_tenant(tenant_name=tenant['name'], as_xml=data,
- assert_status=409)
-
- def test_create_tenant_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.create_tenant(assert_status=403)
-
- def test_create_tenant_expired_token_xml(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- data = '<?xml version="1.0" encoding="UTF-8"?> \
- <tenant xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="true" name="%s"> \
- <description>A description...</description> \
- </tenant>' % (common.unique_str())
-
- self.post_tenant(as_xml=data, assert_status=403)
-
- def test_create_tenant_missing_token(self):
- self.admin_token = ''
- self.create_tenant(assert_status=401)
-
- def test_create_tenant_missing_token_xml(self):
- self.admin_token = ''
- data = '<?xml version="1.0" encoding="UTF-8"?> \
- <tenant xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="true" name="%s"> \
- <description>A description...</description> \
- </tenant>' % (common.unique_str())
-
- self.post_tenant(as_xml=data, assert_status=401)
-
- def test_create_tenant_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_tenant(assert_status=403)
-
- def test_create_tenant_disabled_token_xml(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- data = '<?xml version="1.0" encoding="UTF-8"?> \
- <tenant xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="true" name="%s"> \
- <description>A description...</description> \
- </tenant>' % (common.unique_str())
-
- self.post_tenant(as_xml=data, assert_status=403)
-
- def test_create_tenant_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_tenant(assert_status=401)
-
- def test_create_tenant_invalid_token_xml(self):
- self.admin_token = common.unique_str()
- data = '<?xml version="1.0" encoding="UTF-8"?> \
- <tenant xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="true" name="%s"> \
- <description>A description...</description> \
- </tenant>' % (common.unique_str())
-
- self.post_tenant(as_xml=data, assert_status=401)
-
- def test_create_tenant_missing_name_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<tenant xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'enabled="true" name="%s"> '
- '<description>A description...</description> '
- '</tenant>') % ('',)
- self.post_tenant(as_xml=data, assert_status=400, headers={
- 'Accept': 'application/xml'})
-
-
-class GetTenantsTest(TenantTest):
- def test_get_tenants_using_admin_token(self):
- response = self.list_tenants(assert_status=200)
- self.assertValidJsonTenantListResponse(response)
-
- def test_get_tenants_using_admin_token_xml(self):
- response = self.get_tenants(assert_status=200, headers={
- 'Accept': 'application/xml'})
- self.assertValidXmlTenantListResponse(response)
-
- def test_get_tenants_using_admin_token_xml_on_service_api(self):
- response = self.create_tenant()
- tenant = self.assertValidJsonTenantResponse(response)
- role = self.create_role().json['role']
- user = self.create_user_with_known_password(tenant_id=tenant['id']).\
- json['user']
- self.grant_role_to_user(user_id=user['id'],
- role_id=role['id'], tenant_id=tenant['id'])
-
- # find the admin role
- admin_role = self.get_role_by_name('Admin').json['role']
-
- # grant global admin to user
- self.grant_global_role_to_user(user_id=user['id'],
- role_id=admin_role['id'])
-
- # authenticate as our new admin
- self.service_token = self.authenticate(user['name'],
- user['password']).json['access']['token']['id']
-
- # make a service call with our admin token
- response = self.get_tenants(assert_status=200, headers={
- 'Accept': 'application/xml'}, request_type='service')
- tenants = self.assertValidXmlTenantListResponse(response)
- self.assertEquals(len(tenants), 1)
- self.assertIn(tenant['id'], [t.get('id') for t in tenants])
-
- def test_get_tenants_using_user_token(self):
- response = self.create_tenant()
- tenant = self.assertValidJsonTenantResponse(response)
- user = self.create_user_with_known_password(tenant_id=tenant['id']).\
- json['user']
- token = self.authenticate(user['name'], user['password'],
- tenant['id']).json['access']['token']
- tmp = self.service_token
- self.service_token = token['id']
- response = self.service_request(method='GET', path='/tenants',
- assert_status=200)
- self.service_token = tmp
- tenants = self.assertValidJsonTenantListResponse(response)
- self.assertTrue(len(tenants) == 1)
- self.assertIn(tenant['id'], [t['id'] for t in tenants])
-
- def test_get_tenants_using_user_token_xml(self):
- response = self.create_tenant()
- tenant = self.assertValidJsonTenantResponse(response)
- user = self.create_user_with_known_password(tenant_id=tenant['id']).\
- json['user']
- token = self.authenticate(user['name'], user['password'],
- tenant['id']).json['access']['token']
- tmp = self.service_token
- self.service_token = token['id']
- response = self.service_request(method='GET', path='/tenants',
- assert_status=200, headers={'Accept': 'application/xml'})
- self.service_token = tmp
- tenants = self.assertValidXmlTenantListResponse(response)
- self.assertIn(tenant['id'], [t.get('id') for t in tenants])
-
- def test_get_tenants_exp_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_tenants(assert_status=403)
-
- def test_get_tenants_exp_token_xml(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.get_tenants(assert_status=403, headers={
- 'Accept': 'application/xml'})
-
- def test_get_tenants_blank(self):
- # Create user with no default tenant set
- self.nodefaultuser = self.create_user_with_known_password()\
- .json['user']
- response = self.authenticate(self.nodefaultuser['name'],
- self.nodefaultuser['password'],
- tenant_id=None, assert_status=200)
- token_id = response.json['access']['token']['id']
- response = self.get_tenants(request_type='service', use_token=token_id)
- self.assertTrue(len(response.json['tenants']) == 0,
- "No tenants should be returned")
-
- def test_get_tenants_default_and_role(self):
- """ Validates that the GET /tenants call returns tenants that are
- assigned to the user by role AND by default tenant setting """
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
- other_tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
- self.grant_role_to_user(self.tenant_user['id'], role['id'],
- other_tenant['id'])
-
- response = self.authenticate(self.tenant_user['name'],
- self.tenant_user['password'],
- tenant_id=None, assert_status=200)
- token_id = response.json['access']['token']['id']
- response = self.get_tenants(request_type='service', use_token=token_id)
- tenants = response.json['tenants']
- second_tenant = [tenant for tenant in tenants
- if tenant['id'] == other_tenant['id']]
- self.assertTrue(len(second_tenant) > 0,
- "Tenants with roles assigned should be returned")
-
- default_tenant = [tenant for tenant in tenants
- if tenant['id'] == self.tenant['id']]
- self.assertTrue(len(default_tenant) > 0,
- "Default tenant should be returned")
-
- def test_get_tenants_does_not_return_default(self):
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
- other_tenant = self.create_tenant().json['tenant']
- role = self.create_role().json['role']
- self.grant_role_to_user(self.tenant_user['id'], role['id'],
- other_tenant['id'])
-
- # Authenticate scoped to the non-default tenant
- response = self.authenticate(self.tenant_user['name'],
- self.tenant_user['password'],
- tenant_id=other_tenant['id'],
- assert_status=200)
- token_id = response.json['access']['token']['id']
- response = self.get_tenants(request_type='service', use_token=token_id)
- tenants = response.json['tenants']
- second_tenant = [tenant for tenant in tenants
- if tenant['id'] == other_tenant['id']]
- self.assertTrue(len(second_tenant) > 0,
- "Tenants with roles assigned should be returned")
-
- default_tenant = [tenant for tenant in tenants
- if tenant['id'] == self.tenant['id']]
- self.assertTrue(len(default_tenant) == 0,
- "Default tenant should not be returned")
-
-
-class GetTenantTest(TenantTest):
- def setUp(self, *args, **kwargs):
- super(GetTenantTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_get_tenant(self):
- response = self.fetch_tenant(self.tenant['id'], assert_status=200)
- tenant = self.assertValidJsonTenantResponse(response)
- self.assertEquals(self.tenant['id'], tenant['id'])
- self.assertEquals(self.tenant['name'], tenant['name'])
- self.assertFalse('description' in tenant)
- self.assertEquals(self.tenant['enabled'], tenant['enabled'])
-
- def test_get_tenant_xml(self):
- response = self.fetch_tenant(self.tenant['id'], assert_status=200,
- headers={"Accept": "application/xml"})
- tenant = self.assertValidXmlTenantResponse(response)
- self.assertEquals(self.tenant['id'], tenant.get('id'))
- self.assertEquals(self.tenant['name'], tenant.get('name'))
- self.assertEquals(str(self.tenant['enabled']).lower(),
- tenant.get('enabled'))
-
- def test_get_tenant_not_found(self):
- self.fetch_tenant(assert_status=404)
-
- def test_get_tenant_not_found_xml(self):
- self.get_tenant(common.unique_str(), assert_status=404, headers={
- 'Accept': 'application/xml'})
-
-
-class GetTenantUsersTest(TenantTest):
- def setUp(self, *args, **kwargs):
- super(GetTenantUsersTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
- self.fixture_create_normal_user()
-
- role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'], role['id'], self.tenant['id'])
-
- def test_list_tenant_users(self):
- user = self.list_tenant_users(self.tenant['id'],
- assert_status=200).json['users'][0]
- self.assertEquals(user['name'], self.user['name'])
-
- def test_list_tenant_users_xml(self):
- response = self.list_tenant_users(self.tenant['id'],
- assert_status=200, headers={
- "Accept": "application/xml"})
- self.assertEquals(response.xml.tag, '{%s}users' % self.xmlns)
- users = response.xml.findall('{%s}user' % self.xmlns)
- for user in users:
- self.assertEqual(user.get('name'), self.user['name'])
-
- def test_list_tenant_users_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_tenant_users(self.tenant['id'], assert_status=403)
-
- def test_list_tenant_users_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.list_tenant_users(self.tenant['id'], assert_status=403)
-
- def test_list_tenant_users_missing_token(self):
- self.admin_token = ''
- self.list_tenant_users(self.tenant['id'], assert_status=401)
-
- def test_list_tenant_users_invalid_token(self):
- self.admin_token = common.unique_str()
- self.list_tenant_users(self.tenant['id'], assert_status=401)
-
-
-class GetTenantUsersByRoleTest(TenantTest):
- def setUp(self, *args, **kwargs):
- super(GetTenantUsersByRoleTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
- self.fixture_create_normal_user()
-
- self.role = self.create_role().json['role']
- self.grant_role_to_user(self.user['id'],
- self.role['id'], self.tenant['id'])
-
- def test_list_tenant_users(self):
- user = self.list_tenant_users(self.tenant['id'],
- self.role['id'], assert_status=200).json['users'][0]
- self.assertEquals(user['name'], self.user['name'])
-
- def test_list_tenant_users_xml(self):
- response = self.list_tenant_users(self.tenant['id'],
- self.role['id'], assert_status=200, headers={
- "Accept": "application/xml"})
- self.assertEquals(response.xml.tag, '{%s}users' % self.xmlns)
- users = response.xml.findall('{%s}user' % self.xmlns)
- for user in users:
- self.assertEqual(user.get('name'), self.user['name'])
-
- def test_list_tenant_users_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_tenant_users(self.tenant['id'],
- self.role['id'], assert_status=403)
-
- def test_list_tenant_users_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.list_tenant_users(self.tenant['id'],
- self.role['id'], assert_status=403)
-
- def test_list_tenant_users_missing_token(self):
- self.admin_token = ''
- self.list_tenant_users(self.tenant['id'],
- self.role['id'], assert_status=401)
-
- def test_list_tenant_users_invalid_token(self):
- self.admin_token = common.unique_str()
- self.list_tenant_users(self.tenant['id'],
- self.role['id'], assert_status=401)
-
-
-class GetTenantByNameTest(TenantTest):
- def setUp(self, *args, **kwargs):
- super(GetTenantByNameTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_get_tenant(self):
- response = self.fetch_tenant_by_name(self.tenant['name'],
- assert_status=200)
- tenant = self.assertValidJsonTenantResponse(response)
- self.assertEquals(self.tenant['id'], tenant['id'])
- self.assertEquals(self.tenant['name'], tenant['name'])
- self.assertEquals(self.tenant['enabled'], tenant['enabled'])
-
- def test_get_tenant_data(self):
- tenant = self.fixture_create_tenant(name=common.unique_str(),
- description=common.unique_str(),
- enabled=True)
- response = self.fetch_tenant_by_name(tenant['name'], assert_status=200)
- returned = self.assertValidJsonTenantResponse(response)
- self.assertEquals(returned['id'], tenant['id'])
- self.assertEquals(returned['name'], tenant['name'])
- self.assertEquals(returned['description'], tenant['description'])
- self.assertEquals(returned['enabled'], tenant['enabled'])
-
- def test_get_tenant_xml(self):
- response = self.fetch_tenant_by_name(
- self.tenant['name'], assert_status=200, headers={
- "Accept": "application/xml"})
- tenant = self.assertValidXmlTenantResponse(response)
-
- self.assertEquals(self.tenant['id'], tenant.get('id'))
- self.assertEquals(self.tenant['name'], tenant.get('name'))
- self.assertEquals(str(self.tenant['enabled']).lower(),
- tenant.get('enabled'))
-
- def test_get_tenant_not_found(self):
- self.fetch_tenant_by_name(assert_status=404)
-
- def test_get_tenant_not_found_xml(self):
- self.fetch_tenant_by_name(
- common.unique_str(), assert_status=404, headers={
- 'Accept': 'application/xml'})
-
-
-class UpdateTenantTest(TenantTest):
- def setUp(self, *args, **kwargs):
- super(UpdateTenantTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_update_tenant(self):
- new_tenant_name = common.unique_str()
- new_description = common.unique_str()
- response = self.update_tenant(self.tenant['id'],
- tenant_name=new_tenant_name, tenant_enabled=False,
- tenant_description=new_description, assert_status=200)
- updated_tenant = self.assertValidJsonTenantResponse(response)
- self.assertEqual(updated_tenant['name'], new_tenant_name)
- self.assertEqual(updated_tenant['description'], new_description)
- self.assertEqual(updated_tenant['enabled'], False)
-
- def test_update_tenant_xml(self):
- new_tenant_name = common.unique_str()
- new_description = common.unique_str()
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<tenant xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'name="%s" '
- 'enabled="false"> '
- '<description>%s</description> '
- '</tenant>') % (new_tenant_name, new_description,)
- response = self.post_tenant_for_update(
- self.tenant['id'], as_xml=data, assert_status=200)
- updated = self.assertValidXmlTenantResponse(response)
-
- self.assertEqual(updated.get('id'), self.tenant['id'])
- self.assertEqual(updated.get('name'), new_tenant_name)
- description = updated.find("{%s}description" % self.xmlns)
- self.assertEqual(description.text, new_description)
- self.assertEqual(updated.get('enabled'), 'false')
-
- def test_update_tenant_bad(self):
- data = '{"tenant": { "description_bad": "A NEW description...",\
- "enabled":true }}'
- self.post_tenant_for_update(
- self.tenant['id'], as_json=data, assert_status=400)
-
- def test_update_tenant_bad_xml(self):
- data = '<?xml version="1.0" encoding="UTF-8"?> \
- <tenant xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="true"> \
- <description_bad>A NEW description...</description> \
- </tenant>'
- self.post_tenant_for_update(
- self.tenant['id'], as_xml=data, assert_status=400)
-
- def test_update_tenant_not_found(self):
- self.update_tenant(assert_status=404)
-
- def test_update_tenant_not_found_xml(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?>'
- '<tenant xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'enabled="true"> '
- '<description>A NEW description...</description> '
- '</tenant>')
- self.post_tenant_for_update(
- common.unique_str(), as_xml=data, assert_status=404)
-
-
-class DeleteTenantTest(TenantTest):
- def setUp(self, *args, **kwargs):
- super(DeleteTenantTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_delete_tenant(self):
- self.remove_tenant(self.tenant['id'], assert_status=204)
- self.get_tenant(self.tenant['id'], assert_status=404)
- self.update_tenant(self.tenant['id'], assert_status=404)
-
- def test_delete_tenant_xml(self):
- self.delete_tenant(self.tenant['id'], assert_status=204, headers={
- 'Accept': 'application/xml'})
- self.get_tenant(self.tenant['id'], assert_status=404)
- self.update_tenant(self.tenant['id'], assert_status=404)
-
- def test_delete_tenant_not_found(self):
- self.remove_tenant(common.unique_str(), assert_status=404)
-
- def test_delete_tenant_not_found_xml(self):
- self.delete_tenant(common.unique_str(), assert_status=404, headers={
- 'Accept': 'application/xml'})
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_token.py b/keystone/test/functional/test_token.py
deleted file mode 100644
index 54a41ce0..00000000
--- a/keystone/test/functional/test_token.py
+++ /dev/null
@@ -1,207 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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.
-
-# pylint: disable=W0613
-
-import unittest2 as unittest
-
-from keystone.backends import api
-from keystone.logic.types import fault
-from keystone.logic import service
-from keystone.test.functional import common
-
-
-class ValidateToken(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(ValidateToken, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- self.user = self.create_user_with_known_password(
- tenant_id=self.tenant['id']).json['user']
- self.role = self.create_role().json['role']
- self.rolegrant = self.grant_role_to_user(self.user['id'],
- self.role['id'], self.tenant['id'])
- self.token = self.authenticate(self.user['name'],
- self.user['password'], self.tenant['id']).json['access']['token']
-
- def test_validate_token_true(self):
- r = self.get_token_belongsto(self.token['id'], self.tenant['id'],
- assert_status=200)
- self.assertIsNotNone(r.json['access']['user']["roles"])
- self.assertEqual(r.json['access']['user']["roles"][0]['id'],
- self.role['id'])
- self.assertEqual(r.json['access']['user']["roles"][0]['name'],
- self.role['name'])
- self.assertIsNotNone(r.json['access']['user']['id'], self.user['id'])
- self.assertIsNotNone(r.json['access']['user']['name'],
- self.user['name'])
- self.assertIn('tenants', r.json['access']['token'])
-
- def test_validate_token_true_using_service_token(self):
- self.fixture_create_service_admin()
- self.admin_token = self.service_admin_token
- r = self.get_token_belongsto(self.token['id'], self.tenant['id'],
- assert_status=200)
-
- self.assertIsNotNone(r.json['access']['user']["roles"])
- self.assertEqual(r.json['access']['user']["roles"][0]['id'],
- self.role['id'])
- self.assertEqual(r.json['access']['user']["roles"][0]['name'],
- self.role['name'])
-
- def test_validate_token_true_xml(self):
- r = self.get_token_belongsto(self.token['id'], self.tenant['id'],
- assert_status=200, headers={'Accept': 'application/xml'})
-
- self.assertEqual(r.xml.tag, '{%s}access' % self.xmlns)
-
- user = r.xml.find('{%s}user' % self.xmlns)
- self.assertIsNotNone(user)
- self.assertEqual(self.user['id'], user.get('id'))
- self.assertEqual(self.user['name'], user.get('name'))
-
- roles = user.find('{%s}roles' % self.xmlns)
- self.assertIsNotNone(roles)
-
- role = roles.find('{%s}role' % self.xmlns)
- self.assertIsNotNone(role)
- self.assertEqual(self.role['id'], role.get("id"))
- self.assertEqual(self.role['name'], role.get("name"))
-
- def test_validate_token_expired(self):
- self.get_token(self.expired_admin_token, assert_status=404)
-
- def test_validate_token_expired_xml(self):
- self.get_token(self.expired_admin_token, assert_status=404, headers={
- 'Accept': 'application/xml'})
-
- def test_validate_token_invalid(self):
- self.get_token(common.unique_str(), assert_status=404)
-
- def test_validate_token_invalid_xml(self):
- self.get_token(common.unique_str(), assert_status=404, headers={
- 'Accept': 'application/xml'})
-
-
-class CheckToken(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(CheckToken, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
- self.fixture_create_tenant_user()
-
- self.token = self.authenticate(self.tenant_user['name'],
- self.tenant_user['password'],
- self.tenant['id']).json['access']['token']
-
- def test_validate_token_true(self):
- self.check_token_belongs_to(self.token['id'], self.tenant['id'],
- assert_status=200)
-
- def test_validate_token_true_using_service_token(self):
- self.fixture_create_service_admin()
- self.admin_token = self.service_admin_token
- self.check_token_belongs_to(self.token['id'], self.tenant['id'],
- assert_status=200)
-
- def test_validate_token_expired(self):
- self.fixture_create_expired_token()
- self.check_token(self.expired_admin_token, assert_status=404)
-
- def test_validate_token_expired_xml(self):
- self.fixture_create_expired_token()
- self.check_token(self.expired_admin_token, assert_status=404, headers={
- 'Accept': 'application/xml'})
-
- def test_validate_token_invalid(self):
- self.check_token(common.unique_str(), assert_status=404)
-
-
-# pylint: disable=E1101,E1120
-class TokenEndpointTest(unittest.TestCase):
- def _noop_validate_admin_token(self, admin_token):
- pass
-
- class FakeDtoken(object):
- expires = 'now'
- tenant_id = 1
- id = 2
-
- def _fake_token_get(self, token_id):
- return self.FakeDtoken()
-
- def _fake_missing_token_get(self, token_id):
- return None
-
- class FakeEndpoint(object):
- service = 'foo'
-
- def _fake_tenant_get_all_endpoints(self, tenant_id):
- return [self.FakeEndpoint()]
-
- def _fake_exploding_tenant_get_all_endpoints(self, tenant_id):
- raise Exception("boom")
-
- def setUp(self):
- self.stubout = stubout.StubOutForTesting()
-
- self.identity = service.IdentityService()
- # The downside of python "private" methods ... you
- # have to do stuff like this to stub them out.
- self.stubout.SmartSet(self.identity,
- "_IdentityService__validate_admin_token",
- self._noop_validate_admin_token)
-
- def tearDown(self):
- self.stubout.SmartUnsetAll()
- self.stubout.UnsetAll()
-
- def test_endpoints_from_good_token(self):
- """Happy Day scenario."""
- self.stubout.SmartSet(api.TOKEN,
- 'get', self._fake_token_get)
-
- self.stubout.SmartSet(api.BaseTenantAPI,
- 'get_all_endpoints',
- self._fake_tenant_get_all_endpoints)
-
- auth_data = self.identity.get_endpoints_for_token("admin token",
- "token id")
- self.assertEquals(auth_data.base_urls[0].service, 'foo')
- self.assertEquals(len(auth_data.base_urls), 1)
-
- def test_endpoints_from_bad_token(self):
- self.stubout.SmartSet(api.TOKEN,
- 'get', self._fake_missing_token_get)
-
- self.assertRaises(fault.ItemNotFoundFault,
- self.identity.get_endpoints_for_token,
- "admin token", "token id")
-
- def test_bad_endpoints(self):
- self.stubout.SmartSet(api.TOKEN,
- 'get', self._fake_token_get)
-
- self.stubout.SmartSet(api.TENANT,
- 'get_all_endpoints',
- self._fake_exploding_tenant_get_all_endpoints)
-
- endpoints = self.identity.get_endpoints_for_token("admin token",
- "token id")
- self.assertEquals(endpoints.base_urls, [])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/functional/test_users.py b/keystone/test/functional/test_users.py
deleted file mode 100644
index 7027986c..00000000
--- a/keystone/test/functional/test_users.py
+++ /dev/null
@@ -1,406 +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 unittest2 as unittest
-from keystone.test.functional import common
-
-
-class UserTest(common.FunctionalTestCase):
- def setUp(self, *args, **kwargs):
- super(UserTest, self).setUp(*args, **kwargs)
-
-
-class CreateUserTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(CreateUserTest, self).setUp(*args, **kwargs)
-
- def test_create_user_with_tenant(self):
- tenant = self.create_tenant().json['tenant']
- self.user = self.create_user(tenant_id=tenant['id'],
- assert_status=201)
-
- def test_user_with_no_tenant(self):
- self.create_user(assert_status=201)
-
- def test_create_user_disabled_tenant(self):
- tenant = self.create_tenant(tenant_enabled=False).json['tenant']
- self.create_user(tenant_id=tenant['id'], assert_status=403)
-
- def test_create_user_again(self):
- user_name = common.unique_str()
- self.create_user(user_name)
- self.create_user(user_name, assert_status=409)
-
- def test_create_users_with_duplicate_emails(self):
- email = common.unique_email()
- self.create_user(user_email=email)
- self.create_user(user_email=email, assert_status=409)
-
- def test_create_user_with_empty_password(self):
- self.create_user(user_password='', assert_status=400)
-
- def test_create_user_with_empty_username(self):
- self.create_user(user_name='', assert_status=400)
-
- def test_create_user_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.create_user(assert_status=403)
-
- def test_create_user_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_user(assert_status=403)
-
- def test_create_user_missing_token(self):
- self.admin_token = ''
- self.create_user(assert_status=401)
-
- def test_create_user_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_user(assert_status=401)
-
- def test_create_user_xml_missing_name(self):
- data = ('<?xml version="1.0" encoding="UTF-8"?> '
- '<user xmlns="http://docs.openstack.org/identity/api/v2.0" '
- 'enabled="true" email="john.smith@example.org" '
- 'name="" id="u1000"/>')
- self.post_user(as_xml=data, assert_status=400)
-
-
-class GetUserTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(GetUserTest, self).setUp(*args, **kwargs)
-
- self.user = self.create_user().json['user']
-
- def test_get_user(self):
- self.fetch_user(self.user['id'])
-
- def test_query_user(self):
- self.fetch_user_by_name(self.user['name'])
-
- def test_get_user_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_user(self.user['id'], assert_status=403)
-
- def test_query_user_using_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.fetch_user_by_name(self.user['name'], assert_status=403)
-
- def test_get_user_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_user(self.user['id'], assert_status=403)
-
- def test_query_user_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.fetch_user_by_name(self.user['name'], assert_status=403)
-
- def test_get_user_using_missing_token(self):
- self.admin_token = ''
- self.fetch_user(self.user['id'], assert_status=401)
-
- def test_query_user_using_missing_token(self):
- self.admin_token = ''
- self.fetch_user_by_name(self.user['name'], assert_status=401)
-
- def test_get_user_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_user(self.user['id'], assert_status=401)
-
- def test_query_user_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.fetch_user_by_name(self.user['name'], assert_status=401)
-
- def test_get_disabled_user(self):
- self.disable_user(self.user['id'])
- user = self.fetch_user(self.user['id']).json['user']
- self.assertFalse(user['enabled'])
-
- def test_query_disabled_user(self):
- self.disable_user(self.user['id'])
- self.fetch_user_by_name(self.user['name'])
-
-
-class DeleteUserTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(DeleteUserTest, self).setUp(*args, **kwargs)
-
- self.user = self.create_user().json['user']
-
- def test_user_delete(self):
- self.remove_user(self.user['id'], assert_status=204)
-
- def test_user_delete_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.remove_user(self.user['id'], assert_status=403)
-
- def test_user_delete_missing_token(self):
- self.admin_token = ''
- self.remove_user(self.user['id'], assert_status=401)
-
- def test_user_delete_invalid_token(self):
- self.admin_token = common.unique_str()
- self.remove_user(self.user['id'], assert_status=401)
-
-
-class GetAllUsersTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(GetAllUsersTest, self).setUp(*args, **kwargs)
-
- for _x in range(0, 3):
- self.create_user()
-
- def test_list_users(self):
- self.list_users(assert_status=200)
-
- def test_list_users_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.list_users(assert_status=403)
-
- def test_list_users_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.list_users(assert_status=403)
-
- def test_list_users_missing_token(self):
- self.admin_token = ''
- self.list_users(assert_status=401)
-
- def test_list_users_invalid_token(self):
- self.admin_token = common.unique_str()
- self.list_users(assert_status=401)
-
-
-class UpdateUserTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(UpdateUserTest, self).setUp(*args, **kwargs)
-
- self.user = self.create_user().json['user']
-
- def test_update_user_email(self):
- new_user_email = common.unique_email()
- self.update_user(self.user['id'], user_name=self.user['name'],
- user_email=new_user_email)
- r = self.fetch_user(self.user['id'])
- self.assertTrue(r.json['user']['email'], new_user_email)
-
- def test_update_user_name(self):
- new_user_name = common.unique_str()
- new_user_email = common.unique_email()
- self.update_user(self.user['id'], user_name=new_user_name,
- user_email=new_user_email)
- r = self.fetch_user(self.user['id'])
- self.assertTrue(r.json['user']['name'], new_user_name)
-
- def test_enable_disable_user(self):
- self.assertFalse(self.disable_user(self.user['id']).\
- json['user']['enabled'])
- self.assertFalse(self.fetch_user(self.user['id']).\
- json['user']['enabled'])
- self.assertTrue(self.enable_user(self.user['id']).\
- json['user']['enabled'])
- self.assertTrue(self.fetch_user(self.user['id']).\
- json['user']['enabled'])
-
- def test_update_user_bad_request(self):
- data = '{"user_bad": { "bad": "%s"}}' % (common.unique_email(),)
- self.post_user_for_update(
- self.user['id'], assert_status=400, body=data, headers={
- "Content-Type": "application/json"})
-
- def test_update_user_expired_token(self):
- self.fixture_create_expired_token()
- self.fixture_create_normal_user()
-
- self.admin_token = self.expired_admin_token
- self.update_user(self.user['id'], assert_status=403)
-
- def test_update_user_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.update_user(self.user['id'], user_email=common.unique_email(),
- assert_status=403)
-
- def test_update_user_invalid_token(self):
- self.admin_token = common.unique_str()
- self.update_user(self.user['id'], assert_status=401)
-
- def test_update_user_missing_token(self):
- self.admin_token = ''
- self.update_user(self.user['id'], assert_status=401)
-
-
-class TestUpdateConflict(UserTest):
- def setUp(self, *args, **kwargs):
- super(TestUpdateConflict, self).setUp(*args, **kwargs)
-
- self.users = {}
- for x in range(0, 2):
- self.users[x] = self.create_user().json['user']
-
- def test_update_user_email_conflict(self):
- """Replace the second user's email with that of the first"""
- self.update_user(user_id=self.users[1]['id'],
- user_name=self.users[1]['name'],
- user_email=self.users[0]['email'], assert_status=409)
-
-
-class SetPasswordTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(SetPasswordTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_user()
-
- def test_update_user_password(self):
- new_password = common.unique_str()
- r = self.update_user_password(self.user['id'], new_password)
- self.assertEqual(r.json['user']['password'], new_password)
-
- def test_update_disabled_users_password(self):
- self.disable_user(self.user['id'])
-
- new_password = common.unique_str()
- r = self.update_user_password(self.user['id'], new_password)
- self.assertEqual(r.json['user']['password'], new_password)
-
- def test_user_password_bad_request(self):
- data = '{"user_bad": { "password": "p@ssword"}}'
- self.put_user_password(self.user['id'], body=data, assert_status=400,
- headers={
- "Content-Type": "application/json"})
-
- def test_user_password_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.update_user_password(self.user['id'], assert_status=403)
-
- def test_user_password_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.update_user_password(self.user['id'], assert_status=403)
-
- def test_user_password_invalid_token(self):
- self.admin_token = common.unique_str()
- self.update_user_password(self.user['id'], assert_status=401)
-
- def test_user_password_missing_token(self):
- self.admin_token = ''
- self.update_user_password(self.user['id'], assert_status=401)
-
-
-class SetEnabledTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(SetEnabledTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_user()
-
- def test_user_enabled_bad_request(self):
- data = '{"user_bad": { "enabled": true}}'
- self.put_user_enabled(self.user['id'], body=data, assert_status=400,
- headers={
- "Content-Type": "application/json"})
-
- def test_user_enabled_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.disable_user(self.user['id'], assert_status=403)
-
- def test_user_enabled_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.disable_user(self.user['id'], assert_status=403)
-
-
-class TenantUpdateTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(TenantUpdateTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_user()
- self.fixture_create_normal_tenant()
-
- def test_update_user_tenant(self):
- r = self.update_user_tenant(self.user['id'], self.tenant['id'])
- self.assertEqual(r.json['user']['tenantId'], self.tenant['id'])
-
- def test_update_user_tenant_using_invalid_tenant(self):
- self.update_user_tenant(self.user['id'], assert_status=404)
-
- def test_update_user_tenant_using_disabled_tenant(self):
- disabled_tenant = self.create_tenant(
- tenant_enabled=False).json['tenant']
- self.assertIsNotNone(disabled_tenant['id'])
- self.update_user_tenant(self.user['id'], disabled_tenant['id'],
- assert_status=403)
-
- def test_update_user_tenant_using_missing_token(self):
- self.admin_token = ''
- self.update_user_tenant(self.user['id'], self.tenant['id'],
- assert_status=401)
-
- def test_update_user_tenant_using_invalid_token(self):
- self.admin_token = common.unique_str()
- self.update_user_tenant(self.user['id'], self.tenant['id'],
- assert_status=401)
-
- def test_update_user_tenant_using_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.update_user_tenant(self.user['id'], self.tenant['id'],
- assert_status=403)
-
- def test_update_user_tenant_using_exp_admin_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.update_user_tenant(self.user['id'], self.tenant['id'],
- assert_status=403)
-
-
-class AddUserTest(UserTest):
- def setUp(self, *args, **kwargs):
- super(AddUserTest, self).setUp(*args, **kwargs)
- self.fixture_create_normal_tenant()
-
- def test_add_user_tenant(self):
- self.create_user(tenant_id=self.tenant['id'], assert_status=201)
-
- def test_add_user_tenant_expired_token(self):
- self.fixture_create_expired_token()
- self.admin_token = self.expired_admin_token
- self.create_user(assert_status=403)
-
- def test_add_user_tenant_disabled_token(self):
- self.fixture_create_disabled_user_and_token()
- self.admin_token = self.disabled_admin_token
- self.create_user(assert_status=403)
-
- def test_add_user_tenant_invalid_token(self):
- self.admin_token = common.unique_str()
- self.create_user(assert_status=401)
-
- def test_add_user_tenant_missing_token(self):
- self.admin_token = ''
- self.create_user(assert_status=401)
-
- def test_add_user_tenant_disabled_tenant(self):
- self.tenant = self.create_tenant(tenant_enabled=False).json['tenant']
- self.create_user(tenant_id=self.tenant['id'], assert_status=403)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/sampledata.py b/keystone/test/sampledata.py
deleted file mode 100644
index 410e291d..00000000
--- a/keystone/test/sampledata.py
+++ /dev/null
@@ -1,137 +0,0 @@
-import keystone.manage
-
-DEFAULT_FIXTURE = [
-# Tenants
- ('tenant', 'add', 'customer-x'),
- ('tenant', 'add', 'ANOTHER:TENANT'),
- ('tenant', 'add', 'project-y'),
- ('tenant', 'disable', 'project-y'),
- ('tenant', 'add', 'coffee-tea'),
-# Add some services for the service roles
- ('service', 'add', 'coffee',
- 'coffee service', 'coffee service'),
- ('service', 'add', 'tea',
- 'tea house', 'tea house'),
-# Users
- ('user', 'add', 'joeuser', 'secrete', 'customer-x'),
- ('user', 'add', 'pete', 'secrete', 'coffee-tea'),
- ('user', 'add', 'joeadmin', 'secrete', 'customer-x'),
- ('user', 'add', 'admin', 'secrete'),
- ('user', 'add', 'serviceadmin', 'secrete', 'customer-x'),
- ('user', 'add', 'disabled', 'secrete', 'customer-x'),
- ('user', 'add', 'nodefaulttenant', 'secrete'),
- ('user', 'disable', 'disabled'),
-# Roles
- ('role', 'add', 'Admin'),
- ('role', 'add', 'KeystoneServiceAdmin'),
- ('role', 'grant', 'Admin', 'admin'),
- ('role', 'grant', 'KeystoneServiceAdmin', 'serviceadmin'),
- ('role', 'grant', 'Admin', 'joeadmin', 'customer-x'),
- ('role', 'grant', 'Admin', 'joeadmin', 'ANOTHER:TENANT'),
- ('role', 'grant', 'Admin', 'nodefaulttenant', 'customer-x'),
- ('role', 'add', 'Member'),
- ('role', 'grant', 'Member', 'joeuser', 'customer-x'),
- ('role', 'add', 'barista', 'coffee'),
- ('role', 'add', 'barista', 'tea'),
- ('role', 'grant', 'barista', 'pete'),
- ('role', 'add', 'barista-global'),
- ('role', 'grant', 'barista-global', 'pete'),
-# Add Services
- #1 Service Name:exampleservice Type:example type
- ('service', 'add', 'exampleservice',
- 'example type', 'example description'),
- #2 Service Name:swift Type:object-store
- ('service', 'add', 'swift',
- 'object-store', 'Swift-compatible service'),
- #3 Service Name:cdn Type:object-store
- ('service', 'add', 'cdn',
- 'object-store', 'Swift-compatible service'),
- #4 Service Name:nova Type:compute
- ('service', 'add', 'nova',
- 'compute', 'OpenStack Compute Service'),
- #5 Service Name:nova_compat Type:Compute
- ('service', 'add', 'nova_compat',
- 'compute', 'OpenStack Compute Service'),
- #6 Service Name:glance Type:image
- ('service', 'add', 'glance',
- 'image', 'OpenStack Image Service'),
- #7 Service Name:keystone Type:identity
- ('service', 'add', 'identity',
- 'identity', 'OpenStack Identity Service'),
-# Keeping for compatibility for a while till dashboard catches up
- ('endpointTemplates', 'add', 'RegionOne', 'swift',
- 'http://swift.publicinternets.com/v1/AUTH_%tenant_id%',
- 'http://swift.admin-nets.local:8080/',
- 'http://127.0.0.1:8080/v1/AUTH_%tenant_id%', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'nova_compat',
- 'http://nova.publicinternets.com/v1.0/',
- 'http://127.0.0.1:8774/v1.0', 'http://localhost:8774/v1.0', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'nova',
- 'http://nova.publicinternets.com/v1.1/', 'http://127.0.0.1:8774/v1.1',
- 'http://localhost:8774/v1.1', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'glance',
- 'http://glance.publicinternets.com/v1.1/',
- 'http://nova.admin-nets.local/v1.1/',
- 'http://127.0.0.1:9292/v1.1/', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'cdn',
- 'http://cdn.publicinternets.com/v1.1/%tenant_id%',
- 'http://cdn.admin-nets.local/v1.1/%tenant_id%',
- 'http://127.0.0.1:7777/v1.1/%tenant_id%', '1',
- '0', '1.1', 'http://127.0.0.1:7777/', 'http://127.0.0.1:7777/v1.1'),
-# endpointTemplates
- ('endpointTemplates', 'add', 'RegionOne', 'swift',
- 'http://swift.publicinternets.com/v1/AUTH_%tenant_id%',
- 'http://swift.admin-nets.local:8080/',
- 'http://127.0.0.1:8080/v1/AUTH_%tenant_id%', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'nova',
- 'http://nova.publicinternets.com/v1.0/', 'http://127.0.0.1:8774/v1.0',
- 'http://localhost:8774/v1.0', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'nova_compat',
- 'http://nova.publicinternets.com/v1.1/', 'http://127.0.0.1:8774/v1.1',
- 'http://localhost:8774/v1.1', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'glance',
- 'http://glance.publicinternets.com/v1.1/',
- 'http://nova.admin-nets.local/v1.1/',
- 'http://127.0.0.1:9292/v1.1/', '1', '0'),
- ('endpointTemplates', 'add', 'RegionOne', 'cdn',
- 'http://cdn.publicinternets.com/v1.1/%tenant_id%',
- 'http://cdn.admin-nets.local/v1.1/%tenant_id%',
- 'http://127.0.0.1:7777/v1.1/%tenant_id%', '1', '0'),
-# Global endpointTemplate
- ('endpointTemplates', 'add', 'RegionOne', 'identity',
- 'http://keystone.publicinternets.com/v2.0',
- 'http://127.0.0.1:35357/v2.0', 'http://127.0.0.1:5000/v2.0', '1', '1'),
-# Tokens
- ('token', 'add', '887665443383838', 'joeuser', 'customer-x',
- '2012-02-05T00:00'),
- ('token', 'add', '999888777666', 'admin', None,
- '2015-02-05T00:00'),
- ('token', 'add', '111222333444', 'serviceadmin', None,
- '2015-02-05T00:00'),
- ('token', 'add', '000999', 'admin', 'customer-x', '2010-02-05T00:00'),
- ('token', 'add', '999888777', 'disabled', 'customer-x',
- '2015-02-05T00:00'),
-# Tenant endpointsGlobal endpoint not added
- ('endpoint', 'add', 'customer-x', '1'),
- ('endpoint', 'add', 'customer-x', '2'),
- ('endpoint', 'add', 'customer-x', '3'),
- ('endpoint', 'add', 'customer-x', '4'),
- ('endpoint', 'add', 'customer-x', '5'),
-# Add Credentials
- ('credentials', 'add', 'admin', 'EC2', 'admin:admin', 'admin',
- 'customer-x'),
-]
-
-
-def load_fixture(fixture=DEFAULT_FIXTURE, args=None):
- keystone.manage.parse_args(args)
- for cmd in fixture:
- keystone.manage.process(*cmd)
-
-
-def main():
- load_fixture()
-
-
-if __name__ == '__main__':
- main()
diff --git a/keystone/test/unit/__init__.py b/keystone/test/unit/__init__.py
deleted file mode 100644
index e69de29b..00000000
--- a/keystone/test/unit/__init__.py
+++ /dev/null
diff --git a/keystone/test/unit/base.py b/keystone/test/unit/base.py
deleted file mode 100644
index 0ad0c327..00000000
--- a/keystone/test/unit/base.py
+++ /dev/null
@@ -1,385 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2011 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.
-
-"""Base test case classes for the unit tests"""
-
-import datetime
-import functools
-import httplib
-import logging
-from lxml import etree, objectify
-import pprint
-import os
-import sys
-import tempfile
-import unittest2 as unittest
-import webob
-
-from keystone import config
-from keystone import server
-import keystone.backends.sqlalchemy as db
-import keystone.backends.api as db_api
-from keystone import backends
-
-logger = logging.getLogger('test.unit.base')
-
-CONF = config.CONF
-
-
-class ServiceAPITest(unittest.TestCase):
- """
- Base test case class for any unit test that tests the main service API.
- """
- def __init__(self, *args, **kwargs):
- super(ServiceAPITest, self).__init__(*args, **kwargs)
- # The `api` attribute for this base class is the `server.KeystoneAPI`
- # controller.
- self.api_class = server.ServiceApi
- # Set of dicts of tenant attributes we start each test case with
- self.tenant_fixtures = [
- {'name': 'tenant1',
- 'enabled': True,
- 'desc': 'tenant1'}]
- # Attributes of the Service used for the roles.
- self.service_attrs = {
- 'id': "0",
- 'name': 'test_service',
- 'type': 'test',
- 'desc': 'test service',
- 'owner_id': "0"}
- # Set of Role fixtures to create for each test
- self.role_fixtures = [
- {'id': "0",
- 'name': 'regular_role',
- 'desc': 'regular role',
- 'service_id': self.service_attrs['id']},
- {'id': "1",
- 'name': 'Admin',
- 'desc': 'Admin role',
- 'service_id': self.service_attrs['id']},
- ]
- # Attributes of the user the test creates for each test case that
- # will authenticate against the API. The `auth_user` attribute
- # will contain the created user with the following attributes.
- self.user_attrs = {
- 'auth_user':
- {'name': 'auth_user',
- 'password': 'auth_pass',
- 'email': 'auth_user@example.com',
- 'enabled': True,
- 'tenant_name': 'tenant1',
- 'roles': [self.role_fixtures[0]],
- },
- 'admin_user':
- {'name': 'admin_user',
- 'password': 'admin_pass',
- 'email': 'admin_user@example.com',
- 'enabled': True,
- 'tenant_name': 'tenant1',
- 'roles': [self.role_fixtures[1]],
- }}
- # Special attribute that is the identifier of the token we use in
- # authenticating. Makes it easy to test the authentication process.
- self.auth_token_id = 'SPECIALAUTHTOKEN'
- # The special attribute for identifying the admin token.
- self.admin_token_id = 'SPECIALADMINTOKEN'
- # Content-type of requests. Generally, you don't need to manually
- # change this. Instead, :see test.unit.decorators
- self.content_type = 'json'
- # Version of the API to test
- self.api_version = '2.0'
- # Save the original configuration
- self.conf_save = CONF
- # Set the desired conf options
- conf_text = """
-[DEFAULT]
-backends = keystone.backends.sqlalchemy
-keystone_admin_role = Admin
-keystone_service_admin_role = KeystoneServiceAdmin
-hash_password = True
-verbose = False
-debug = False
-
-[keystone.backends.sqlalchemy]
-sql_connection = sqlite://
-backend_entities = ['UserRoleAssociation',
- 'Endpoints', 'Role', 'Tenant', 'User',
- 'Credentials', 'EndpointTemplates', 'Token', 'Service']
-"""
- self.update_CONF(conf_text)
-
- @staticmethod
- def update_CONF(txt):
- """
- Resets the CONF file, and reads in the passed configuration text.
- """
- CONF.reset()
- fd, tmpname = tempfile.mkstemp()
- os.close(fd)
- with file(tmpname, "w") as fconf:
- fconf.write(txt)
- CONF(config_files=[tmpname])
- os.remove(tmpname)
-
- def setUp(self):
- self.api = self.api_class()
-
- dt = datetime
- self.expires = dt.datetime.utcnow() + dt.timedelta(days=1)
- self.clear_all_data()
-
- # Create all our base tenants
- for tenant in self.tenant_fixtures:
- self.fixture_create_tenant(**tenant)
-
- # Create the test service
- self.fixture_create_service(**self.service_attrs)
-
- # Create all our roles
- for role in self.role_fixtures:
- self.fixture_create_role(**role)
-
- # Create the user we will authenticate with
- auth_user_attrs = self.user_attrs.get("auth_user")
- admin_user_attrs = self.user_attrs.get("admin_user")
- self.auth_user = self.fixture_create_user(**auth_user_attrs)
- self.admin_user = self.fixture_create_user(**admin_user_attrs)
- self.auth_token = self.fixture_create_token(
- id=self.auth_token_id,
- user_id=self.auth_user['id'],
- tenant_id=self.auth_user['tenant_id'],
- expires=self.expires,
- )
- self.admin_token = self.fixture_create_token(
- id=self.admin_token_id,
- user_id=self.admin_user['id'],
- tenant_id=self.admin_user['tenant_id'],
- expires=self.expires,
- )
-
- self.add_verify_status_helpers()
-
- def tearDown(self):
- self.clear_all_data()
- setattr(self, 'req', None)
- setattr(self, 'res', None)
-
- def clear_all_data(self):
- """
- Purges the database of all data
- """
- db.unregister_models()
- logger.debug("Cleared all data from database")
- reload(db)
- backends.configure_backends()
-
- def fixture_create_credentials(self, **kwargs):
- """
- Creates a tenant fixture.
-
- :params \*\*kwargs: Attributes of the tenant to create
- """
- values = kwargs.copy()
- user = db_api.USER.get_by_name(values['user_name'])
- if user:
- values['user_id'] = user.id
- credentials = db_api.CREDENTIALS.create(values)
- logger.debug("Created credentials fixture %s",
- credentials['user_id'])
- return credentials
-
- def fixture_create_tenant(self, **kwargs):
- """
- Creates a tenant fixture.
-
- :params \*\*kwargs: Attributes of the tenant to create
- """
- values = kwargs.copy()
- tenant = db_api.TENANT.create(values)
- logger.debug("Created tenant fixture %s", values['name'])
- return tenant
-
- def fixture_create_service(self, **kwargs):
- """
- Creates a service fixture.
-
- :params \*\*kwargs: Attributes of the service to create
- """
- values = kwargs.copy()
- service = db_api.SERVICE.create(values)
- logger.debug("Created service fixture %s", values['name'])
- return service
-
- def fixture_create_user(self, **kwargs):
- """
- Creates a user fixture. If the user's tenant ID is set, and the tenant
- does not exist in the database, the tenant is created.
-
- :params \*\*kwargs: Attributes of the user to create
- """
- values = kwargs.copy()
- roles = values.pop("roles", [])
- tenant_name = values.get('tenant_name')
- if tenant_name:
- if not db_api.TENANT.get_by_name(tenant_name):
- tenant = db_api.TENANT.create({'name': tenant_name,
- 'enabled': True,
- 'desc': tenant_name})
- values['tenant_id'] = tenant.id
- user = db_api.USER.create(values)
- logger.debug("Created user fixture %s", user.id)
- for role in roles:
- user_role = db_api.USER.user_role_add(
- {'user_id': user['id'], 'tenant_id': user['tenant_id'],
- 'role_id': role['id']})
- logger.debug("Created user-role association %s", user_role.id)
- return user
-
- def fixture_create_role(self, **kwargs):
- """
- Creates a role fixture.
-
- :params \*\*kwargs: Attributes of the role to create
- """
- values = kwargs.copy()
- role = db_api.ROLE.create(values)
- logger.debug("Created role fixture %s", role.id)
- return role
-
- def fixture_create_token(self, **kwargs):
- """
- Creates a token fixture.
-
- :params \*\*kwargs: Attributes of the token to create
- """
- values = kwargs.copy()
- token = db_api.TOKEN.create(values)
- logger.debug("Created token fixture %s", values['id'])
- return token
-
- def get_request(self, method, url, headers=None):
- """
- Sets the `req` attribute to a `webob.Request` object that
- is constructed with the supplied method and url. Supplied
- headers are added to appropriate Content-type headers.
- """
- headers = headers or {}
- self.req = webob.Request.blank(url)
- self.req.method = method
- self.req.headers = headers
- if 'content-type' not in headers:
- ct = 'application/%s' % self.content_type
- self.req.headers['content-type'] = ct
- self.req.headers['accept'] = ct
- return self.req
-
- def get_response(self):
- """
- Sets the appropriate headers for the `req` attribute for
- the current content type, then calls `req.get_response()` and
- sets the `res` attribute to the returned `webob.Response` object
- """
- self.res = self.req.get_response(self.api)
- logger.debug("%s %s returned %s", self.req.method, self.req.path_qs,
- self.res.status)
- if self.res.status_int != httplib.OK:
- logger.debug("Response Body:")
- for line in self.res.body.split("\n"):
- logger.debug(line)
- return self.res
-
- def verify_status(self, status_code):
- """
- Simple convenience wrapper for validating a response's status
- code.
- """
- if not getattr(self, 'res'):
- raise RuntimeError("Called verify_status() before calling "
- "get_response()!")
-
- self.assertEqual(status_code, self.res.status_int,
- "Incorrect status code %d. Expected %d" %
- (self.res.status_int, status_code))
-
- def add_verify_status_helpers(self):
- """
- Adds some convenience helpers using partials...
- """
- self.status_ok = functools.partial(self.verify_status,
- httplib.OK)
- self.status_not_found = functools.partial(self.verify_status,
- httplib.NOT_FOUND)
- self.status_unauthorized = functools.partial(self.verify_status,
- httplib.UNAUTHORIZED)
- self.status_bad_request = functools.partial(self.verify_status,
- httplib.BAD_REQUEST)
-
- def assert_dict_equal(self, expected, got):
- """
- Compares two dicts for equality and prints the dictionaries
- nicely formatted for easy comparison if there is a failure.
- """
- self.assertEqual(expected, got, "Mappings are not equal.\n"
- "Got:\n%s\nExpected:\n%s" %
- (pprint.pformat(got),
- pprint.pformat(expected)))
-
- def assert_xml_strings_equal(self, expected, got):
- """
- Compares two XML strings for equality by parsing them both
- into DOMs. Prints the DOMs nicely formatted for easy comparison
- if there is a failure.
- """
- # This is a nice little trick... objectify.fromstring() returns
- # a DOM different from etree.fromstring(). The objectify version
- # removes any different whitespacing...
- got = objectify.fromstring(got)
- expected = objectify.fromstring(expected)
- self.assertEqual(etree.tostring(expected),
- etree.tostring(got), "DOMs are not equal.\n"
- "Got:\n%s\nExpected:\n%s" %
- (etree.tostring(got, pretty_print=True),
- etree.tostring(expected, pretty_print=True)))
-
-
-class AdminAPITest(ServiceAPITest):
- """
- Base test case class for any unit test that tests the admin API. The
- """
- def __init__(self, *args, **kwargs):
- super(AdminAPITest, self).__init__(*args, **kwargs)
- # The `api` attribute for this base class is the
- # `server.KeystoneAdminAPI` controller.
- self.api_class = server.AdminApi
- # Set of dicts of tenant attributes we start each test case with
- self.tenant_fixtures = [
- {'id': 'tenant1',
- 'name': 'tenant1',
- 'enabled': True,
- 'desc': 'tenant1'},
- {'id': 'tenant2',
- 'name': 'tenant2',
- 'enabled': True,
- 'desc': 'tenant2'}]
-
- # Attributes of the user the test creates for each test case that
- # will authenticate against the API.
- self.auth_user_attrs = {'id': 'admin_user',
- 'password': 'admin_pass',
- 'email': 'admin_user@example.com',
- 'enabled': True,
- 'tenant_id': 'tenant2',
- 'roles': []}
diff --git a/keystone/test/unit/decorators.py b/keystone/test/unit/decorators.py
deleted file mode 100644
index 17a7d432..00000000
--- a/keystone/test/unit/decorators.py
+++ /dev/null
@@ -1,49 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2011 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.
-
-"""Decorators useful in unit tests"""
-
-import functools
-
-
-def content_type(func, content_type='json'):
- """
- Decorator for a test case method that sets the test case's
- content_type to 'json' or 'xml' and resets it afterwards to
- the original setting. This also asserts that if there is a
- value for the test object's `res` attribute, that the content-type
- header of the response is correct.
- """
- @functools.wraps(func)
- def wrapped(*a, **kwargs):
- test_obj = a[0]
- orig_content_type = test_obj.content_type
- try:
- test_obj.content_type = content_type
- func(*a, **kwargs)
- if getattr(test_obj, 'res'):
- expected = 'application/%s' % content_type
- got = test_obj.res.headers['content-type'].split(';')[0]
- test_obj.assertEqual(expected, got,
- "Bad content type: %s. Expected: %s" %
- (got, expected))
- finally:
- test_obj.content_type = orig_content_type
- return wrapped
-
-
-jsonify = functools.partial(content_type, content_type='json')
-xmlify = functools.partial(content_type, content_type='xml')
diff --git a/keystone/test/unit/test_auth.py b/keystone/test/unit/test_auth.py
deleted file mode 100644
index 458873e7..00000000
--- a/keystone/test/unit/test_auth.py
+++ /dev/null
@@ -1,187 +0,0 @@
-import json
-import unittest2 as unittest
-import keystone.logic.types.auth as auth
-import keystone.logic.types.fault as fault
-
-
-class TestAuth(unittest.TestCase):
- '''Unit tests for auth.py.'''
-
- pwd_xml = '<?xml version="1.0" encoding="UTF-8"?>\
- <auth xmlns="http://docs.openstack.org/identity/api/v2.0">\
- <passwordCredentials \
- xmlns="http://docs.openstack.org/identity/api/v2.0" \
- password="secret" username="disabled" \
- /></auth>'
-
- def test_pwd_cred_marshall(self):
- creds = auth.AuthWithPasswordCredentials.from_xml(self.pwd_xml)
- self.assertEqual(creds.password, "secret")
- self.assertEqual(creds.username, "disabled")
-
- def test_pwd_creds_from_json(self):
- data = json.dumps({"auth":
- {"passwordCredentials":
- {"username": "foo", "password": "bar"}}})
- creds = auth.AuthWithPasswordCredentials.from_json(data)
- self.assertEqual(creds.username, "foo")
- self.assertEqual(creds.password, "bar")
- self.assertIsNone(creds.tenant_id)
- self.assertIsNone(creds.tenant_name)
-
- def test_pwd_creds_with_tenant_name_from_json(self):
- data = json.dumps({"auth":
- {"tenantName": "blaa",
- "passwordCredentials":
- {"username": "foo", "password": "bar"}}})
- creds = auth.AuthWithPasswordCredentials.from_json(data)
- self.assertEqual(creds.username, "foo")
- self.assertEqual(creds.password, "bar")
- self.assertIsNone(creds.tenant_id)
- self.assertEqual(creds.tenant_name, "blaa")
-
- def test_pwd_creds_with_tenant_id_from_json(self):
- data = json.dumps({"auth":
- {"tenantId": "blaa",
- "passwordCredentials":
- {"username": "foo", "password": "bar"}}})
- creds = auth.AuthWithPasswordCredentials.from_json(data)
- self.assertEqual(creds.username, "foo")
- self.assertEqual(creds.password, "bar")
- self.assertEqual(creds.tenant_id, "blaa")
- self.assertIsNone(creds.tenant_name)
-
- def test_pwd_not_both_tenant_from_json(self):
- data = json.dumps({"auth": {"tenantId": "blaa", "tenantName": "aalb"}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "not both",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_invalid_from_json(self):
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Cannot parse",
- auth.AuthWithPasswordCredentials.from_json,
- "")
-
- def test_pwd_no_auth_from_json(self):
- data = json.dumps({"foo": "bar"})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting auth",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_no_creds_from_json(self):
- data = json.dumps({"auth": {}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_invalid_attribute_from_json(self):
- data = json.dumps({"auth": {"foo": "bar"}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Invalid",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_no_username_from_json(self):
- data = json.dumps({"auth": {"passwordCredentials": {}}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials:username",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_no_password_from_json(self):
- data = json.dumps({"auth": {"passwordCredentials":
- {"username": "foo"}}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials:password",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_invalid_creds_attribute_from_json(self):
- data = json.dumps({"auth": {"passwordCredentials": {"bar": "foo"}}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Invalid",
- auth.AuthWithPasswordCredentials.from_json,
- data)
-
- def test_token_creds_from_json(self):
- data = json.dumps({"auth": {"token": {"id": "1"}}})
- creds = auth.AuthWithUnscopedToken.from_json(data)
- self.assertEqual(creds.token_id, "1")
- self.assertIsNone(creds.tenant_id)
- self.assertIsNone(creds.tenant_name)
-
- def test_token_creds_with_tenant_name_from_json(self):
- data = json.dumps({"auth":
- {"tenantName": "blaa",
- "token": {"id": "1"}}})
- creds = auth.AuthWithUnscopedToken.from_json(data)
- self.assertEqual(creds.token_id, "1")
- self.assertIsNone(creds.tenant_id)
- self.assertEqual(creds.tenant_name, "blaa")
-
- def test_token_creds_with_tenant_id_from_json(self):
- data = json.dumps({"auth":
- {"tenantId": "blaa",
- "token": {"id": "1"}}})
- creds = auth.AuthWithUnscopedToken.from_json(data)
- self.assertEqual(creds.token_id, "1")
- self.assertEqual(creds.tenant_id, "blaa")
- self.assertIsNone(creds.tenant_name)
-
- def test_token_not_both_tenant_from_json(self):
- data = json.dumps({"auth":
- {"tenantId": "blaa",
- "tenantName": "aalb",
- "token": {"id": "1"}}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "not both",
- auth.AuthWithUnscopedToken.from_json,
- data)
-
- def test_token_invalid_from_json(self):
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Cannot parse",
- auth.AuthWithUnscopedToken.from_json,
- "")
-
- def test_token_no_auth_from_json(self):
- data = json.dumps({"foo": "bar"})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting auth",
- auth.AuthWithUnscopedToken.from_json,
- data)
-
- def test_token_no_creds_from_json(self):
- data = json.dumps({"auth": {}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting token",
- auth.AuthWithUnscopedToken.from_json,
- data)
-
- def test_token_invalid_attribute_from_json(self):
- data = json.dumps({"auth": {"foo": "bar"}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Invalid",
- auth.AuthWithUnscopedToken.from_json,
- data)
-
- def test_token_no_id_from_json(self):
- data = json.dumps({"auth": {"token": {}}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting token:id",
- auth.AuthWithUnscopedToken.from_json,
- data)
-
- def test_token_invalid_token_attribute_from_json(self):
- data = json.dumps({"auth": {"token": {"bar": "foo"}}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Invalid",
- auth.AuthWithUnscopedToken.from_json,
- data)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_authn_ec2.py b/keystone/test/unit/test_authn_ec2.py
deleted file mode 100644
index e8cdd995..00000000
--- a/keystone/test/unit/test_authn_ec2.py
+++ /dev/null
@@ -1,303 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2011 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 logging
-import unittest2 as unittest
-
-import base
-from keystone.test.unit.decorators import jsonify
-from keystone.logic import signer
-from keystone.logic.types import auth
-
-LOGGER = logging.getLogger(__name__)
-
-
-class EC2AuthnMethods(base.ServiceAPITest):
-
- @jsonify
- def test_valid_authn_ec2_success_json(self):
- """Tests correct syntax with {"auth":} wrapper and extension """
- url = "/tokens"
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": self.auth_user['tenant_id'],
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- req = self.get_request('POST', url)
- params = {
- "SignatureVersion": "2",
- "one_param": "5",
- "two_params": "happy",
- }
- credentials = {
- "access": access,
- "verb": "GET",
- "params": params,
- "host": "some.host.com:8773",
- "path": "services/Cloud",
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.Ec2Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds)
- body = {
- "auth": {
- "OS-KSEC2:ec2Credentials": credentials,
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'access': {
- u'token': {
- u'id': self.auth_token_id,
- u'expires': self.expires.strftime("%Y-%m-%dT%H:%M:%S.%f")},
- u'user': {
- u'id': unicode(self.auth_user['id']),
- u'name': self.auth_user['name'],
- u'roles': [{u'description': u'regular role',
- u'id': u'0',
- u'name': u'regular_role'}]}}}
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.status_ok()
-
- @jsonify
- def test_authn_ec2_success_json(self):
- """Tests syntax with {"auth":} wrapper """
- self._auth_to_url(url="/ec2tokens")
-
- @jsonify
- def test_authn_ec2_success_json_contract(self):
- """Tests syntax with {"auth":} wrapper """
- self._auth_to_url(url="/tokens")
-
- def _auth_to_url(self, url):
- """
- Test that plain ec2 credentials returns a 200 OK
- """
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": self.auth_user['tenant_id'],
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- req = self.get_request('POST', url)
- params = {
- "SignatureVersion": "2",
- "one_param": "5",
- "two_params": "happy",
- }
- credentials = {
- "access": access,
- "verb": "GET",
- "params": params,
- "host": "some.host.com:8773",
- "path": "services/Cloud",
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.Ec2Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds)
- body = {
- "auth": {
- "ec2Credentials": credentials,
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'access': {
- u'token': {
- u'id': self.auth_token_id,
- u'expires': self.expires.strftime("%Y-%m-%dT%H:%M:%S.%f")},
- u'user': {
- u'id': unicode(self.auth_user['id']),
- u'name': self.auth_user['name'],
- u'roles': [{u'description': u'regular role',
- u'id': u'0',
- u'name': u'regular_role'}]}}}
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.status_ok()
-
- @jsonify
- def test_old_authn_ec2_success_json(self):
- """Tests old syntax without {"auth":} wrapper """
- self._old_auth_to_url(url="/ec2tokens")
-
- @jsonify
- def test_old_authn_ec2_success_json_contract(self):
- """Tests old syntax without {"auth":} wrapper """
- self._old_auth_to_url(url="/tokens")
-
- def _old_auth_to_url(self, url):
- """
- Test that old ec2 credentials returns a 200 OK
- """
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": self.auth_user['tenant_id'],
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- req = self.get_request('POST', url)
- params = {
- "SignatureVersion": "2",
- "one_param": "5",
- "two_params": "happy",
- }
- credentials = {
- "access": access,
- "verb": "GET",
- "params": params,
- "host": "some.host.com:8773",
- "path": "services/Cloud",
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.Ec2Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds)
- body = {
- "ec2Credentials": credentials,
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'access': {
- u'token': {
- u'id': self.auth_token_id,
- u'expires': self.expires.strftime("%Y-%m-%dT%H:%M:%S.%f")},
- u'user': {
- u'id': unicode(self.auth_user['id']),
- u'name': self.auth_user['name'],
- u'roles': [{u'description': u'regular role',
- u'id': u'0',
- u'name': u'regular_role'}]}}}
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.status_ok()
-
- @jsonify
- def test_authn_ec2_success_json_bad_user(self):
- """
- Test that bad credentials returns a 401
- """
- access = "xpd285.access"
- secret = "345fgi.secret"
- url = "/ec2tokens"
- req = self.get_request('POST', url)
- params = {
- "SignatureVersion": "2",
- "one_param": "5",
- "two_params": "happy",
- }
- credentials = {
- "access": access,
- "verb": "GET",
- "params": params,
- "host": "some.host.com:8773",
- "path": "services/Cloud",
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.Ec2Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds)
- body = {
- "ec2Credentials": credentials,
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'unauthorized': {
- u'code': u'401',
- u'message': u'No credentials found for %s' % access,
- }
- }
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.assertEqual(self.res.status_int, 401)
-
- @jsonify
- def test_authn_ec2_success_json_bad_tenant(self):
- """
- Test that bad credentials returns a 401
- """
- # Create dummy tenant (or adding creds will fail)
- self.fixture_create_tenant(id='bad', name='bad')
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": 'bad',
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- # Delete the 'bad' tenant, orphaning the creds
- self.get_request('DELETE', '/tenants/bad')
-
- url = "/ec2tokens"
- req = self.get_request('POST', url)
- params = {
- "SignatureVersion": "2",
- "one_param": "5",
- "two_params": "happy",
- }
- credentials = {
- "access": access,
- "verb": "GET",
- "params": params,
- "host": "some.host.com:8773",
- "path": "services/Cloud",
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.Ec2Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds)
- body = {
- "ec2Credentials": credentials,
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'unauthorized': {
- u'code': u'401',
- u'message': u'Unauthorized on this tenant',
- }
- }
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.assertEqual(self.res.status_int, 401)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_authn_password.py b/keystone/test/unit/test_authn_password.py
deleted file mode 100644
index 947dfc60..00000000
--- a/keystone/test/unit/test_authn_password.py
+++ /dev/null
@@ -1,65 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2011 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 logging
-import unittest2 as unittest
-
-import base
-from keystone.test.unit.decorators import jsonify
-from keystone.logic.types import auth
-
-LOGGER = logging.getLogger(__name__)
-
-
-class PasswordAuthnMethods(base.ServiceAPITest):
-
- @jsonify
- def test_authn_password_success_json(self):
- """
- Test that good password credentials returns a 200 OK
- """
- url = "/tokens"
- req = self.get_request('POST', url)
- credentials = {
- "username": self.auth_user['name'],
- "password": "auth_pass",
- }
- body = {"auth": {
- "passwordCredentials": credentials,
- "tenantId": self.auth_user['tenant_id'],
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'access': {
- u'token': {
- u'id': self.auth_token_id,
- u'expires': self.expires.strftime("%Y-%m-%dT%H:%M:%S.%f")},
- u'user': {
- u'id': unicode(self.auth_user['id']),
- u'name': self.auth_user['name'],
- u'roles': [{u'description': u'regular role', u'id': u'0',
- u'name': u'regular_role'}]}}}
-
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.status_ok()
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_authn_s3.py b/keystone/test/unit/test_authn_s3.py
deleted file mode 100644
index 2cb3a358..00000000
--- a/keystone/test/unit/test_authn_s3.py
+++ /dev/null
@@ -1,245 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2011 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 logging
-import unittest2 as unittest
-
-import base
-from keystone.test.unit.decorators import jsonify
-from keystone.logic import signer
-from keystone.logic.types import auth
-
-LOGGER = logging.getLogger('test.unit.test_s3_authn')
-
-
-class S3AuthnMethods(base.ServiceAPITest):
-
- @jsonify
- def test_valid_authn_s3_success_json(self):
- """Tests correct syntax with {"auth":} wrapper and extension """
- url = "/tokens"
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": self.auth_user['tenant_id'],
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- req = self.get_request('POST', url)
- params = {
- "x-amz-acl": "public-read-write",
- "x-amz-server-side-encryption": "AES256",
- }
- credentials = {
- "access": access,
- "verb": "PUT",
- "path": "/test.txt",
- "expire": 0,
- "content_type": "text/plain",
- "content_md5": "1234567890abcdef",
- "xheaders": params,
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.S3Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds, s3=True)
- body = {
- "auth": {
- "OS-KSS3:s3Credentials": credentials,
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'access': {
- u'token': {
- u'id': self.auth_token_id,
- u'expires': self.expires.strftime("%Y-%m-%dT%H:%M:%S.%f")},
- u'user': {
- u'id': unicode(self.auth_user['id']),
- u'name': self.auth_user['name'],
- u'roles': [{u'description': u'regular role',
- u'id': u'0',
- u'name': u'regular_role'}]}}}
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.status_ok()
-
- @jsonify
- def test_authn_s3_success_json(self):
- """Tests correct syntax with {"auth":} wrapper """
- self._auth_to_url(url="/tokens")
-
- def _auth_to_url(self, url):
- """
- Test that good s3 credentials returns a 200 OK
- """
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": self.auth_user['tenant_id'],
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- req = self.get_request('POST', url)
- params = {
- "x-amz-acl": "public-read-write",
- "x-amz-server-side-encryption": "AES256",
- }
- credentials = {
- "access": access,
- "verb": "PUT",
- "path": "/test.txt",
- "expire": 0,
- "content_type": "text/plain",
- "content_md5": "1234567890abcdef",
- "xheaders": params,
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.S3Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds, s3=True)
- body = {
- "auth": {
- "OS-KSS3:s3Credentials": credentials,
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'access': {
- u'token': {
- u'id': self.auth_token_id,
- u'expires': self.expires.strftime("%Y-%m-%dT%H:%M:%S.%f")},
- u'user': {
- u'id': unicode(self.auth_user['id']),
- u'name': self.auth_user['name'],
- u'roles': [{u'description': u'regular role',
- u'id': u'0',
- u'name': u'regular_role'}]}}}
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.status_ok()
-
- @jsonify
- def test_authn_s3_success_json_bad_user(self):
- """
- Test that bad credentials returns a 401
- """
- access = "xpd285.access"
- secret = "345fgi.secret"
- url = "/tokens"
- req = self.get_request('POST', url)
- params = {
- "x-amz-acl": "public-read-write",
- "x-amz-server-side-encryption": "AES256",
- }
- credentials = {
- "access": access,
- "verb": "PUT",
- "path": "/test.txt",
- "expire": 0,
- "content_type": "text/plain",
- "content_md5": "1234567890abcdef",
- "xheaders": params,
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.S3Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds, s3=True)
- body = {
- "auth": {
- "OS-KSS3:s3Credentials": credentials,
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'unauthorized': {
- u'code': u'401',
- u'message': u'No credentials found for %s' % access,
- }
- }
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.assertEqual(self.res.status_int, 401)
-
- @jsonify
- def test_authn_s3_success_json_bad_tenant(self):
- """
- Test that bad credentials returns a 401
- """
- # Create dummy tenant (or adding creds will fail)
- self.fixture_create_tenant(id='bad', name='bad')
- access = "xpd285.access"
- secret = "345fgi.secret"
- kwargs = {
- "user_name": self.auth_user['name'],
- "tenant_id": 'bad',
- "type": "EC2",
- "key": access,
- "secret": secret,
- }
- self.fixture_create_credentials(**kwargs)
- # Delete the 'bad' tenant, orphaning the creds
- self.get_request('DELETE', '/tenants/bad')
-
- url = "/tokens"
- req = self.get_request('POST', url)
- params = {
- "x-amz-acl": "public-read-write",
- "x-amz-server-side-encryption": "AES256",
- }
- credentials = {
- "access": access,
- "verb": "PUT",
- "path": "/test.txt",
- "expire": 0,
- "content_type": "text/plain",
- "content_md5": "1234567890abcdef",
- "xheaders": params,
- "signature": None,
- }
- sign = signer.Signer(secret)
- obj_creds = auth.S3Credentials(**credentials)
- credentials['signature'] = sign.generate(obj_creds, s3=True)
- body = {
- "auth": {
- "OS-KSS3:s3Credentials": credentials,
- }
- }
- req.body = json.dumps(body)
- self.get_response()
-
- expected = {
- u'unauthorized': {
- u'code': u'401',
- u'message': u'Unauthorized on this tenant',
- }
- }
- self.assert_dict_equal(expected, json.loads(self.res.body))
- self.assertEqual(self.res.status_int, 401)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_backends.py b/keystone/test/unit/test_backends.py
deleted file mode 100644
index c1b9de14..00000000
--- a/keystone/test/unit/test_backends.py
+++ /dev/null
@@ -1,199 +0,0 @@
-# Copyright (c) 2011 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 os
-import unittest2 as unittest
-import uuid
-
-from keystone import backends
-from keystone import config
-from keystone.cfg import OptGroup, NoSuchOptError
-import keystone.backends.api as api
-import keystone.backends.models as legacy_backend_models
-import keystone.backends.sqlalchemy as db
-from keystone import models
-from keystone.test import KeystoneTest
-from keystone import utils
-
-CONF = config.CONF
-
-
-class BackendTestCase(unittest.TestCase):
- """
- Base class to run tests for Keystone backends (and backend configs)
- """
- def __init__(self, *args, **kwargs):
- super(BackendTestCase, self).__init__(*args, **kwargs)
- self.base_template = "sql.conf.template"
- self.ldap_template = "ldap.conf.template"
- self.current_template = self.base_template
-
- def setUp(self):
- self.update_CONF(self.current_template)
- db.unregister_models()
- reload(db)
- backends.configure_backends()
- super(BackendTestCase, self).setUp()
-
- def tearDown(self):
- self.current_template = self.base_template
-
- def update_CONF(self, template):
- """
- Resets the CONF file, and reads in the passed configuration text.
- """
- kt = KeystoneTest()
- kt.config_name = template
- kt.construct_temp_conf_file()
- fname = kt.conf_fp.name
- # Provide a hook for customizing the config if needed.
- self.modify_conf(fname)
- # Create the configuration
- CONF.reset()
- CONF(config_files=[fname])
-
- def modify_conf(self, fname):
- pass
-
- def tearDown(self):
- db.unregister_models()
- reload(db)
-
- def test_registration(self):
- self.assertIsNotNone(backends.api.CREDENTIALS)
- self.assertIsNotNone(backends.api.ENDPOINT_TEMPLATE)
- self.assertIsNotNone(backends.api.ROLE)
- self.assertIsNotNone(backends.api.SERVICE)
- self.assertIsNotNone(backends.api.TENANT)
- self.assertIsNotNone(backends.api.TOKEN)
- self.assertIsNotNone(backends.api.USER)
-
- def test_basic_tenant_create(self):
- tenant = models.Tenant(name="Tee One", description="This is T1",
- enabled=True)
-
- original_tenant = tenant.copy()
- new_tenant = api.TENANT.create(tenant)
- self.assertIsInstance(new_tenant, models.Tenant)
- for k, v in original_tenant.items():
- if k not in ['id'] and k in new_tenant:
- self.assertEquals(new_tenant[k], v)
-
- def test_tenant_create_with_id(self):
- tenant = models.Tenant(id="T2%s" % uuid.uuid4().hex, name="Tee Two",
- description="This is T2", enabled=True)
-
- original_tenant = tenant.to_dict()
- new_tenant = api.TENANT.create(tenant)
- self.assertIsInstance(new_tenant, models.Tenant)
- for k, v in original_tenant.items():
- if k in new_tenant:
- self.assertEquals(new_tenant[k], v,
- "'%s' did not match" % k)
- self.assertEqual(original_tenant['tenant'], tenant,
- "Backend modified provided tenant")
-
- def test_tenant_update(self):
- id = "T3%s" % uuid.uuid4().hex
- tenant = models.Tenant(id=id, name="Tee Three",
- description="This is T3", enabled=True)
- new_tenant = api.TENANT.create(tenant)
- new_tenant.enabled = False
- new_tenant.description = "This is UPDATED T3"
- api.TENANT.update(id, new_tenant)
- updated_tenant = api.TENANT.get(id)
- self.assertEqual(new_tenant, updated_tenant)
-
- def test_endpointtemplate_create(self):
- service = models.Service(name="glance", type="image-service")
- service = api.SERVICE.create(service)
-
- global_ept = models.EndpointTemplate(
- region="north",
- name="global",
- type=service.type,
- is_global=True,
- public_URL="http://global.public")
- global_ept = api.ENDPOINT_TEMPLATE.create(global_ept)
- self.assertIsNotNone(global_ept.id)
-
- ept = models.EndpointTemplate(
- region="north",
- name="floating",
- type=service.type,
- is_global=False,
- public_URL="http://floating.public/%tenant_id%/")
- ept = api.ENDPOINT_TEMPLATE.create(ept)
- self.assertIsNotNone(ept.id)
-
- def test_endpoint_list(self):
- self.test_endpointtemplate_create()
- self.test_basic_tenant_create()
- tenant = api.TENANT.get_by_name("Tee One")
-
- templates = api.ENDPOINT_TEMPLATE.get_all()
- for template in templates:
- if not template.is_global:
- endpoint = legacy_backend_models.Endpoints()
- endpoint.tenant_id = tenant.id
- endpoint.endpoint_template_id = template.id
- api.ENDPOINT_TEMPLATE.endpoint_add(endpoint)
-
- global_endpoints = api.TENANT.get_all_endpoints(None)
- self.assertGreater(len(global_endpoints), 0)
-
- tenant_endpoints = api.TENANT.get_all_endpoints(tenant.id)
- self.assertGreater(len(tenant_endpoints), 0)
-
-
-class LDAPBackendTestCase(BackendTestCase):
- def setUp(self):
- self.current_template = self.ldap_template
- super(LDAPBackendTestCase, self).setUp()
-
-
-class SQLiteBackendTestCase(BackendTestCase):
- """ Tests SQLite backend using actual file (not in memory)
-
- Since we have a code path that is specific to in-memory databases, we need
- to test for when we have a real file behind the ORM
- """
- def setUp(self):
- self.current_template = self.base_template
- self.database_name = os.path.abspath("%s.test.db" % \
- uuid.uuid4().hex)
- super(SQLiteBackendTestCase, self).setUp()
-
- def modify_conf(self, fname):
- # Need to override the connection
- conn = "sqlite:///%s" % self.database_name
- out = []
- with file(fname, "r") as conf_file:
- for ln in conf_file:
- if ln.rstrip() == "sql_connection = sqlite://":
- out.append("sql_connection = %s" % conn)
- else:
- out.append(ln.rstrip())
- with file(fname, "w") as conf_file:
- conf_file.write("\n".join(out))
-
- def tearDown(self):
- super(SQLiteBackendTestCase, self).tearDown()
- if os.path.exists(self.database_name):
- os.unlink(self.database_name)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_buffout.py b/keystone/test/unit/test_buffout.py
deleted file mode 100644
index 715960e0..00000000
--- a/keystone/test/unit/test_buffout.py
+++ /dev/null
@@ -1,91 +0,0 @@
-import unittest2 as unittest
-import sys
-
-from keystone.tools import buffout
-
-
-class TestStdoutIdentity(unittest.TestCase):
- """Tests buffout's manipulation of the stdout pointer"""
- def test_stdout(self):
- stdout = sys.stdout
- ob = buffout.OutputBuffer()
- self.assertTrue(sys.stdout is stdout,
- "sys.stdout was replaced")
- ob.start()
- self.assertTrue(sys.stdout is not stdout,
- "sys.stdout not replaced")
- ob.stop()
- self.assertTrue(sys.stdout is stdout,
- "sys.stdout not restored")
-
-
-class TestOutputBufferContents(unittest.TestCase):
- """Tests the contents of the buffer"""
- def test_read_contents(self):
- with buffout.OutputBuffer() as ob:
- print 'foobar'
- print 'wompwomp'
- output = ob.read()
- self.assertEquals(len(output), 16, output)
- self.assertIn('foobar', output)
- self.assertIn('ompwom', output)
-
- def test_read_lines(self):
- with buffout.OutputBuffer() as ob:
- print 'foobar'
- print 'wompwomp'
- lines = ob.read_lines()
- self.assertTrue(isinstance(lines, list))
- self.assertEqual(len(lines), 2)
- self.assertIn('foobar', lines)
- self.assertIn('wompwomp', lines)
-
- def test_additional_output(self):
- with buffout.OutputBuffer() as ob:
- print 'foobar'
- lines = ob.read_lines()
- self.assertEqual(len(lines), 1)
- print 'wompwomp'
- lines = ob.read_lines()
- self.assertEqual(len(lines), 2)
-
- def test_clear(self):
- with buffout.OutputBuffer() as ob:
- print 'foobar'
- ob.clear()
- print 'wompwomp'
- output = ob.read()
- self.assertNotIn('foobar', output)
- self.assertIn('ompwom', output)
-
- def test_buffer_preservation(self):
- ob = buffout.OutputBuffer()
- ob.start()
-
- print 'foobar'
- print 'wompwomp'
-
- ob.stop()
-
- output = ob.read()
- self.assertIn('foobar', output)
- self.assertIn('ompwom', output)
-
- def test_buffer_contents(self):
- ob = buffout.OutputBuffer()
- ob.start()
-
- print 'foobar'
- print 'wompwomp'
-
- ob.stop()
-
- self.assertEqual('foobar\nwompwomp\n', unicode(ob))
- self.assertEqual('foobar\nwompwomp\n', str(ob))
-
- def test_exception_raising(self):
- def raise_value_error():
- with buffout.OutputBuffer():
- raise ValueError()
-
- self.assertRaises(ValueError, raise_value_error)
diff --git a/keystone/test/unit/test_cfg.py b/keystone/test/unit/test_cfg.py
deleted file mode 100644
index 9dc07727..00000000
--- a/keystone/test/unit/test_cfg.py
+++ /dev/null
@@ -1,826 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2011 Red Hat, Inc.
-#
-# 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 os
-import sys
-import StringIO
-import tempfile
-import unittest
-
-import stubout
-
-from keystone.cfg import *
-
-
-class BaseTestCase(unittest.TestCase):
-
- def setUp(self):
- self.conf = ConfigOpts(prog='test',
- version='1.0',
- usage='%prog FOO BAR',
- default_config_files=[])
- self.tempfiles = []
- self.stubs = stubout.StubOutForTesting()
-
- def tearDown(self):
- self.remove_tempfiles()
- self.stubs.UnsetAll()
-
- def create_tempfiles(self, files):
- for (basename, contents) in files:
- (fd, path) = tempfile.mkstemp(prefix=basename)
- self.tempfiles.append(path)
- try:
- os.write(fd, contents)
- finally:
- os.close(fd)
- return self.tempfiles[-len(files):]
-
- def remove_tempfiles(self):
- for p in self.tempfiles:
- os.remove(p)
-
-
-class LeftoversTestCase(BaseTestCase):
-
- def test_leftovers(self):
- self.conf.register_cli_opt(StrOpt('foo'))
- self.conf.register_cli_opt(StrOpt('bar'))
-
- leftovers = self.conf(['those', '--foo', 'this',
- 'thems', '--bar', 'that', 'these'])
-
- self.assertEquals(leftovers, ['those', 'thems', 'these'])
-
-
-class FindConfigFilesTestCase(BaseTestCase):
-
- def test_find_config_files(self):
- config_files = \
- [os.path.expanduser('~/.blaa/blaa.conf'), '/etc/foo.conf']
-
- self.stubs.Set(os.path, 'exists', lambda p: p in config_files)
-
- self.assertEquals(find_config_files(project='blaa', prog='foo'),
- config_files)
-
-
-class CliOptsTestCase(BaseTestCase):
-
- def _do_cli_test(self, opt_class, default, cli_args, value):
- self.conf.register_cli_opt(opt_class('foo', default=default))
-
- self.conf(cli_args)
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, value)
-
- def test_str_default(self):
- self._do_cli_test(StrOpt, None, [], None)
-
- def test_str_arg(self):
- self._do_cli_test(StrOpt, None, ['--foo', 'bar'], 'bar')
-
- def test_bool_default(self):
- self._do_cli_test(BoolOpt, False, [], False)
-
- def test_bool_arg(self):
- self._do_cli_test(BoolOpt, None, ['--foo'], True)
-
- def test_bool_arg_inverse(self):
- self._do_cli_test(BoolOpt, None, ['--foo', '--nofoo'], False)
-
- def test_int_default(self):
- self._do_cli_test(IntOpt, 10, [], 10)
-
- def test_int_arg(self):
- self._do_cli_test(IntOpt, None, ['--foo=20'], 20)
-
- def test_float_default(self):
- self._do_cli_test(FloatOpt, 1.0, [], 1.0)
-
- def test_float_arg(self):
- self._do_cli_test(FloatOpt, None, ['--foo', '2.0'], 2.0)
-
- def test_list_default(self):
- self._do_cli_test(ListOpt, ['bar'], [], ['bar'])
-
- def test_list_arg(self):
- self._do_cli_test(ListOpt, None,
- ['--foo', 'blaa,bar'], ['blaa', 'bar'])
-
- def test_multistr_default(self):
- self._do_cli_test(MultiStrOpt, ['bar'], [], ['bar'])
-
- def test_multistr_arg(self):
- self._do_cli_test(MultiStrOpt, None,
- ['--foo', 'blaa', '--foo', 'bar'], ['blaa', 'bar'])
-
- def test_help(self):
- self.stubs.Set(sys, 'stdout', StringIO.StringIO())
- self.assertRaises(SystemExit, self.conf, ['--help'])
- self.assertTrue('FOO BAR' in sys.stdout.getvalue())
- self.assertTrue('--version' in sys.stdout.getvalue())
- self.assertTrue('--help' in sys.stdout.getvalue())
- self.assertTrue('--config-file=PATH' in sys.stdout.getvalue())
-
- def test_version(self):
- self.stubs.Set(sys, 'stdout', StringIO.StringIO())
- self.assertRaises(SystemExit, self.conf, ['--version'])
- self.assertTrue('1.0' in sys.stdout.getvalue())
-
- def test_config_file(self):
- paths = self.create_tempfiles([('1.conf', '[DEFAULT]'),
- ('2.conf', '[DEFAULT]')])
-
- self.conf(['--config-file', paths[0], '--config-file', paths[1]])
-
- self.assertEquals(self.conf.config_file, paths)
-
-
-class ConfigFileOptsTestCase(BaseTestCase):
-
- def test_str_default(self):
- self.conf.register_opt(StrOpt('foo', default='bar'))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 'bar')
-
- def test_str_value(self):
- self.conf.register_opt(StrOpt('foo'))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = bar\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 'bar')
-
- def test_str_value_file_override(self):
- self.conf.register_cli_opt(StrOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = baar\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = baaar\n')])
-
- self.conf(['--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 'baaar')
-
- def test_str_value_arg_override(self):
- self.conf.register_cli_opt(StrOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = baar\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = baaar\n')])
-
- self.conf(['--foo', 'bar',
- '--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 'bar')
-
- def test_int_default(self):
- self.conf.register_opt(IntOpt('foo', default=666))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 666)
-
- def test_int_value(self):
- self.conf.register_opt(IntOpt('foo'))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = 666\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 666)
-
- def test_int_value_file_override(self):
- self.conf.register_cli_opt(IntOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = 66\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = 666\n')])
-
- self.conf(['--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 666)
-
- def test_int_value_arg_override(self):
- self.conf.register_cli_opt(IntOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = 66\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = 666\n')])
-
- self.conf(['--foo', '6',
- '--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 6)
-
- def test_float_default(self):
- self.conf.register_opt(FloatOpt('foo', default=6.66))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 6.66)
-
- def test_float_value(self):
- self.conf.register_opt(FloatOpt('foo'))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = 6.66\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 6.66)
-
- def test_float_value_arg_override(self):
- self.conf.register_cli_opt(FloatOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = 6.6\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = 6.66\n')])
-
- self.conf(['--foo', '6',
- '--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 6.0)
-
- def test_float_value_file_override(self):
- self.conf.register_cli_opt(FloatOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = 6.6\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = 6.66\n')])
-
- self.conf(['--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, 6.66)
-
- def test_list_default(self):
- self.conf.register_opt(ListOpt('foo', default=['bar']))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, ['bar'])
-
- def test_list_value(self):
- self.conf.register_opt(ListOpt('foo'))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = bar\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, ['bar'])
-
- def test_list_value_override(self):
- self.conf.register_cli_opt(ListOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = bar,bar\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = b,a,r\n')])
-
- self.conf(['--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, ['b', 'a', 'r'])
-
- def test_multistr_default(self):
- self.conf.register_opt(MultiStrOpt('foo', default=['bar']))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, ['bar'])
-
- def test_multistr_value(self):
- self.conf.register_opt(MultiStrOpt('foo'))
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = bar\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, ['bar'])
-
- def test_multistr_values_append(self):
- self.conf.register_cli_opt(ListOpt('foo'))
-
- paths = self.create_tempfiles([('1.conf',
- '[DEFAULT]\n'
- 'foo = bar\n'),
- ('2.conf',
- '[DEFAULT]\n'
- 'foo = bar\n')])
-
- self.conf(['--foo', 'bar',
- '--config-file', paths[0],
- '--config-file', paths[1]])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
-
- # FIXME(markmc): values spread across the CLI and multiple
- # config files should be appended
- # self.assertEquals(self.conf.foo, ['bar', 'bar', 'bar'])
-
-
-class OptGroupsTestCase(BaseTestCase):
-
- def test_arg_group(self):
- blaa_group = OptGroup('blaa')
- self.conf.register_group(blaa_group)
- self.conf.register_cli_opt(StrOpt('foo'), group=blaa_group)
-
- self.conf(['--blaa-foo', 'bar'])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'bar')
-
- def test_arg_group_by_name(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_cli_opt(StrOpt('foo'), group='blaa')
-
- self.conf(['--blaa-foo', 'bar'])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'bar')
-
- def test_arg_group_with_default(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_cli_opt(StrOpt('foo', default='bar'), group='blaa')
-
- self.conf([])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'bar')
-
- def test_arg_group_in_config_file(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_opt(StrOpt('foo'), group='blaa')
-
- paths = self.create_tempfiles([('test.conf',
- '[blaa]\n'
- 'foo = bar\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'bar')
-
-
-class TemplateSubstitutionTestCase(BaseTestCase):
-
- def _prep_test_str_sub(self, foo_default=None, bar_default=None):
- self.conf.register_cli_opt(StrOpt('foo', default=foo_default))
- self.conf.register_cli_opt(StrOpt('bar', default=bar_default))
-
- def _assert_str_sub(self):
- self.assertTrue(hasattr(self.conf, 'bar'))
- self.assertEquals(self.conf.bar, 'blaa')
-
- def test_str_sub_default_from_default(self):
- self._prep_test_str_sub(foo_default='blaa', bar_default='$foo')
-
- self.conf([])
-
- self._assert_str_sub()
-
- def test_str_sub_default_from_arg(self):
- self._prep_test_str_sub(bar_default='$foo')
-
- self.conf(['--foo', 'blaa'])
-
- self._assert_str_sub()
-
- def test_str_sub_default_from_config_file(self):
- self._prep_test_str_sub(bar_default='$foo')
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = blaa\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self._assert_str_sub()
-
- def test_str_sub_arg_from_default(self):
- self._prep_test_str_sub(foo_default='blaa')
-
- self.conf(['--bar', '$foo'])
-
- self._assert_str_sub()
-
- def test_str_sub_arg_from_arg(self):
- self._prep_test_str_sub()
-
- self.conf(['--foo', 'blaa', '--bar', '$foo'])
-
- self._assert_str_sub()
-
- def test_str_sub_arg_from_config_file(self):
- self._prep_test_str_sub()
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'foo = blaa\n')])
-
- self.conf(['--config-file', paths[0], '--bar=$foo'])
-
- self._assert_str_sub()
-
- def test_str_sub_config_file_from_default(self):
- self._prep_test_str_sub(foo_default='blaa')
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'bar = $foo\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self._assert_str_sub()
-
- def test_str_sub_config_file_from_arg(self):
- self._prep_test_str_sub()
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'bar = $foo\n')])
-
- self.conf(['--config-file', paths[0], '--foo=blaa'])
-
- self._assert_str_sub()
-
- def test_str_sub_config_file_from_config_file(self):
- self._prep_test_str_sub()
-
- paths = self.create_tempfiles([('test.conf',
- '[DEFAULT]\n'
- 'bar = $foo\n'
- 'foo = blaa\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self._assert_str_sub()
-
- def test_str_sub_group_from_default(self):
- self.conf.register_cli_opt(StrOpt('foo', default='blaa'))
- self.conf.register_group(OptGroup('ba'))
- self.conf.register_cli_opt(StrOpt('r', default='$foo'), group='ba')
-
- self.conf([])
-
- self.assertTrue(hasattr(self.conf, 'ba'))
- self.assertTrue(hasattr(self.conf.ba, 'r'))
- self.assertEquals(self.conf.ba.r, 'blaa')
-
-
-class ReparseTestCase(BaseTestCase):
-
- def test_reparse(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_cli_opt(StrOpt('foo', default='r'), group='blaa')
-
- paths = self.create_tempfiles([('test.conf',
- '[blaa]\n'
- 'foo = b\n')])
-
- self.conf(['--config-file', paths[0]])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'b')
-
- self.conf(['--blaa-foo', 'a'])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'a')
-
- self.conf([])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertTrue(hasattr(self.conf.blaa, 'foo'))
- self.assertEquals(self.conf.blaa.foo, 'r')
-
-
-class OverridesTestCase(BaseTestCase):
-
- def test_no_default_override(self):
- self.conf.register_opt(StrOpt('foo'))
- self.conf([])
- self.assertEquals(self.conf.foo, None)
- self.conf.set_default('foo', 'bar')
- self.assertEquals(self.conf.foo, 'bar')
-
- def test_default_override(self):
- self.conf.register_opt(StrOpt('foo', default='foo'))
- self.conf([])
- self.assertEquals(self.conf.foo, 'foo')
- self.conf.set_default('foo', 'bar')
- self.assertEquals(self.conf.foo, 'bar')
- self.conf.set_default('foo', None)
- self.assertEquals(self.conf.foo, 'foo')
-
- def test_override(self):
- self.conf.register_opt(StrOpt('foo'))
- self.conf.set_override('foo', 'bar')
- self.conf([])
- self.assertEquals(self.conf.foo, 'bar')
-
- def test_group_no_default_override(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_opt(StrOpt('foo'), group='blaa')
- self.conf([])
- self.assertEquals(self.conf.blaa.foo, None)
- self.conf.set_default('foo', 'bar', group='blaa')
- self.assertEquals(self.conf.blaa.foo, 'bar')
-
- def test_default_override_II(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_opt(StrOpt('foo', default='foo'), group='blaa')
- self.conf([])
- self.assertEquals(self.conf.blaa.foo, 'foo')
- self.conf.set_default('foo', 'bar', group='blaa')
- self.assertEquals(self.conf.blaa.foo, 'bar')
- self.conf.set_default('foo', None, group='blaa')
- self.assertEquals(self.conf.blaa.foo, 'foo')
-
- def test_override_II(self):
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_opt(StrOpt('foo'), group='blaa')
- self.conf.set_override('foo', 'bar', group='blaa')
- self.conf([])
- self.assertEquals(self.conf.blaa.foo, 'bar')
-
-
-class SadPathTestCase(BaseTestCase):
-
- def test_unknown_attr(self):
- self.conf([])
- self.assertFalse(hasattr(self.conf, 'foo'))
- self.assertRaises(NoSuchOptError, getattr, self.conf, 'foo')
-
- def test_unknown_group_attr(self):
- self.conf.register_group(OptGroup('blaa'))
-
- self.conf([])
-
- self.assertTrue(hasattr(self.conf, 'blaa'))
- self.assertFalse(hasattr(self.conf.blaa, 'foo'))
- self.assertRaises(NoSuchOptError, getattr, self.conf.blaa, 'foo')
-
- def test_ok_duplicate(self):
- opt = StrOpt('foo')
- self.conf.register_cli_opt(opt)
- self.conf.register_cli_opt(opt)
-
- self.conf([])
-
- self.assertTrue(hasattr(self.conf, 'foo'))
- self.assertEquals(self.conf.foo, None)
-
- def test_error_duplicate(self):
- self.conf.register_cli_opt(StrOpt('foo'))
- self.assertRaises(DuplicateOptError,
- self.conf.register_cli_opt, StrOpt('foo'))
-
- def test_error_duplicate_with_different_dest(self):
- self.conf.register_cli_opt(StrOpt('foo', dest='f'))
- self.assertRaises(DuplicateOptError,
- self.conf.register_cli_opt, StrOpt('foo'))
-
- def test_error_duplicate_short(self):
- self.conf.register_cli_opt(StrOpt('foo', short='f'))
- self.assertRaises(DuplicateOptError,
- self.conf.register_cli_opt, StrOpt('bar', short='f'))
-
- def test_no_such_group(self):
- self.assertRaises(NoSuchGroupError, self.conf.register_cli_opt,
- StrOpt('foo'), group='blaa')
-
- def test_already_parsed(self):
- self.conf([])
-
- self.assertRaises(ArgsAlreadyParsedError,
- self.conf.register_cli_opt, StrOpt('foo'))
-
- def test_bad_cli_arg(self):
- self.stubs.Set(sys, 'stderr', StringIO.StringIO())
-
- self.assertRaises(SystemExit, self.conf, ['--foo'])
-
- self.assertTrue('error' in sys.stderr.getvalue())
- self.assertTrue('--foo' in sys.stderr.getvalue())
-
- def _do_test_bad_cli_value(self, opt_class):
- self.conf.register_cli_opt(opt_class('foo'))
-
- self.stubs.Set(sys, 'stderr', StringIO.StringIO())
-
- self.assertRaises(SystemExit, self.conf, ['--foo', 'bar'])
-
- self.assertTrue('foo' in sys.stderr.getvalue())
- self.assertTrue('bar' in sys.stderr.getvalue())
-
- def test_bad_int_arg(self):
- self._do_test_bad_cli_value(IntOpt)
-
- def test_bad_float_arg(self):
- self._do_test_bad_cli_value(FloatOpt)
-
- def test_conf_file_not_found(self):
- paths = self.create_tempfiles([('test.conf', 'foo')])
-
- self.assertRaises(ConfigFileParseError,
- self.conf, ['--config-file', paths[0]])
-
- def _do_test_conf_file_bad_value(self, opt_class):
- self.conf.register_opt(opt_class('foo'))
-
- def test_conf_file_bad_bool(self):
- self._do_test_conf_file_bad_value(BoolOpt)
-
- def test_conf_file_bad_int(self):
- self._do_test_conf_file_bad_value(IntOpt)
-
- def test_conf_file_bad_float(self):
- self._do_test_conf_file_bad_value(FloatOpt)
-
- def test_str_sub_from_group(self):
- self.conf.register_group(OptGroup('f'))
- self.conf.register_cli_opt(StrOpt('oo', default='blaa'), group='f')
- self.conf.register_cli_opt(StrOpt('bar', default='$f.oo'))
-
- self.conf([])
-
- self.assertFalse(hasattr(self.conf, 'bar'))
- self.assertRaises(TemplateSubstitutionError, getattr, self.conf, 'bar')
-
- def test_set_default_unknown_attr(self):
- self.conf([])
- self.assertRaises(NoSuchOptError, self.conf.set_default, 'foo', 'bar')
-
- def test_set_default_unknown_group(self):
- self.conf([])
- self.assertRaises(NoSuchGroupError,
- self.conf.set_default, 'foo', 'bar', group='blaa')
-
- def test_set_override_unknown_attr(self):
- self.conf([])
- self.assertRaises(NoSuchOptError, self.conf.set_override, 'foo', 'bar')
-
- def test_set_override_unknown_group(self):
- self.conf([])
- self.assertRaises(NoSuchGroupError,
- self.conf.set_override, 'foo', 'bar', group='blaa')
-
-
-class OptDumpingTestCase(BaseTestCase):
-
- class FakeLogger:
-
- def __init__(self, test_case, expected_lvl):
- self.test_case = test_case
- self.expected_lvl = expected_lvl
- self.logged = []
-
- def log(self, lvl, fmt, *args):
- self.test_case.assertEquals(lvl, self.expected_lvl)
- self.logged.append(fmt % args)
-
- def test_log_opt_values(self):
- self.conf.register_cli_opt(StrOpt('foo'))
- self.conf.register_group(OptGroup('blaa'))
- self.conf.register_cli_opt(StrOpt('bar'), 'blaa')
-
- self.conf(['--foo', 'this', '--blaa-bar', 'that'])
-
- logger = self.FakeLogger(self, 666)
-
- self.conf.log_opt_values(logger, 666)
-
- self.assertEquals(logger.logged, [
- "*" * 80,
- "Configuration options gathered from:",
- "command line args: ['--foo', 'this', '--blaa-bar', 'that']",
- "config files: []",
- "=" * 80,
- "config_file = []",
- "foo = this",
- "blaa.bar = that",
- "*" * 80,
- ])
-
-
-class CommonOptsTestCase(BaseTestCase):
-
- def setUp(self):
- super(CommonOptsTestCase, self).setUp()
- self.conf = CommonConfigOpts()
-
- def test_debug_verbose(self):
- self.conf(['--debug', '--verbose'])
-
- self.assertEquals(self.conf.debug, True)
- self.assertEquals(self.conf.verbose, True)
-
- def test_logging_opts(self):
- self.conf([])
-
- self.assertTrue(self.conf.log_config is None)
- self.assertTrue(self.conf.log_file is None)
- self.assertTrue(self.conf.log_dir is None)
-
- self.assertEquals(self.conf.log_format,
- CommonConfigOpts.DEFAULT_LOG_FORMAT)
- self.assertEquals(self.conf.log_date_format,
- CommonConfigOpts.DEFAULT_LOG_DATE_FORMAT)
-
- self.assertEquals(self.conf.use_syslog, False)
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_commands.py b/keystone/test/unit/test_commands.py
deleted file mode 100644
index cb8e86df..00000000
--- a/keystone/test/unit/test_commands.py
+++ /dev/null
@@ -1,1241 +0,0 @@
-import argparse
-import datetime
-import logging
-import unittest2 as unittest
-import uuid
-
-from keystone import backends
-import keystone.backends.sqlalchemy as db
-from keystone.manage2 import base
-from keystone.manage2 import common
-from keystone.manage2.commands import create_credential
-from keystone.manage2.commands import create_endpoint_template
-from keystone.manage2.commands import create_role
-from keystone.manage2.commands import create_service
-from keystone.manage2.commands import create_tenant
-from keystone.manage2.commands import create_token
-from keystone.manage2.commands import create_user
-from keystone.manage2.commands import delete_credential
-from keystone.manage2.commands import delete_endpoint_template
-from keystone.manage2.commands import delete_role
-from keystone.manage2.commands import delete_service
-from keystone.manage2.commands import delete_tenant
-from keystone.manage2.commands import delete_token
-from keystone.manage2.commands import delete_user
-from keystone.manage2.commands import grant_role
-from keystone.manage2.commands import list_credentials
-from keystone.manage2.commands import list_endpoint_templates
-from keystone.manage2.commands import list_endpoints
-from keystone.manage2.commands import list_role_grants
-from keystone.manage2.commands import list_roles
-from keystone.manage2.commands import list_services
-from keystone.manage2.commands import list_tenants
-from keystone.manage2.commands import list_tokens
-from keystone.manage2.commands import list_users
-from keystone.manage2.commands import map_endpoint
-from keystone.manage2.commands import revoke_role
-from keystone.manage2.commands import unmap_endpoint
-from keystone.manage2.commands import update_credential
-from keystone.manage2.commands import update_endpoint_template
-from keystone.manage2.commands import update_role
-from keystone.manage2.commands import update_service
-from keystone.manage2.commands import update_tenant
-from keystone.manage2.commands import update_token
-from keystone.manage2.commands import update_user
-from keystone.manage2.commands import version
-from keystone.tools import buffout
-from keystone import utils
-
-
-LOGGER = logging.getLogger(__name__)
-
-OPTIONS = {
- "keystone-service-admin-role": "KeystoneServiceAdmin",
- "keystone-admin-role": "KeystoneAdmin",
- "hash-password": "False",
- 'backends': 'keystone.backends.sqlalchemy',
- 'keystone.backends.sqlalchemy': {
- "sql_connection": "sqlite://",
- "backend_entities": "['UserRoleAssociation', "
- "'Endpoints', 'Role', 'Tenant', 'User', "
- "'Credentials', 'EndpointTemplates', 'Token', "
- "'Service']",
- "sql_idle_timeout": "30"}}
-# Configure the CONF module to match
-utils.set_configuration(OPTIONS)
-
-
-class CommandTestCase(unittest.TestCase):
- """Buffers stdout to test keystone-manage commands"""
-
- def run_cmd(self, module, args=None, use_managers=True):
- """Runs the Command in the given module using the provided args"""
- args = args if args is not None else []
-
- managers = self.managers if use_managers else None
-
- cmd = module.Command(managers=managers)
- parsed_args = cmd.parser.parse_args(args)
- return cmd.run(parsed_args)
-
- def setUp(self):
- self.managers = common.init_managers()
-
- # buffer stdout so we can assert what's printed
- self.ob = buffout.OutputBuffer()
- self.ob.start()
-
- def tearDown(self):
- self.ob.stop()
-
- self.clear_all_data()
-
- def clear_all_data(self):
- """
- Purges the database of all data
- """
- db.unregister_models()
- reload(db)
- backends.configure_backends()
-
- def assertTableContainsRow(self, table, row):
- """Assumes that row[0] is a unique identifier for the row"""
- # ensure we're comparing str to str
- row = [str(col) for col in row]
-
- # ensure the data we're looking for is *somewhere* in the table
- self.assertIn(row[0], table)
-
- # find the matching row
- matching_row = [r for r in table.split("\n") if row[0] in r][0]
- matching_row = [c for c in matching_row.split() if c.strip() != '|']
-
- self.assertEquals(row, matching_row)
-
- def _create_user(self):
- # TODO(dolph): these ob.clear()'s need to be cleaned up
- self.ob.clear()
- self.run_cmd(create_user, [
- '--name', uuid.uuid4().hex,
- '--password', uuid.uuid4().hex])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _create_tenant(self):
- self.ob.clear()
- self.run_cmd(create_tenant, [
- '--name', uuid.uuid4().hex])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _create_token(self, user_id):
- self.ob.clear()
- self.run_cmd(create_token, [
- '--user-id', user_id])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _create_credential(self, user_id):
- self.ob.clear()
- cred_type = uuid.uuid4().hex
- key = uuid.uuid4().hex
- secret = uuid.uuid4().hex
- self.run_cmd(create_credential, [
- '--user-id', user_id,
- '--type', cred_type,
- '--key', key,
- '--secret', secret])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _create_service(self):
- self.ob.clear()
- self.run_cmd(create_service, [
- '--name', uuid.uuid4().hex,
- '--type', uuid.uuid4().hex])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _create_role(self):
- self.ob.clear()
- self.run_cmd(create_role, [
- '--name', uuid.uuid4().hex])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _create_endpoint_template(self, service_id):
- self.ob.clear()
- self.run_cmd(create_endpoint_template, [
- '--region', uuid.uuid4().hex,
- '--service-id', service_id,
- '--public-url', 'http://%s' % (uuid.uuid4().hex),
- '--admin-url', 'http://%s' % (uuid.uuid4().hex),
- '--internal-url', 'http://%s' % (uuid.uuid4().hex)])
- obj_id = self.ob.read_lines()[0]
- self.ob.clear()
- return obj_id
-
- def _map_endpoint(self, endpoint_template_id, tenant_id):
- self.ob.clear()
- self.run_cmd(map_endpoint, [
- '--endpoint-template-id', endpoint_template_id,
- '--tenant-id', tenant_id])
- self.ob.clear()
-
-
-class TestCommon(unittest.TestCase):
- def test_enable_disable(self):
- """$ manage [command] --enable --disable"""
- args = argparse.Namespace(enable=True, disable=True)
- with self.assertRaises(SystemExit):
- cmd = base.BaseCommand()
- cmd.true_or_false(args, 'enable', 'disable')
-
- "Unable to apply both: --enable and --disable"
-
- def test_enable(self):
- """$ manage [command] --enable"""
- args = argparse.Namespace(enable=True, disable=False)
- cmd = base.BaseCommand()
- self.assertTrue(cmd.true_or_false(args, 'enable', 'disable'))
-
- def test_disable(self):
- """$ manage [command] --disable"""
- args = argparse.Namespace(enable=False, disable=True)
- cmd = base.BaseCommand()
- self.assertFalse(cmd.true_or_false(args, 'enable', 'disable'))
-
- def test_no_args(self):
- """$ manage [command]"""
- args = argparse.Namespace(enable=False, disable=False)
- cmd = base.BaseCommand()
- self.assertFalse(cmd.true_or_false(args, 'enable', 'disable'))
-
-
-class TestVersionCommand(CommandTestCase):
- """Tests for ./bin/keystone-manage version"""
- API_VERSION = '2.0 beta'
- IMPLEMENTATION_VERSION = '2012.1-dev'
- DATABASE_VERSION = 'not under version control'
-
- def test_api_version(self):
- v = version.Command.get_api_version()
- self.assertEqual(v, self.API_VERSION)
-
- def test_implementation_version(self):
- v = version.Command.get_implementation_version()
- self.assertEqual(v, self.IMPLEMENTATION_VERSION)
-
- def test_all_version_responses(self):
- self.run_cmd(version, [], use_managers=False)
- lines = self.ob.read_lines()
- self.assertEqual(len(lines), 3, lines)
- self.assertIn(self.API_VERSION, lines[0])
- self.assertIn(self.IMPLEMENTATION_VERSION, lines[1])
- self.assertIn(self.DATABASE_VERSION, lines[2])
-
- def test_api_version_arg(self):
- self.run_cmd(version, ['--api'], use_managers=False)
- lines = self.ob.read_lines()
- self.assertEqual(len(lines), 1, lines)
- self.assertIn(self.API_VERSION, lines[0])
-
- def test_implementation_version_arg(self):
- self.run_cmd(version, ['--implementation'], use_managers=False)
- lines = self.ob.read_lines()
- self.assertEqual(len(lines), 1, lines)
- self.assertIn(self.IMPLEMENTATION_VERSION, lines[0])
-
- def test_database_version_arg(self):
- self.run_cmd(version, ['--database'], use_managers=False)
- lines = self.ob.read_lines()
- self.assertEqual(len(lines), 1, lines)
- self.assertIn(self.DATABASE_VERSION, lines[0])
-
-
-class TestCreateUserCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(create_user)
-
- def test_create_user_min_fields(self):
- name = uuid.uuid4().hex
- password = uuid.uuid4().hex
- self.run_cmd(create_user, [
- '--name', name,
- '--password', password])
- user_id = self.ob.read_lines()[0]
- self.assertEqual(len(user_id), 32)
-
- self.ob.clear()
-
- self.run_cmd(list_users)
- output = self.ob.read()
- self.assertIn(user_id, output)
- self.assertIn(name, output)
- self.assertNotIn(password, output)
-
- def test_create_user_all_fields(self):
- user_id = uuid.uuid4().hex
- name = uuid.uuid4().hex
- password = uuid.uuid4().hex
- email = uuid.uuid4().hex
- self.run_cmd(create_user, [
- '--id', user_id,
- '--name', name,
- '--password', password,
- '--email', email,
- '--disable'])
- output = self.ob.read_lines()
- self.assertEquals(user_id, output[0])
-
- self.ob.clear()
-
- self.run_cmd(list_users)
- self.assertTableContainsRow(self.ob.read(), [user_id, name, email,
- str(None), str(False)])
-
-
-class TestListUsersCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_users)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals('ID', row[0])
- self.assertEquals('Name', row[1])
- self.assertEquals('Email', row[2])
- self.assertEquals('Default Tenant ID', row[3])
- self.assertEquals('Enabled', row[4])
-
-
-class TestUpdateUserCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(update_user)
-
- def test_invalid_id(self):
- with self.assertRaises(KeyError):
- self.run_cmd(update_user, [
- '--where-id', uuid.uuid4().hex])
-
- def test_create_update_list(self):
- user_id = uuid.uuid4().hex
- self.run_cmd(create_user, [
- '--id', user_id,
- '--name', uuid.uuid4().hex,
- '--password', uuid.uuid4().hex,
- '--email', uuid.uuid4().hex])
-
- name = uuid.uuid4().hex
- password = uuid.uuid4().hex
- email = uuid.uuid4().hex
- self.run_cmd(update_user, [
- '--where-id', user_id,
- '--name', name,
- '--password', password,
- '--email', email,
- '--disable'])
-
- self.ob.clear()
-
- self.run_cmd(list_users)
- output = self.ob.read()
- self.assertIn(user_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if user_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(user_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(email, row[2])
- self.assertEquals(str(None), row[3])
- self.assertEquals(str(False), row[4])
-
-
-class TestDeleteUserCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_user)
-
- def test_invalid_id(self):
- with self.assertRaises(KeyError):
- self.run_cmd(delete_user, [
- '--where-id', uuid.uuid4().hex])
-
- def test_create_delete_list(self):
- user_id = uuid.uuid4().hex
- self.run_cmd(create_user, [
- '--id', user_id,
- '--name', uuid.uuid4().hex,
- '--password', uuid.uuid4().hex,
- '--email', uuid.uuid4().hex])
-
- self.run_cmd(delete_user, [
- '--where-id', user_id])
-
- self.ob.clear()
-
- self.run_cmd(list_users)
- self.assertNotIn(user_id, self.ob.read())
-
-
-class TestCreateTenantCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(create_tenant)
-
- def test_create_enabled_tenant(self):
- name = uuid.uuid4().hex
- self.run_cmd(create_tenant, [
- '--name', name])
- tenant_id = self.ob.read_lines()[0]
- self.assertEqual(len(tenant_id), 32)
-
- self.ob.clear()
-
- self.run_cmd(list_tenants)
- output = self.ob.read()
- self.assertIn(tenant_id, output)
- self.assertIn(name, output)
-
- def test_create_disabled_tenant(self):
- name = uuid.uuid4().hex
- self.run_cmd(create_tenant, [
- '--name', name,
- '--disabled'])
- tenant_id = self.ob.read_lines()[0]
- self.assertEqual(len(tenant_id), 32)
-
- self.ob.clear()
-
- self.run_cmd(list_tenants)
- output = self.ob.read()
- self.assertIn(tenant_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if tenant_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(tenant_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(str(False), row[2])
-
-
-class TestListTenantsCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_tenants)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals('ID', row[0])
- self.assertEquals('Name', row[1])
- self.assertEquals('Enabled', row[2])
-
-
-class TestUpdateTenantCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(update_tenant)
-
- def test_invalid_id(self):
- with self.assertRaises(KeyError):
- self.run_cmd(update_tenant, [
- '--where-id', uuid.uuid4().hex])
-
- def test_create_update_list(self):
- tenant_id = uuid.uuid4().hex
- self.run_cmd(create_tenant, [
- '--id', tenant_id,
- '--name', uuid.uuid4().hex])
-
- name = uuid.uuid4().hex
- self.run_cmd(update_tenant, [
- '--where-id', tenant_id,
- '--name', name,
- '--disable'])
-
- self.ob.clear()
-
- self.run_cmd(list_tenants)
- output = self.ob.read()
- self.assertIn(tenant_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if tenant_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(tenant_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(str(False), row[2])
-
-
-class TestDeleteTenantCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_tenant)
-
- def test_invalid_id(self):
- with self.assertRaises(KeyError):
- self.run_cmd(delete_tenant, [
- '--where-id', uuid.uuid4().hex])
-
- def test_create_delete_list(self):
- tenant_id = uuid.uuid4().hex
- self.run_cmd(create_tenant, [
- '--id', tenant_id,
- '--name', uuid.uuid4().hex])
-
- self.run_cmd(delete_tenant, [
- '--where-id', tenant_id])
-
- self.ob.clear()
-
- self.run_cmd(list_tenants)
- self.assertNotIn(tenant_id, self.ob.read())
-
-
-class TestCreateRoleCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(create_role)
-
- def test_create_role(self):
- name = uuid.uuid4().hex
- self.run_cmd(create_role, [
- '--name', name])
- role_id = self.ob.read_lines()[0]
- self.assertTrue(int(role_id))
-
- self.ob.clear()
-
- self.run_cmd(list_roles)
- output = self.ob.read()
- self.assertIn(role_id, output)
- self.assertIn(name, output)
-
- def test_create_role_with_description(self):
- name = uuid.uuid4().hex
- description = uuid.uuid4().hex
- self.run_cmd(create_role, [
- '--name', name,
- '--description', description])
- role_id = self.ob.read_lines()[0]
- self.assertTrue(int(role_id))
-
- self.ob.clear()
-
- self.run_cmd(list_roles)
- output = self.ob.read()
- self.assertIn(role_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if role_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(role_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(str(None), row[2])
- self.assertEquals(description, row[3])
-
- def test_create_role_owned_by_service(self):
- self.run_cmd(create_service, [
- '--name', uuid.uuid4().hex,
- '--type', uuid.uuid4().hex])
- service_id = self.ob.read_lines()[0]
-
- name = uuid.uuid4().hex
- self.run_cmd(create_role, [
- '--name', name,
- '--service-id', service_id])
- role_id = self.ob.read_lines()[0]
-
- self.ob.clear()
-
- self.run_cmd(list_roles)
- output = self.ob.read()
- self.assertIn(role_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if role_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(role_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(service_id, row[2])
- self.assertEquals(str(None), row[3])
-
-
-class TestUpdateRoleCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(update_role)
-
- def test_update_role(self):
- old_name = uuid.uuid4().hex
- old_description = uuid.uuid4().hex
- old_service_id = self._create_service()
- self.run_cmd(create_role, [
- '--name', old_name,
- '--description', old_description,
- '--service-id', old_service_id])
- role_id = self.ob.read_lines()[0]
-
- # update the role
- name = uuid.uuid4().hex
- description = uuid.uuid4().hex
- service_id = self._create_service()
- self.run_cmd(update_role, [
- '--where-id', role_id,
- '--name', name,
- '--description', description,
- '--service-id', service_id])
-
- self.ob.clear()
-
- self.run_cmd(list_roles)
- self.assertTableContainsRow(self.ob.read(), [role_id, name,
- service_id, description])
-
-
-class TestListRolesCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_roles)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals('ID', row[0])
- self.assertEquals('Name', row[1])
- self.assertEquals('Service ID', row[2])
- self.assertEquals('Description', row[3])
-
-
-class TestDeleteRoleCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_role)
-
- def test_invalid_id(self):
- with self.assertRaises(KeyError):
- self.run_cmd(delete_role, [
- '--where-id', uuid.uuid4().hex])
-
- def test_delete_role(self):
- role_id = self._create_role()
-
- # delete it
- self.run_cmd(delete_role, [
- '--where-id', role_id])
-
- self.ob.clear()
-
- # ensure it's not returned
- self.run_cmd(list_roles)
- output = self.ob.read()
- self.assertNotIn(role_id, output)
-
-
-class TestListRoleGrants(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_role_grants)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals(['Role ID', 'User ID', 'Tenant ID', 'Global'], row)
-
-
-class TestGrantRoleCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(grant_role)
-
- def test_invalid_ids(self):
- with self.assertRaises(KeyError):
- self.run_cmd(grant_role, [
- '--user-id', uuid.uuid4().hex,
- '--role-id', uuid.uuid4().hex])
-
- def test_grant_global_role(self):
- user_id = self._create_user()
- role_id = self._create_role()
-
- self.run_cmd(grant_role, [
- '--user-id', user_id,
- '--role-id', role_id])
-
- # granting again should fail
- # TODO(dolph): this should be an IntegrityError
- with self.assertRaises(KeyError):
- self.run_cmd(grant_role, [
- '--user-id', user_id,
- '--role-id', role_id])
-
- self.ob.clear()
-
- self.run_cmd(list_role_grants, [
- '--where-user-id', user_id,
- '--where-role-id', role_id,
- '--where-global'])
- self.assertTableContainsRow(self.ob.read(), [role_id, user_id,
- str(None), str(True)])
-
- def test_grant_tenant_role(self):
- user_id = self._create_user()
- role_id = self._create_role()
- tenant_id = self._create_tenant()
-
- self.run_cmd(grant_role, [
- '--user-id', user_id,
- '--role-id', role_id,
- '--tenant-id', tenant_id])
-
- # granting again should fail
- # TODO(dolph): this should be an IntegrityError
- with self.assertRaises(KeyError):
- self.run_cmd(grant_role, [
- '--user-id', user_id,
- '--role-id', role_id,
- '--tenant-id', tenant_id])
-
- self.ob.clear()
-
- self.run_cmd(list_role_grants, [
- '--where-user-id', user_id,
- '--where-role-id', role_id,
- '--where-tenant-id', tenant_id])
- self.assertTableContainsRow(self.ob.read(), [role_id, user_id,
- tenant_id, str(False)])
-
-
-class TestRevokeRoleCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(revoke_role)
-
- def test_revoke_global_role(self):
- user_id = self._create_user()
- role_id = self._create_role()
-
- self.run_cmd(grant_role, [
- '--user-id', user_id,
- '--role-id', role_id])
-
- self.run_cmd(revoke_role, [
- '--user-id', user_id,
- '--role-id', role_id])
-
- self.ob.clear()
-
- self.run_cmd(list_role_grants, [
- '--where-user-id', user_id,
- '--where-role-id', role_id,
- '--where-global'])
- with self.assertRaises(AssertionError):
- self.assertTableContainsRow(self.ob.read(), [role_id, user_id,
- str(None), str(True)])
-
- def test_revoke_tenant_role(self):
- user_id = self._create_user()
- role_id = self._create_role()
- tenant_id = self._create_tenant()
-
- self.run_cmd(grant_role, [
- '--user-id', user_id,
- '--role-id', role_id,
- '--tenant-id', tenant_id])
-
- self.run_cmd(revoke_role, [
- '--user-id', user_id,
- '--role-id', role_id,
- '--tenant-id', tenant_id])
-
- self.ob.clear()
-
- self.run_cmd(list_role_grants, [
- '--where-user-id', user_id,
- '--where-role-id', role_id,
- '--where-tenant-id', tenant_id])
- with self.assertRaises(AssertionError):
- self.assertTableContainsRow(self.ob.read(), [role_id, user_id,
- tenant_id, str(False)])
-
-
-class TestCreateServiceCommand(CommandTestCase):
- def test_create_service(self):
- name = uuid.uuid4().hex
- service_type = uuid.uuid4().hex
- description = uuid.uuid4().hex
- owner_id = self._create_user()
- self.run_cmd(create_service, [
- '--name', name,
- '--type', service_type,
- '--description', description,
- '--owner-id', owner_id])
- service_id = self.ob.read_lines()[0]
- self.assertTrue(int(service_id))
-
- self.ob.clear()
-
- self.run_cmd(list_services)
- output = self.ob.read()
- self.assertIn(service_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if service_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(service_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(service_type, row[2])
- self.assertEquals(owner_id, row[3])
- self.assertEquals(description, row[4])
-
-
-class TestUpdateServiceCommand(CommandTestCase):
- def test_update_service(self):
- old_name = uuid.uuid4().hex
- old_type = uuid.uuid4().hex
- old_description = uuid.uuid4().hex
- old_owner_id = self._create_user()
- self.run_cmd(create_service, [
- '--name', old_name,
- '--type', old_type,
- '--description', old_description,
- '--owner-id', old_owner_id])
- service_id = self.ob.read_lines()[0]
-
- # update the service
- name = uuid.uuid4().hex
- service_type = uuid.uuid4().hex
- description = uuid.uuid4().hex
- owner_id = self._create_user()
- self.run_cmd(update_service, [
- '--where-id', service_id,
- '--name', name,
- '--type', service_type,
- '--description', description,
- '--owner-id', owner_id])
-
- self.ob.clear()
-
- self.run_cmd(list_services)
- output = self.ob.read()
- self.assertIn(service_id, output)
-
- lines = self.ob.read_lines()
- row = [row for row in lines if service_id in row][0]
- row = [col for col in row.split() if col.strip() != '|']
- self.assertEquals(service_id, row[0])
- self.assertEquals(name, row[1])
- self.assertEquals(service_type, row[2])
- self.assertEquals(owner_id, row[3])
- self.assertEquals(description, row[4])
-
-
-class TestListServicesCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_services)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals('ID', row[0])
- self.assertEquals('Name', row[1])
- self.assertEquals('Type', row[2])
- self.assertEquals('Owner ID', row[3])
- self.assertEquals('Description', row[4])
-
-
-class TestDeleteServiceCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_service)
-
- def test_invalid_id(self):
- with self.assertRaises(KeyError):
- self.run_cmd(delete_service, [
- '--where-id', uuid.uuid4().hex])
-
- def test_delete_service(self):
- service_id = self._create_service()
-
- self.run_cmd(delete_service, [
- '--where-id', service_id])
-
- self.ob.clear()
-
- self.run_cmd(list_services)
- output = self.ob.read()
- self.assertNotIn(service_id, output)
-
-
-class TestCreateTokenCommand(CommandTestCase):
- """Creates tokens and validates their attributes.
-
- This class has a known potential race condition, due to the expected
- token expiration being 24 hours after token creation. If the
- 'create_token' command runs immediately before the minute rolls over,
- and the test class produces a timestamp for the subsequent minute, the
- test will fail.
-
- """
-
- @staticmethod
- def _get_tomorrow_str():
- return (datetime.datetime.utcnow() +
- datetime.timedelta(days=1)).strftime('%Y-%m-%dT%H:%M')
-
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(create_token)
-
- def test_create_unscoped_token(self):
- user_id = self._create_user()
- self.run_cmd(create_token, [
- '--user-id', user_id])
- tomorrow = TestCreateTokenCommand._get_tomorrow_str()
- token_id = self.ob.read_lines()[0]
- self.assertEqual(len(token_id), 32)
-
- self.ob.clear()
-
- self.run_cmd(list_tokens)
- self.assertTableContainsRow(self.ob.read(), [token_id, user_id,
- str(None), tomorrow])
-
- def test_create_scoped_token(self):
- user_id = self._create_user()
- tenant_id = self._create_tenant()
- self.run_cmd(create_token, [
- '--user-id', user_id,
- '--tenant-id', tenant_id])
- tomorrow = TestCreateTokenCommand._get_tomorrow_str()
- token_id = self.ob.read_lines()[0]
- self.assertEqual(len(token_id), 32)
-
- self.ob.clear()
-
- self.run_cmd(list_tokens)
- self.assertTableContainsRow(self.ob.read(), [token_id, user_id,
- tenant_id, tomorrow])
-
- def test_create_expired_token(self):
- user_id = self._create_user()
- expiration = '1999-12-31T23:59'
- self.run_cmd(create_token, [
- '--user-id', user_id,
- '--expires', expiration])
- token_id = self.ob.read_lines()[0]
- self.assertEqual(len(token_id), 32)
-
- self.ob.clear()
-
- self.run_cmd(list_tokens)
- self.assertTableContainsRow(self.ob.read(), [token_id, user_id,
- str(None), expiration])
-
- def test_create_specific_token_id(self):
- token_id = uuid.uuid4().hex
- user_id = self._create_user()
- self.run_cmd(create_token, [
- '--id', token_id,
- '--user-id', user_id])
- tomorrow = TestCreateTokenCommand._get_tomorrow_str()
- self.assertEqual(token_id, self.ob.read_lines()[0])
-
- self.ob.clear()
-
- self.run_cmd(list_tokens)
- self.assertTableContainsRow(self.ob.read(), [token_id, user_id,
- str(None), tomorrow])
-
-
-class TestUpdateTokenCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(update_token)
-
- def test_update_token(self):
- token_id = self._create_token(self._create_user())
-
- user_id = self._create_user()
- tenant_id = self._create_tenant()
- expiration = '1999-12-31T23:59'
- self.run_cmd(update_token, [
- '--where-id', token_id,
- '--user-id', user_id,
- '--tenant-id', tenant_id,
- '--expires', expiration])
-
- self.ob.clear()
-
- self.run_cmd(list_tokens)
- self.assertTableContainsRow(self.ob.read(), [token_id, user_id,
- tenant_id, expiration])
-
-
-class TestListTokensCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_tokens)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals(['ID', 'User ID', 'Tenant ID', 'Expiration'],
- row)
-
-
-class TestDeleteTokenCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_token)
-
- def test_delete_token(self):
- token_id = self._create_token(self._create_user())
-
- self.run_cmd(delete_token, [
- '--where-id', token_id])
-
- self.ob.clear()
-
- # ensure it's not returned
- self.run_cmd(list_tokens)
- output = self.ob.read()
- self.assertNotIn(token_id, output)
-
-
-class TestCreateCredentialCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(create_credential)
-
- def test_create_credential(self):
- user_id = self._create_user()
- cred_type = uuid.uuid4().hex
- key = uuid.uuid4().hex
- secret = uuid.uuid4().hex
- self.run_cmd(create_credential, [
- '--user-id', user_id,
- '--type', cred_type,
- '--key', key,
- '--secret', secret])
- credential_id = self.ob.read_lines()[0]
- self.assertTrue(int(credential_id))
-
- self.ob.clear()
-
- self.run_cmd(list_credentials)
- self.assertTableContainsRow(self.ob.read(), [credential_id,
- user_id, str(None), cred_type, key, secret])
-
- def test_create_credential_with_tenant(self):
- user_id = self._create_user()
- tenant_id = self._create_tenant()
- cred_type = uuid.uuid4().hex
- key = uuid.uuid4().hex
- secret = uuid.uuid4().hex
- self.run_cmd(create_credential, [
- '--user-id', user_id,
- '--tenant-id', tenant_id,
- '--type', cred_type,
- '--key', key,
- '--secret', secret])
- credential_id = self.ob.read_lines()[0]
- self.assertTrue(int(credential_id))
-
- self.ob.clear()
-
- self.run_cmd(list_credentials)
- self.assertTableContainsRow(self.ob.read(), [credential_id,
- user_id, tenant_id, cred_type, key, secret])
-
-
-class TestUpdateCredentialCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(update_credential)
-
- def test_update_credential(self):
- credential_id = self._create_credential(self._create_user())
-
- user_id = self._create_user()
- tenant_id = self._create_tenant()
- cred_type = uuid.uuid4().hex
- key = uuid.uuid4().hex
- secret = uuid.uuid4().hex
- self.run_cmd(update_credential, [
- '--where-id', credential_id,
- '--user-id', user_id,
- '--tenant-id', tenant_id,
- '--type', cred_type,
- '--key', key,
- '--secret', secret])
-
- self.ob.clear()
-
- self.run_cmd(list_credentials)
- self.assertTableContainsRow(self.ob.read(), [credential_id,
- user_id, tenant_id, cred_type, key, secret])
-
-
-class TestListCredentialsCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_credentials)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals(['ID', 'User ID', 'Tenant ID', 'Type', 'Key',
- 'Secret'], row)
-
-
-class TestDeleteCredentialCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_credential)
-
- def test_delete_credential(self):
- credential_id = self._create_credential(self._create_user())
-
- self.run_cmd(delete_credential, [
- '--where-id', credential_id])
-
- self.ob.clear()
-
- # ensure it's not returned
- self.run_cmd(list_credentials)
- output = self.ob.read()
- self.assertNotIn(credential_id, output)
-
-
-class TestCreateEndpointTemplateCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(create_endpoint_template)
-
- def test_create_global_endpoint_template(self):
- region = uuid.uuid4().hex
- service_id = self._create_service()
- public_url = 'http://%s' % (uuid.uuid4().hex)
- admin_url = 'http://%s' % (uuid.uuid4().hex)
- internal_url = 'http://%s' % (uuid.uuid4().hex)
- self.run_cmd(create_endpoint_template, [
- '--region', region,
- '--service-id', service_id,
- '--public-url', public_url,
- '--admin-url', admin_url,
- '--internal-url', internal_url,
- '--global'])
- endpoint_template_id = self.ob.read_lines()[0]
- self.assertTrue(int(endpoint_template_id))
-
- self.ob.clear()
-
- self.run_cmd(list_endpoint_templates)
- self.assertTableContainsRow(self.ob.read(), [endpoint_template_id,
- service_id, region, str(True), str(True), public_url, admin_url,
- internal_url])
-
-
-class TestUpdateEndpointTemplateCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(update_endpoint_template)
-
- def test_update_endpoint_template(self):
- endpoint_template_id = self._create_endpoint_template(
- self._create_service())
-
- region = uuid.uuid4().hex
- service_id = self._create_service()
- public_url = 'http://%s' % (uuid.uuid4().hex)
- admin_url = 'http://%s' % (uuid.uuid4().hex)
- internal_url = 'http://%s' % (uuid.uuid4().hex)
-
- self.run_cmd(update_endpoint_template, [
- '--where-id', endpoint_template_id,
- '--region', region,
- '--service-id', service_id,
- '--public-url', public_url,
- '--admin-url', admin_url,
- '--internal-url', internal_url,
- '--global',
- '--disable'])
-
- self.ob.clear()
-
- self.run_cmd(list_endpoint_templates)
- self.assertTableContainsRow(self.ob.read(), [endpoint_template_id,
- service_id, region, str(False), str(True), public_url, admin_url,
- internal_url])
-
-
-class TestListEndpointTemplatesCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_endpoint_templates)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals(['ID', 'Service ID', 'Region', 'Enabled', 'Global',
- 'Public URL', 'Admin URL', 'Internal URL'], row)
-
-
-class TestDeleteEndpointTemplateCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(delete_endpoint_template)
-
- def test_delete_endpoint_template(self):
- endpoint_template_id = self._create_endpoint_template(
- self._create_service())
-
- self.run_cmd(delete_endpoint_template, [
- '--where-id', endpoint_template_id])
-
- self.ob.clear()
-
- # ensure it's not returned
- self.run_cmd(list_endpoint_templates)
- output = self.ob.read()
- self.assertNotIn(endpoint_template_id, output)
-
-
-class TestCreateEndpointCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(map_endpoint)
-
- def test_create_global_endpoint(self):
- tenant_id = self._create_tenant()
- endpoint_template_id = self._create_endpoint_template(
- self._create_service())
- self.run_cmd(map_endpoint, [
- '--endpoint-template-id', endpoint_template_id,
- '--tenant-id', tenant_id])
-
- self.ob.clear()
-
- self.run_cmd(list_endpoints)
- self.assertTableContainsRow(self.ob.read(), [endpoint_template_id,
- tenant_id])
-
-
-class TestListEndpointsCommand(CommandTestCase):
- def test_no_args(self):
- self.run_cmd(list_endpoints)
- lines = self.ob.read_lines()
- row = [col.strip() for col in lines[1].split('|') if col.strip()]
- self.assertEquals(['Endpoint Template ID', 'Tenant ID'], row)
-
-
-class TestDeleteEndpointCommand(CommandTestCase):
- def test_no_args(self):
- with self.assertRaises(SystemExit):
- self.run_cmd(unmap_endpoint)
-
- def test_delete_endpoint(self):
- tenant_id = self._create_tenant()
- endpoint_template_id = self._create_endpoint_template(
- self._create_service())
- self._map_endpoint(endpoint_template_id, tenant_id)
-
- self.run_cmd(unmap_endpoint, [
- '--tenant-id', tenant_id,
- '--endpoint-template-id', endpoint_template_id])
-
- self.ob.clear()
-
- # ensure it's not returned
- self.run_cmd(list_endpoints)
- output = self.ob.read()
- self.assertNotIn(" | ".join([endpoint_template_id, tenant_id]), output)
diff --git a/keystone/test/unit/test_commands_v1.py b/keystone/test/unit/test_commands_v1.py
deleted file mode 100644
index abd722f6..00000000
--- a/keystone/test/unit/test_commands_v1.py
+++ /dev/null
@@ -1,77 +0,0 @@
-import datetime
-import unittest2 as unittest
-
-from keystone import backends
-import keystone.backends.sqlalchemy as db
-import keystone.backends.api as db_api
-import keystone.manage.api as manage_api
-from keystone import utils
-
-
-class TestCommandsV1(unittest.TestCase):
- """Tests for keystone-manage version 1 commands"""
-
- def __init__(self, *args, **kwargs):
- super(TestCommandsV1, self).__init__(*args, **kwargs)
- self.options = {
- 'backends': 'keystone.backends.sqlalchemy',
- 'keystone.backends.sqlalchemy': {
- # in-memory db
- 'sql_connection': 'sqlite://',
- 'backend_entities':
- "['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant', "
- "'Tenant', 'User', 'Credentials', 'EndpointTemplates', "
- "'Token', 'Service']",
- },
- }
- # Need to populate the CONF module with these options
- utils.set_configuration(self.options)
-
- def setUp(self):
- self.clear_all_data()
- manage_api.add_tenant('Test tenant')
- self.user = manage_api.add_user('Test user', 'Test password',
- 'Test tenant')
-
- def tearDown(self):
- self.clear_all_data()
-
- @staticmethod
- def clear_all_data():
- """
- Purges the database of all data
- """
- db.unregister_models()
- reload(db)
- backends.configure_backends()
-
- def test_service_list(self):
- result = manage_api.list_services()
- self.assertEqual(result, [])
-
- def test_add_service(self):
- data = {
- 'name': 'Test name',
- 'type': 'Test type',
- 'desc': 'Test description',
- 'owner_id': self.user.id,
- }
- manage_api.add_service(**data)
- result = manage_api.list_services()
- self.assertEqual(result, [['1', data['name'], data['type'],
- data['owner_id'], data['desc']]])
-
- def test_add_token(self):
- data = {
- 'token': 'Test token',
- 'user': 'Test user',
- 'tenant': 'Test tenant',
- 'expires': '20120104T18:30',
- }
- manage_api.add_token(**data)
- result = manage_api.list_tokens()
- user = db_api.USER.get_by_name(data['user'])
- tenant = db_api.TENANT.get_by_name(data['tenant'])
- self.assertEqual(result, [[data['token'], user['id'],
- datetime.datetime(2012, 1, 4, 18, 30),
- tenant['id']]])
diff --git a/keystone/test/unit/test_config.py b/keystone/test/unit/test_config.py
deleted file mode 100644
index b1827055..00000000
--- a/keystone/test/unit/test_config.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# Copyright (c) 2011 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 ast
-import unittest2 as unittest
-
-from keystone import config
-from keystone import utils
-
-CONF = config.CONF
-
-
-class ConfigTestCase(unittest.TestCase):
- """
- Base class to test keystone/config.py
- """
- def __init__(self, *args, **kwargs):
- super(ConfigTestCase, self).__init__(*args, **kwargs)
-
- def setUp(self):
- pass
-
- def tearDown(self):
- pass
-
- def test_old_config_syntax(self):
- options = {
- 'verbose': True,
- 'debug': False,
- 'backends': "keystone.backends.sqlalchemy",
- 'keystone.backends.sqlalchemy': {
- # in-memory db
- 'sql_connection': 'sqlite://',
- 'backend_entities':
- "['UserRoleAssociation', 'Endpoints', 'Role', 'Tenant', "
- "'Tenant', 'User', 'Credentials', 'EndpointTemplates', "
- "'Token', 'Service']",
- },
- 'extensions': 'osksadm, oskscatalog, hpidm',
- 'keystone-admin-role': 'Admin',
- 'keystone-service-admin-role': 'KeystoneServiceAdmin',
- 'hash-password': 'True',
- }
- utils.set_configuration(options)
- self.assertTrue(CONF.verbose)
- self.assertFalse(CONF.debug)
- self.assertIn('hpidm', [ext.strip() for ext in CONF.extensions])
- self.assertIn('keystone.backends.sqlalchemy', CONF.backends)
- self.assertTrue(CONF.hash_password)
- self.assertEquals(CONF['keystone.backends.sqlalchemy'].sql_connection,
- 'sqlite://')
- self.assertIsInstance(ast.literal_eval(
- CONF['keystone.backends.sqlalchemy'].backend_entities),
- list)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_controller_version.py b/keystone/test/unit/test_controller_version.py
deleted file mode 100644
index eccf629d..00000000
--- a/keystone/test/unit/test_controller_version.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2011 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 logging
-from lxml import etree
-import unittest2 as unittest
-from webob import Request
-
-from keystone.controllers.version import VersionController
-
-LOGGER = logging.getLogger(__name__)
-
-
-class TestVersionController(unittest.TestCase):
- def setUp(self):
- self.controller = VersionController()
-
- def _default_version(self, file=None):
- """ Verify default response for versions is JSON """
- if file is None:
- file = 'admin/version'
- req = Request.blank('/')
- req.environ = {}
- response = self.controller.get_version_info(req, file=file)
- self.assertEqual(response.content_type, 'application/json')
- data = json.loads(response.body)
- self.assertIsNotNone(data)
-
- def _json_version(self, file=None):
- """ Verify JSON response for versions
-
- Checks that JSON is returned when Accept is set to application/json.
- Also checks that verions and version exist and that
- values are as expected
-
- """
- if file is None:
- file = 'admin/version'
- req = Request.blank('/')
- req.headers['Accept'] = 'application/json'
- req.environ = {}
- response = self.controller.get_version_info(req, file=file)
- self.assertEqual(response.content_type, 'application/json')
- data = json.loads(response.body)
- self.assertIn("versions", data)
- versions = data['versions']
- self.assertIn("values", versions)
- values = versions['values']
- self.assertIsInstance(values, list)
- for version in values:
- for item in version:
- self.assertIn(item, ["id", "status", "updated", "links",
- "media-types"])
-
- def _xml_version(self, file=None):
- """ Verify XML response for versions
-
- Checks that XML is returned when Accept is set to application/xml.
- Also checks that verions and version tags exist and that
- attributes are as expected
-
- """
- if file is None:
- file = 'admin/version'
- req = Request.blank('/')
- req.headers['Accept'] = 'application/xml'
- req.environ = {}
- response = self.controller.get_version_info(req, file=file)
- self.assertEqual(response.content_type, 'application/xml')
- data = etree.fromstring(response.body)
- self.assertEqual(data.tag,
- '{http://docs.openstack.org/common/api/v2.0}versions')
- for version in data:
- self.assertEqual(version.tag,
- '{http://docs.openstack.org/common/api/v2.0}version')
- for attribute in version.attrib:
- self.assertIn(attribute, ["id", "status", "updated", "links",
- "media-types"])
-
- def _atom_version(self, file=None):
- """ Verify ATOM response for versions
-
- Checks that ATOM XML is returned when Accept is set to
- aapplication/atom+xml.
- Also checks that verions and version tags exist and that
- attributes are as expected
-
- """
- if file is None:
- file = 'admin/version'
- req = Request.blank('/')
- req.headers['Accept'] = 'application/atom+xml'
- req.environ = {}
- response = self.controller.get_version_info(req, file=file)
- self.assertEqual(response.content_type, 'application/atom+xml')
- data = etree.fromstring(response.body)
- self.assertEqual(data.tag,
- '{http://www.w3.org/2005/Atom}feed')
-
- def test_default_version_admin(self):
- self._default_version(file='admin/version')
-
- def test_default_version_service(self):
- self._default_version(file='service/version')
-
- def test_xml_version_admin(self):
- self._xml_version(file='admin/version')
-
- def test_xml_version_service(self):
- self._xml_version(file='service/version')
-
- def test_json_version_admin(self):
- self._json_version(file='admin/version')
-
- def test_json_version_service(self):
- self._json_version(file='service/version')
-
- def test_atom_version_admin(self):
- self._atom_version(file='admin/version')
-
- def test_atom_version_service(self):
- self._atom_version(file='service/version')
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_d5_compat.py b/keystone/test/unit/test_d5_compat.py
deleted file mode 100644
index 40d0e997..00000000
--- a/keystone/test/unit/test_d5_compat.py
+++ /dev/null
@@ -1,174 +0,0 @@
-import json
-import unittest2 as unittest
-from keystone.frontends import d5_compat
-import keystone.logic.types.fault as fault
-
-
-class TestD5Auth(unittest.TestCase):
- """Test to make sure Keystone honors the 'unofficial' D5 API contract.
-
- The main differences were:
- - POST /v2.0/tokens without the "auth" wrapper
- - POST /v2.0/tokens with tenantId in the passwordCredentials object
- (instead of the auth wrapper)
- - Response for validate token was wrapped in "auth"
-
- TODO(zns): deprecate this once we move to the next version of the API
- """
-
- pwd_xml = '<?xml version="1.0" encoding="UTF-8"?>\
- <passwordCredentials\
- xmlns="http://docs.openstack.org/identity/api/v2.0" \
- password="secret" username="disabled" \
- />'
-
- def test_pwd_cred_marshall(self):
- creds = d5_compat.D5AuthWithPasswordCredentials.from_xml(self.pwd_xml)
- self.assertEqual(creds.password, "secret")
- self.assertEqual(creds.username, "disabled")
-
- def test_pwd_creds_from_json(self):
- data = json.dumps({"passwordCredentials":
- {"username": "foo", "password": "bar"}})
- creds = d5_compat.D5AuthWithPasswordCredentials.from_json(data)
- self.assertEqual(creds.username, "foo")
- self.assertEqual(creds.password, "bar")
- self.assertIsNone(creds.tenant_id)
- self.assertIsNone(creds.tenant_name)
-
- def test_pwd_creds_with_tenant_name_from_json(self):
- data = json.dumps({"passwordCredentials":
- {"tenantName": "blaa", "username": "foo",
- "password": "bar"}})
- creds = d5_compat.D5AuthWithPasswordCredentials.from_json(data)
- self.assertEqual(creds.username, "foo")
- self.assertEqual(creds.password, "bar")
- self.assertIsNone(creds.tenant_id)
- self.assertEqual(creds.tenant_name, "blaa")
-
- def test_pwd_creds_with_tenant_id_from_json(self):
- data = json.dumps({"passwordCredentials":
- {"tenantId": "blaa", "username": "foo",
- "password": "bar"}})
- creds = d5_compat.D5AuthWithPasswordCredentials.from_json(data)
- self.assertEqual(creds.username, "foo")
- self.assertEqual(creds.password, "bar")
- self.assertEqual(creds.tenant_id, "blaa")
- self.assertIsNone(creds.tenant_name)
-
- def test_pwd_not_both_tenant_from_json(self):
- data = json.dumps({"tenantId": "blaa", "tenantName": "aalb"})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials",
- d5_compat.D5AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_no_creds_from_json(self):
- data = json.dumps({"auth": {}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials",
- d5_compat.D5AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_invalid_attribute_from_json(self):
- data = json.dumps({"passwordCredentials": {"foo": "bar"}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Invalid",
- d5_compat.D5AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_no_username_from_json(self):
- data = json.dumps({"passwordCredentials": {}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials:username",
- d5_compat.D5AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_no_password_from_json(self):
- data = json.dumps({"passwordCredentials":
- {"username": "foo"}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Expecting passwordCredentials:password",
- d5_compat.D5AuthWithPasswordCredentials.from_json,
- data)
-
- def test_pwd_invalid_creds_attribute_from_json(self):
- data = json.dumps({"passwordCredentials": {"bar": "foo"}})
- self.assertRaisesRegexp(fault.BadRequestFault,
- "Invalid",
- d5_compat.D5AuthWithPasswordCredentials.from_json,
- data)
-
- def test_json_pwd_creds_from_D5(self):
- D5_data = json.dumps({"passwordCredentials":
- {"username": "foo", "password": "bar"}})
- diablo_data = json.dumps({"auth": {"passwordCredentials":
- {"username": "foo", "password": "bar"}}})
- creds = d5_compat.D5AuthWithPasswordCredentials.from_json(D5_data)
- diablo = creds.to_json()
- self.assertEquals(diablo, diablo_data)
-
- def test_json_authdata_from_D5(self):
- pass
-
- def test_json_validatedata_from_D5(self):
- diablo_data = {
- "access": {
- "token": {
- "expires": "2011-12-07T21:31:49.215675",
- "id": "92c8962a-7e9b-40d1-83eb-a2f3b6eb45c3"
- },
- "user": {
- "id": "3",
- "name": "admin",
- "roles": [
- {
- "id": "1",
- "name": "Admin"
- }
- ],
- "username": "admin"
- }
- }
- }
- D5_data = {"auth": {
- "token": {
- "expires": "2011-12-07T21:31:49.215675",
- "id": "92c8962a-7e9b-40d1-83eb-a2f3b6eb45c3"
- },
- "user": {
- "roleRefs": [
- {
- "id": "1",
- "roleId": "Admin"
- }
- ],
- "username": "admin"
- }
- }
- }
- creds = d5_compat.D5ValidateData.from_json(json.dumps(diablo_data))
- D5 = json.loads(creds.to_json())
- self.assertEquals(diablo_data['access'], D5['access'],
- "D5 compat response must contain Diablo format")
- self.assertEquals(D5_data['auth'], D5['auth'],
- "D5 compat response must contain D5 format")
-
- def test_no_catalog_in_response(self):
- minimal_response = {
- "access": {
- "token": {
- "expires": "2011-12-07T21:31:49.215675",
- "id": "92c8962a-7e9b-40d1-83eb-a2f3b6eb45c3"
- },
- "user": {
- "id": "3",
- "name": "admin",
- }
- }
- }
- d5 = d5_compat.D5toDiabloAuthData(init_json=minimal_response)
- self.assertTrue(d5.to_json())
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_extensions.py b/keystone/test/unit/test_extensions.py
deleted file mode 100644
index 2a72d570..00000000
--- a/keystone/test/unit/test_extensions.py
+++ /dev/null
@@ -1,81 +0,0 @@
-# Copyright (c) 2011 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.
-
-from xml.etree import ElementTree
-import json
-import unittest2 as unittest
-
-from keystone import config
-from keystone.contrib.extensions import CONFIG_EXTENSION_PROPERTY
-from keystone.contrib.extensions.admin import EXTENSION_ADMIN_PREFIX
-from keystone.logic.extension_reader import ExtensionsReader
-from keystone.logic.extension_reader import get_supported_extensions
-
-CONF = config.CONF
-
-
-class TestExtensionReader(unittest.TestCase):
- """Unit tests for ExtensionsReader.These
- tests check whether the returned extensions vary
- when they are configured differently."""
-
- def setUp(self):
- self.original_extensions = CONF.extensions
- CONF.set_override(CONFIG_EXTENSION_PROPERTY, ["osksadm"])
- self.extensions_reader = ExtensionsReader(EXTENSION_ADMIN_PREFIX)
-
- def tearDown(self):
- CONF.set_override(CONFIG_EXTENSION_PROPERTY, self.original_extensions)
-
- def test_extensions_reader_getsupportedoptions(self):
- self.assertIn('osksadm', get_supported_extensions())
-
- def test_extensions_with_only_osksadm_json(self):
- r = self.extensions_reader.get_extensions().to_json()
- content = json.loads(r)
- self.assertIsNotNone(content['extensions'])
- self.assertIsNotNone(content['extensions']['values'])
- found_osksadm = False
- found_oskscatalog = False
- for value in content['extensions']['values']:
- if value['extension']['alias'] == 'OS-KSADM':
- found_osksadm = True
- if value['extension']['alias'] == 'OS-KSCATALOG':
- found_oskscatalog = True
- self.assertTrue(found_osksadm,
- "Missing OS-KSADM extension.")
- self.assertFalse(found_oskscatalog,
- "Non configured OS-KSCATALOG extension returned.")
-
- def test_extensions_with_only_osksadm_xml(self):
- r = self.extensions_reader.get_extensions().to_xml()
- content = ElementTree.XML(r)
- extensions = content.findall(
- "{http://docs.openstack.org/common/api/v1.0}extension")
- found_osksadm = False
- found_oskscatalog = False
- for extension in extensions:
- if extension.get("alias") == 'OS-KSADM':
- found_osksadm = True
- if extension.get("alias") == 'OS-KSCATALOG':
- found_oskscatalog = True
- self.assertTrue(found_osksadm,
- "Missing OS-KSADM extension.")
- self.assertFalse(found_oskscatalog,
- "Non configured OS-KSCATALOG extension returned.")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_logic_auth.py b/keystone/test/unit/test_logic_auth.py
deleted file mode 100644
index 3b61debf..00000000
--- a/keystone/test/unit/test_logic_auth.py
+++ /dev/null
@@ -1,132 +0,0 @@
-# Copyright (c) 2011 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 datetime
-from lxml import etree
-import unittest2 as unittest
-
-import base
-from keystone.logic.types import auth as logic_auth
-from keystone import models
-from keystone.test import utils as test_utils
-
-
-class LogicTypesAuthTestCase(base.ServiceAPITest):
- """
- Base class to test keystone/logic/types/auth.py
- """
- def __init__(self, *args, **kwargs):
- super(LogicTypesAuthTestCase, self).__init__(*args, **kwargs)
-
- self.user = models.User(id='u1', name='john', username='john')
- self.role = models.Role(id=1, name='Admin')
- self.user.rolegrants = models.Roles([self.role], links=None)
- self.token = models.Token(id='abc123T', user_id=self.user.id,
- expires=datetime.date(2000, 1, 31))
- self.tenant = models.Tenant(id='ten8', name='The Tenant')
- self.token.tenant = self.tenant
- self.base_urls = [models.EndpointTemplate(
- id="1",
- internal_url="http://127.0.0.1/v1/%tenant_id%",
- public_url="http://internet.com/v1/%tenant_id%",
- admin_url="http://private.net/v1/",
- version_id="v1",
- version_url="http://127.0.0.1/v1/",
- version_info="http://127.0.0.1/",
- region="RegionOne",
- service_id="0"
- ),
- models.EndpointTemplate(
- id="2",
- internal_url="http://127.0.0.1/v1/%tenant_id%",
- public_url="http://internet.com/v1/%tenant_id%",
- service_id="0"
- )]
- self.url_types = ["internal", "public", "admin"]
-
- def test_AuthData_json_serialization(self):
- auth = logic_auth.AuthData(self.token, self.user)
- data = json.loads(auth.to_json())
- expected = {
- 'access': {
- 'token': {
- 'expires': '2000-01-31',
- 'tenants': [{
- 'id': 'ten8',
- 'name': 'The Tenant'
- }],
- 'id': 'abc123T',
- 'tenant': {
- 'id': 'ten8',
- 'name': 'The Tenant'
- }
- },
- 'user': {
- 'id': 'u1',
- 'roles': [{
- 'name': 'Admin',
- 'id': '1'
- }],
- 'name': 'john'
- }
- }
- }
- self.assertDictEqual(data, expected)
-
- def test_AuthData_xml_serialization(self):
- auth = logic_auth.AuthData(self.token, self.user)
- xml_str = auth.to_xml()
- expected = ('<access xmlns='
- '"http://docs.openstack.org/identity/api/v2.0"><token expires='
- '"2000-01-31" id="abc123T"><tenant name="The Tenant" '
- 'id="ten8"/></token><user name="john" id="u1"><roles '
- 'xmlns="http://docs.openstack.org/identity/api/v2.0"><role '
- 'xmlns="http://docs.openstack.org/identity/api/v2.0" id="1" '
- 'name="Admin"/></roles></user></access>')
- self.assertTrue(test_utils.XMLTools.xmlEqual(xml_str, expected))
-
- def test_AuthData_json_catalog(self):
- auth = logic_auth.AuthData(self.token, self.user, self.base_urls)
- data = json.loads(auth.to_json())
- self.assertIn("access", data)
- self.assertIn("serviceCatalog", data['access'])
- catalog = data['access']['serviceCatalog']
- self.assertTrue(len(catalog) > 0)
- endpoints = catalog[0]['endpoints']
- self.assertTrue(len(endpoints) > 1)
- endpoint = endpoints[0]
- self.assertIn("publicURL", endpoint)
- self.assertIn("versionId", endpoint)
- self.assertIn("tenantId", endpoint)
-
- endpoint = endpoints[1]
- self.assertNotIn("versionId", endpoint)
-
- def test_AuthData_xml_catalog(self):
- auth = logic_auth.AuthData(self.token, self.user, self.base_urls)
- xml_str = auth.to_xml()
- dom = etree.fromstring(xml_str)
- xmlns = "http://docs.openstack.org/identity/api/v2.0"
- catalog = dom.find("{%s}serviceCatalog" % xmlns)
- service = catalog.find("{%s}service" % xmlns)
- endpoint = service.find("{%s}endpoint" % xmlns)
- self.assertIsNotNone("publicURL", endpoint.attrib)
- self.assertIn("versionId", endpoint.attrib)
- self.assertIn("tenantId", endpoint.attrib)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_migrations.py b/keystone/test/unit/test_migrations.py
deleted file mode 100644
index 9284386a..00000000
--- a/keystone/test/unit/test_migrations.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010-2011 OpenStack, LLC
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Tests for database migrations. The test case runs a series of test cases to
-ensure that migrations work properly both upgrading and downgrading, and that
-no data loss occurs if possible.
-"""
-
-import os
-import unittest2 as unittest
-import urlparse
-
-from migrate.versioning.repository import Repository
-from sqlalchemy import *
-from sqlalchemy.pool import NullPool
-
-import keystone.backends.sqlalchemy.migration as migration_api
-from keystone.logic.types import fault
-
-
-class TestMigrations(unittest.TestCase):
-
- """Test sqlalchemy-migrate migrations"""
-
- TEST_DATABASES = {'sqlite': 'sqlite:///migration.db'}
-
- REPOSITORY_PATH = os.path.abspath(os.path.join(os.path.abspath(__file__),
- os.pardir, os.pardir, os.pardir, 'backends',
- 'sqlalchemy', 'migrate_repo'))
- REPOSITORY = Repository(REPOSITORY_PATH)
-
- def __init__(self, *args, **kwargs):
- super(TestMigrations, self).__init__(*args, **kwargs)
-
- def setUp(self):
- # Load test databases
- self.engines = {}
- for key, value in TestMigrations.TEST_DATABASES.items():
- self.engines[key] = create_engine(value, poolclass=NullPool)
-
- # We start each test case with a completely blank slate.
- self._reset_databases()
-
- def tearDown(self):
- # We destroy the test data store between each test case,
- # and recreate it, which ensures that we have no side-effects
- # from the tests
- self._reset_databases()
-
- def _reset_databases(self):
- for key, engine in self.engines.items():
- conn_string = TestMigrations.TEST_DATABASES[key]
- conn_pieces = urlparse.urlparse(conn_string)
- if conn_string.startswith('sqlite'):
- # We can just delete the SQLite database, which is
- # the easiest and cleanest solution
- db_path = conn_pieces.path.strip('/')
- if os.path.exists(db_path):
- os.unlink(db_path)
- # No need to recreate the SQLite DB. SQLite will
- # create it for us if it's not there...
- elif conn_string.startswith('mysql'):
- # We can execute the MySQL client to destroy and re-create
- # the MYSQL database, which is easier and less error-prone
- # than using SQLAlchemy to do this via MetaData...trust me.
- database = conn_pieces.path.strip('/')
- loc_pieces = conn_pieces.netloc.split('@')
- host = loc_pieces[1]
- auth_pieces = loc_pieces[0].split(':')
- user = auth_pieces[0]
- password = ""
- if len(auth_pieces) > 1:
- if auth_pieces[1].strip():
- password = "-p%s" % auth_pieces[1]
- sql = ("drop database if exists %(database)s; "
- "create database %(database)s;") % locals()
- cmd = ("mysql -u%(user)s %(password)s -h%(host)s "
- "-e\"%(sql)s\"") % locals()
- exitcode, out, err = execute(cmd)
- self.assertEqual(0, exitcode)
-
- def test_walk_versions(self):
- """
- Walks all version scripts for each tested database, ensuring
- that there are no errors in the version scripts for each engine
- """
- for key, engine in self.engines.items():
- self._walk_versions(TestMigrations.TEST_DATABASES[key])
-
- def _walk_versions(self, sql_connection):
- # Determine latest version script from the repo, then
- # upgrade from 1 through to the latest, with no data
- # in the databases. This just checks that the schema itself
- # upgrades successfully.
-
- # Assert we are not under version control...
- self.assertRaises(fault.DatabaseMigrationError,
- migration_api.db_version,
- sql_connection)
- # Place the database under version control
- print migration_api.version_control(sql_connection)
-
- cur_version = migration_api.db_version(sql_connection)
- self.assertEqual(0, cur_version)
-
- for version in xrange(1, TestMigrations.REPOSITORY.latest + 1):
- migration_api.upgrade(sql_connection, version)
- cur_version = migration_api.db_version(sql_connection)
- self.assertEqual(cur_version, version)
-
- # Now walk it back down to 0 from the latest, testing
- # the downgrade paths.
- for version in reversed(
- xrange(0, TestMigrations.REPOSITORY.latest)):
- migration_api.downgrade(sql_connection, version)
- cur_version = migration_api.db_version(sql_connection)
- self.assertEqual(cur_version, version)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models.py b/keystone/test/unit/test_models.py
deleted file mode 100644
index dd096aab..00000000
--- a/keystone/test/unit/test_models.py
+++ /dev/null
@@ -1,131 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.models import AttrDict, Resource
-from keystone.test import utils as testutils
-
-
-class TestModels(unittest.TestCase):
- '''Unit tests for keystone/models.py.'''
-
- def test_attrdict_class(self):
- ad = AttrDict()
- ad.id = 1
- self.assertEqual(ad.id, 1)
- ad._sa_instance_state = AttrDict()
- self.assertIsInstance(ad._sa_instance_state, AttrDict)
-
- def test_resource(self):
- resource = Resource()
- self.assertEquals(str(resource.__class__),
- "<class 'keystone.models.Resource'>",
- "Resource should be of instance "
- "class keystone.models.Resource but instead "
- "was '%s'" % str(resource.__class__))
- self.assertIsInstance(resource, dict, "")
- resource._sa_instance_state = AttrDict()
- self.assertIsInstance(resource._sa_instance_state, AttrDict)
-
- def test_resource_respresentation(self):
- resource = Resource(id=1, name="John")
- self.assertIn(resource.__repr__(), [
- "<Resource(id=1, name='John')>",
- "<Resource(name='John', id=1)>"])
- self.assertIn(resource.__str__(), [
- "{'resource': {'name': 'John', 'id': 1}}",
- "{'resource': {'id': 1, 'name': 'John'}}"])
- self.assertEqual(resource['resource']['id'], 1)
-
- def test_resource_static_properties(self):
- resource = Resource(id=1, name="the resource", blank=None)
- self.assertEquals(resource.id, 1)
- self.assertEquals(resource.name, "the resource")
- self.assertRaises(AttributeError, getattr, resource,
- 'some_bad_property')
-
- def test_resource_keys(self):
- resource = Resource(id=1, name="the resource", blank=None)
- self.assertEquals(resource.id, 1)
- self.assertEquals(resource['id'], 1)
-
- self.assertTrue('id' in resource)
- self.assertTrue(hasattr(resource, 'id'))
-
- resource['dynamic'] = '1'
- self.assertEquals(resource['dynamic'], '1')
-
- self.assertTrue('dynamic' in resource)
-
- def test_resource_dynamic_properties(self):
- resource = Resource(id=1, name="the resource", blank=None)
- resource["dynamic"] = "test"
- self.assertEquals(resource["dynamic"], "test")
- self.assertEquals(resource["name"], "the resource")
-
- def test_resource_json_serialization(self):
- resource = Resource(id=1, name="the resource", blank=None)
- json_str = resource.to_json()
- d1 = json.loads(json_str)
- d2 = json.loads('{"resource": {"name": "the resource", "id": 1}}')
- self.assertDictEqual(d1, d2)
-
- def test_resource_json_serialization_mapping(self):
- resource = Resource(id=1, name="the resource", rolegrant_id=12)
- json_str = resource.to_json(hints={"maps": {"refId": "rolegrant_id",
- }})
- d1 = json.loads(json_str)
- d2 = {"resource": {"name": "the resource", "id": 1, "refId": 12}}
- self.assertDictEqual(d1, d2)
-
- def test_resource_json_serialization_types(self):
- resource = Resource(id=1, name="the resource", bool=True, int=5)
- json_str = resource.to_json(hints={"types":
- [("bool", bool), ("int", int)]})
- d1 = json.loads(json_str)
- d2 = {"resource": {"name": "the resource", "id": 1, "bool": True,
- "int": 5}}
- self.assertDictEqual(d1, d2)
-
- def test_resource_xml_serialization(self):
- resource = Resource(id=1, name="the resource", blank=None)
- xml_str = resource.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<resource id="1" name="the resource"/>'))
-
- def test_resource_xml_serialization_mapping(self):
- resource = Resource(id=1, name="the resource", rolegrant_id=12)
- xml_str = resource.to_xml(hints={"maps": {"refId": "rolegrant_id", }})
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<resource id="1" name="the resource" refId="12"/>'))
-
- def test_resource_xml_deserialization(self):
- resource = Resource.from_xml('<Resource blank="" id="1" \
- name="the resource"/>',
- hints={
- "contract_attributes": ['id', 'name'],
- "types": [("id", int)]})
- self.assertIsInstance(resource, Resource)
- self.assertEquals(resource.id, 1)
- self.assertEquals(resource.name, "the resource")
-
- def test_resource_json_deserialization(self):
- resource = Resource.from_json('{"resource": {"name": "the resource", \
- "id": 1}}',
- hints={
- "contract_attributes": ['id', 'name'],
- "types": [("id", int)]})
- self.assertIsInstance(resource, Resource)
- self.assertEquals(resource.id, 1)
- self.assertEquals(resource.name, "the resource")
-
- def test_resource_inspection(self):
- resource = Resource(id=1, name="the resource", blank=None)
- self.assertFalse(resource.inspect())
-
- def test_resource_validation(self):
- resource = Resource(id=1, name="the resource", blank=None)
- self.assertTrue(resource.validate())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_endpoint.py b/keystone/test/unit/test_models_endpoint.py
deleted file mode 100644
index 1f216010..00000000
--- a/keystone/test/unit/test_models_endpoint.py
+++ /dev/null
@@ -1,78 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.models import Endpoint
-from keystone.test import utils as testutils
-
-
-class TestModelsEndpoint(unittest.TestCase):
- '''Unit tests for keystone/models.py:Endpoint class.'''
-
- def test_endpoint(self):
- endpoint = Endpoint()
- self.assertEquals(str(endpoint.__class__),
- "<class 'keystone.models.Endpoint'>",
- "endpoint should be of instance "
- "class keystone.models.Endpoint but instead "
- "was '%s'" % str(endpoint.__class__))
- self.assertIsInstance(endpoint, dict, "")
-
- def test_endpoint_static_properties(self):
- endpoint = Endpoint(id=1, name="the endpoint", enabled=True,
- blank=None)
- self.assertEquals(endpoint.id, 1)
- self.assertEquals(endpoint.name, "the endpoint")
- self.assertTrue(endpoint.enabled)
- self.assertRaises(AttributeError, getattr, endpoint,
- 'some_bad_property')
-
- def test_endpoint_properties(self):
- endpoint = Endpoint(id=2, name="the endpoint", blank=None)
- endpoint["dynamic"] = "test"
- self.assertEquals(endpoint["dynamic"], "test")
-
- def test_endpoint_json_serialization(self):
- endpoint = Endpoint(id=3, name="the endpoint", blank=None)
- endpoint["dynamic"] = "test"
- json_str = endpoint.to_json()
- d1 = json.loads(json_str)
- d2 = json.loads('{"endpoint": {"name": "the endpoint", \
- "id": 3, "dynamic": "test"}}')
- self.assertDictEqual(d1, d2)
-
- def test_endpoint_xml_serialization(self):
- endpoint = Endpoint(id=4, name="the endpoint", blank=None)
- xml_str = endpoint.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<endpoint name="the endpoint" id="4"/>'))
-
- def test_endpoint_json_deserialization(self):
- endpoint = Endpoint.from_json('{"name": "the endpoint", "id": 5}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(endpoint, Endpoint)
- self.assertEquals(endpoint.id, 5)
- self.assertEquals(endpoint.name, "the endpoint")
-
- def test_endpoint_json_deserialization_rootless(self):
- endpoint = Endpoint.from_json('{"endpoint": {"name": "the endpoint", \
- "id": 6}}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(endpoint, Endpoint)
- self.assertEquals(endpoint.id, 6)
- self.assertEquals(endpoint.name, "the endpoint")
-
- def test_endpoint_xml_deserialization(self):
- endpoint = Endpoint(id=7, name="the endpoint", blank=None)
- self.assertIsInstance(endpoint, Endpoint)
-
- def test_endpoint_inspection(self):
- endpoint = Endpoint(id=8, name="the endpoint", blank=None)
- self.assertFalse(endpoint.inspect())
-
- def test_endpoint_validation(self):
- endpoint = Endpoint(id=9, name="the endpoint", blank=None)
- self.assertTrue(endpoint.validate())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_endpoint_template.py b/keystone/test/unit/test_models_endpoint_template.py
deleted file mode 100644
index 14841085..00000000
--- a/keystone/test/unit/test_models_endpoint_template.py
+++ /dev/null
@@ -1,79 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.models import EndpointTemplate
-from keystone.test import utils as testutils
-
-
-class TestModelsEndpointTemplate(unittest.TestCase):
- '''Unit tests for keystone/models.py:EndpointTemplate class.'''
-
- def test_endpointtemplate(self):
- endpointtemplate = EndpointTemplate()
- self.assertEquals(str(endpointtemplate.__class__),
- "<class 'keystone.models.EndpointTemplate'>",
- "endpointtemplate should be of instance "
- "class keystone.models.EndpointTemplate but instead "
- "was '%s'" % str(endpointtemplate.__class__))
- self.assertIsInstance(endpointtemplate, dict, "")
-
- def test_endpointtemplate_static_properties(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- enabled=True, blank=None)
- self.assertEquals(endpointtemplate.id, 1)
- self.assertEquals(endpointtemplate.name, "the endpointtemplate")
- self.assertTrue(endpointtemplate.enabled)
- self.assertEquals(endpointtemplate.admin_url, None)
- self.assertRaises(AttributeError, getattr, endpointtemplate,
- 'some_bad_property')
-
- def test_endpointtemplate_properties(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- blank=None)
- endpointtemplate["dynamic"] = "test"
- self.assertEquals(endpointtemplate["dynamic"], "test")
-
- def test_endpointtemplate_json_serialization(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- blank=None)
- endpointtemplate["dynamic"] = "test"
- json_str = endpointtemplate.to_json()
- d1 = json.loads(json_str)
- d2 = json.loads('{"endpointtemplate": {"name": "the endpointtemplate",\
- "id": 1, "dynamic": "test"}}')
- self.assertDictEqual(d1, d2)
-
- def test_endpointtemplate_xml_serialization(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- blank=None)
- xml_str = endpointtemplate.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<endpointtemplate \
- name="the endpointtemplate" id="1"/>'))
-
- def test_endpointtemplate_json_deserialization(self):
- endpointtemplate = EndpointTemplate.from_json('{"name": \
- "the endpointtemplate", "id": 1}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(endpointtemplate, EndpointTemplate)
- self.assertEquals(endpointtemplate.id, 1)
- self.assertEquals(endpointtemplate.name, "the endpointtemplate")
-
- def test_endpointtemplate_xml_deserialization(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- blank=None)
- self.assertIsInstance(endpointtemplate, EndpointTemplate)
-
- def test_endpointtemplate_inspection(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- blank=None)
- self.assertFalse(endpointtemplate.inspect())
-
- def test_endpointtemplate_validation(self):
- endpointtemplate = EndpointTemplate(id=1, name="the endpointtemplate",
- blank=None)
- self.assertTrue(endpointtemplate.validate())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_role.py b/keystone/test/unit/test_models_role.py
deleted file mode 100644
index 9c254484..00000000
--- a/keystone/test/unit/test_models_role.py
+++ /dev/null
@@ -1,115 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.models import Role, UserRoleAssociation
-from keystone.test import utils as testutils
-
-
-class TestModelsRole(unittest.TestCase):
- '''Unit tests for keystone/models.py:Role class.'''
-
- def test_role(self):
- role = Role()
- self.assertEquals(str(role.__class__),
- "<class 'keystone.models.Role'>",
- "role should be of instance "
- "class keystone.models.Role but instead "
- "was '%s'" % str(role.__class__))
- self.assertIsInstance(role, dict, "")
-
- def test_role_static_properties(self):
- role = Role(id=1, name="the role", service_id=1, blank=None)
- self.assertEquals(role.id, "1")
- self.assertEquals(role.name, "the role")
- self.assertEquals(role.service_id, "1")
- self.assertEquals(role.description, None)
- self.assertRaises(AttributeError, getattr, role,
- 'some_bad_property')
-
- def test_role_properties(self):
- role = Role(id=1, name="the role", blank=None)
- role["dynamic"] = "test"
- self.assertEquals(role["dynamic"], "test")
-
- def test_role_json_serialization(self):
- role = Role(id=1, name="the role", blank=None)
- role["dynamic"] = "test"
- json_str = role.to_json()
- d1 = json.loads(json_str)
- d2 = {"role": {"name": "the role", "id": "1", "dynamic": "test"}}
- self.assertDictEqual(d1, d2)
-
- def test_role_json_serialization_mapped(self):
- role = Role(id=1, name="the role",
- service_id="s1",
- tenant_id="t1")
- json_str = role.to_json()
- d1 = json.loads(json_str)
- d2 = {"role": {"name": "the role", "id": "1", "serviceId": "s1",
- "tenantId": "t1"}}
- self.assertDictEqual(d1, d2)
-
- def test_role_xml_serialization(self):
- role = Role(id=1, name="the role", blank=None)
- xml_str = role.to_xml()
- expected = ('<role xmlns="http://docs.openstack.org/identity/api/v2.0"'
- ' id="1" name="the role"/>')
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str, expected),
- msg='%s != %s' % (xml_str, expected))
-
- def test_role_xml_serialization_mapping(self):
- role = Role(id=1, name="the role",
- service_id="s1",
- tenant_id="t1")
- xml_str = role.to_xml()
- expected = ('<role xmlns="http://docs.openstack.org/identity/api/v2.0"'
- ' id="1" name="the role" serviceId="s1" tenantId="t1"/>')
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str, expected),
- msg='%s != %s' % (xml_str,
- expected))
- self.assertEquals(role.service_id, "s1")
-
- def test_role_json_deserialization(self):
- role = Role.from_json('{"name": "the role", "id": "1"}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(role, Role)
- self.assertEquals(role.id, "1")
- self.assertEquals(role.name, "the role")
-
- role = Role.from_json('{"role":{"name": "r1", "serviceId": "s1"}}')
- self.assertEquals(role.service_id, "s1")
-
- def test_role_json_deserialization_types(self):
- role = Role.from_json('{"name": "the role", "id": 1}')
- self.assertIsInstance(role, Role)
- self.assertEquals(role.id, "1",
- "'id' should always be returned as a string")
- self.assertEquals(role.name, "the role")
-
- def test_role_xml_deserialization(self):
- role = Role(id=1, name="the role", blank=None)
- self.assertIsInstance(role, Role)
-
- def test_role_inspection(self):
- role = Role(id=1, name="the role", blank=None)
- self.assertFalse(role.inspect())
-
- def test_role_validation(self):
- role = Role(id=1, name="the role", blank=None)
- self.assertTrue(role.validate())
-
- #
- # UserRoleAssociation
- #
- def test_userroleassociation_json_serialization_mapped(self):
- ura = UserRoleAssociation(id=1, role_id=1, user_id="u1",
- tenant_id="t1")
- json_str = ura.to_json()
- d1 = json.loads(json_str)
- d2 = {"role": {"id": 1, "roleId": 1, "userId": "u1",
- "tenantId": "t1"}}
- self.assertDictEqual(d1, d2)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_service.py b/keystone/test/unit/test_models_service.py
deleted file mode 100644
index a7a73478..00000000
--- a/keystone/test/unit/test_models_service.py
+++ /dev/null
@@ -1,90 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.logic.types import fault
-from keystone.models import Service
-from keystone.test import utils as testutils
-
-
-class TestModelsService(unittest.TestCase):
- '''Unit tests for keystone/models.py:Service class.'''
-
- def test_service(self):
- service = Service()
- self.assertEquals(str(service.__class__),
- "<class 'keystone.models.Service'>",
- "service should be of instance "
- "class keystone.models.Service but instead "
- "was '%s'" % str(service.__class__))
- self.assertIsInstance(service, dict, "")
-
- def test_service_static_properties(self):
- service = Service(id=1, name="the service", type="compute", blank=None)
- self.assertEquals(service.id, "1")
- self.assertEquals(service.name, "the service")
- self.assertRaises(AttributeError, getattr, service,
- 'some_bad_property')
-
- def test_service_properties(self):
- service = Service(id=1, name="the service", type="compute", blank=None)
- service["dynamic"] = "test"
- self.assertEquals(service["dynamic"], "test")
-
- def test_service_json_serialization(self):
- service = Service(id=1, name="the service", type="compute", blank=None)
- service["dynamic"] = "test"
- json_str = service.to_json()
- d1 = json.loads(json_str)
- d2 = json.loads('{"OS-KSADM:service": {"name": "the service", \
- "id": "1", "dynamic": "test", "type": "compute"}}')
- self.assertDictEqual(d1, d2)
-
- def test_service_xml_serialization(self):
- service = Service(id=1, name="the service", type="compute", blank=None)
- xml_str = service.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<service \
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0" \
- id="1" name="the service" type="compute"/>'))
-
- def test_service_json_deserialization(self):
- service = Service.from_json('{"name": "the service", "id": 1,\
- "type": "compute"}',
- hints={
- "contract_attributes": ['id', 'name'],
- "types": [("id", int)]})
- self.assertIsInstance(service, Service)
- self.assertEquals(service.id, 1)
- self.assertEquals(service.name, "the service")
-
- def test_service_xml_deserialization(self):
- service = Service(id=1, name="the service", blank=None)
- self.assertIsInstance(service, Service)
-
- def test_service_inspection(self):
- service = Service(id=1, name="the service", type="compute")
- self.assertFalse(service.inspect())
-
- def test_service_validation_from_json(self):
- self.assertRaises(fault.BadRequestFault, Service.from_json,
- '{"name": "", "id": 1}')
- self.assertRaises(fault.BadRequestFault, Service.from_json,
- '{"type": None, "id": 1}')
-
- def test_service_validation_from_xml(self):
- self.assertRaises(fault.BadRequestFault, Service.from_xml,
- '<service \
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0" \
- id="1" name="the service" type=""/>')
- self.assertRaises(fault.BadRequestFault, Service.from_xml,
- '<service \
- xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0" \
- id="1" name="" type="compute"/>')
-
- def test_service_validation(self):
- service = Service(id=1, name="the service", type="compute")
- self.assertTrue(service.validate())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_services.py b/keystone/test/unit/test_models_services.py
deleted file mode 100644
index 3ceb2385..00000000
--- a/keystone/test/unit/test_models_services.py
+++ /dev/null
@@ -1,47 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.logic.types import fault
-from keystone.models import Service, Services
-from keystone.test import utils as testutils
-
-
-class TestModelsServices(unittest.TestCase):
- '''Unit tests for keystone/models.py:Service class.'''
-
- def test_services(self):
- services = Services(None, None)
- self.assertEquals(str(services.__class__),
- "<class 'keystone.models.Services'>",
- "services should be of instance "
- "class keystone.models.Services but instead "
- "was '%s'" % str(services.__class__))
-
- def test_xml_serialization(self):
- service_list = [Service(name="keystone", type="identity"),
- Service(name="nova", type="compute"),
- Service(name="glance", type="image-service")]
- services = Services(service_list, {})
- xml_str = services.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<services xmlns="http://docs.openstack.org/identity/api/ext/\
-OS-KSADM/v1.0"><service xmlns="http://docs.openstack.org/identity/api/ext/\
-OS-KSADM/v1.0" type="identity" name="keystone"/><service xmlns="http://\
-docs.openstack.org/identity/api/ext/OS-KSADM/v1.0" type="compute" name="nova"\
-/><service xmlns="http://docs.openstack.org/identity/api/ext/OS-KSADM/v1.0" \
-type="image-service" name="glance"/></services>'))
-
- def test_json_serialization(self):
- service_list = [Service(name="keystone", type="identity"),
- Service(name="nova", type="compute"),
- Service(name="glance", type="image-service")]
- services = Services(service_list, {})
- json_str = services.to_json()
- self.assertEqual(json_str,
- '{"OS-KSADM:services": [{"type": "identity", "name": \
-"keystone"}, {"type": "compute", "name": "nova"}, {"type": "image-service", \
-"name": "glance"}], "OS-KSADM:services_links": []}')
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_tenant.py b/keystone/test/unit/test_models_tenant.py
deleted file mode 100644
index 9f8e7fa0..00000000
--- a/keystone/test/unit/test_models_tenant.py
+++ /dev/null
@@ -1,167 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone.models import Tenant
-from keystone.test import utils as testutils
-
-
-class TestModelsTenant(unittest.TestCase):
- '''Unit tests for keystone/models.py:Tenant class.'''
-
- def test_tenant(self):
- tenant = Tenant()
- self.assertEquals(str(tenant.__class__),
- "<class 'keystone.models.Tenant'>",
- "tenant should be of instance "
- "class keystone.models.Tenant but instead "
- "was '%s'" % str(tenant.__class__))
- self.assertIsInstance(tenant, dict, "")
-
- def test_tenant_static_properties(self):
- tenant = Tenant(id=1, name="the tenant", enabled=True, blank=None)
- self.assertEquals(tenant.id, "1")
- self.assertEquals(tenant.name, "the tenant")
- self.assertTrue(tenant.enabled)
- self.assertEquals(tenant.description, None)
- self.assertRaises(AttributeError, getattr, tenant, 'some_bad_property')
-
- def test_tenant_properties(self):
- tenant = Tenant(id=2, name="the tenant", blank=None)
- tenant["dynamic"] = "test"
- self.assertEquals(tenant["dynamic"], "test")
-
- def test_tenant_initialization(self):
- tenant = Tenant(id=3, name="the tenant", enabled=True, blank=None)
- self.assertTrue(tenant.enabled)
-
- tenant = Tenant(id=35, name="the tenant", enabled=0, blank=None)
- self.assertEquals(tenant.enabled, False)
-
- json_str = tenant.to_json()
- d1 = json.loads(json_str)
- self.assertIn('tenant', d1)
- self.assertIn('enabled', d1['tenant'])
- self.assertEquals(d1['tenant']['enabled'], False)
-
- tenant = Tenant(id=36, name="the tenant", enabled=False, blank=None)
- self.assertEquals(tenant.enabled, False)
-
- def test_tenant_json_serialization(self):
- tenant = Tenant(id=3, name="the tenant", enabled=True, blank=None)
- tenant["dynamic"] = "test"
- json_str = tenant.to_json()
-
- d1 = json.loads(json_str)
- d2 = {"tenant": {"name": "the tenant", "id": "3", "enabled": True,
- "dynamic": "test"}}
- self.assertDictEqual(d1, d2)
-
- def test_tenant_xml_serialization(self):
- tenant = Tenant(id=4, name="the tenant", description="X", blank=None)
- xml_str = tenant.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<tenant \
- xmlns="http://docs.openstack.org/identity/api/v2.0" \
- id="4" name="the tenant">\
- <description>X</description></tenant>'))
-
- def test_resource_json_serialization_mapping(self):
- tenant = Tenant(id=1, name="the tenant", rolegrant_id=12)
- json_str = tenant.to_json(hints={"maps": {"refId": "rolegrant_id", }})
- d1 = json.loads(json_str)
- d2 = {"tenant": {"name": "the tenant", "id": "1", "refId": 12}}
- self.assertDictEqual(d1, d2)
-
- def test_tenant_json_serialization_types(self):
- tenant = Tenant(id=1, name="the tenant", bool=True, int=5)
- json_str = tenant.to_json(hints={"types":
- [("bool", bool), ("int", int)]})
- d1 = json.loads(json_str)
- d2 = {"tenant": {"name": "the tenant", "id": "1", "bool": True,
- "int": 5}}
- self.assertDictEqual(d1, d2)
-
- def test_tenant_xml_serialization_mapping(self):
- tenant = Tenant(id=1, name="the resource", rolegrant_id=12)
- xml_str = tenant.to_xml(hints={"maps": {"refId": "rolegrant_id", }})
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<tenant xmlns="http://docs.openstack.org/identity/api/v2.0"\
- id="1" name="the resource" refId="12"></tenant>'))
-
- def test_tenant_json_deserialization(self):
- tenant = Tenant.from_json('{"tenant": {"name": "the tenant",\
- "id": 5, "extra": "some data"}}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(tenant, Tenant)
- self.assertEquals(tenant.id, 5)
- self.assertEquals(tenant.name, "the tenant")
-
- def test_tenant_xml_deserialization(self):
- tenant = Tenant.from_xml('<tenant \
- xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="true" id="6" name="the tenant">\
- <description>qwerty text</description></tenant>',
- hints={
- "contract_attributes": ['id', 'name'],
- "types": [("id", int),
- ("description", str)]})
- self.assertIsInstance(tenant, Tenant)
- self.assertEquals(tenant.id, 6)
- self.assertEquals(tenant.name, "the tenant")
- self.assertEquals(tenant.description, "qwerty text")
-
- def test_tenant_xml_deserialization_hintless(self):
- tenant = Tenant.from_xml('<tenant \
- xmlns="http://docs.openstack.org/identity/api/v2.0" \
- enabled="none" id="7" name="the tenant">\
- <description>qwerty text</description></tenant>')
- self.assertIsInstance(tenant, Tenant)
- self.assertEquals(tenant.id, "7")
- self.assertEquals(tenant.name, "the tenant")
- self.assertEquals(tenant.description, "qwerty text")
-
- def test_tenant_inspection(self):
- tenant = Tenant(id=8, name="the tenant", blank=None)
- self.assertFalse(tenant.inspect())
-
- def test_tenant_validation(self):
- tenant = Tenant(id=9, name="the tenant", blank=None)
- self.assertTrue(tenant.validate())
-
- def test_tenant_description_values(self):
- tenant = Tenant(id=10, name="the tenant")
- self.assertIsNone(tenant.description,
- "Uninitialized description should be None")
- xml = tenant.to_dom()
- desc = xml.find("{http://docs.openstack.org/identity/api/v2.0}"
- "description")
- self.assertIsNone(desc,
- "Uninitialized description should not exist in xml")
-
- tenant = Tenant(id=10, name="the tenant", description=None)
- self.assertIsNone(tenant.description,
- "Description initialized to None should be None")
- xml = tenant.to_dom()
- desc = xml.find("{http://docs.openstack.org/identity/api/v2.0}"
- "description")
- self.assertIsNone(desc,
- "Uninitialized description should not exist in xml")
-
- tenant = Tenant(id=10, name="the tenant", description='')
- self.assertEquals(tenant.description, '',
- 'Description initialized to empty string should be empty string')
- xml = tenant.to_dom()
- desc = xml.find("description")
- self.assertEquals(desc.text, '',
- "Blank Description should show as blank tag in xml")
-
- tenant = Tenant(id=10, name="the tenant", description=None)
- xml = tenant.to_xml(hints={"tags": ["description"]})
- xml = tenant.to_dom()
- desc = xml.find("description")
- self.assertEquals(desc, None,
- "'None' Description should show as empty tag in xml")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_token.py b/keystone/test/unit/test_models_token.py
deleted file mode 100644
index 06affd9c..00000000
--- a/keystone/test/unit/test_models_token.py
+++ /dev/null
@@ -1,70 +0,0 @@
-import json
-from lxml import etree
-import unittest2 as unittest
-
-from keystone.models import Token
-from keystone.test import utils as testutils
-
-
-class TestModelsToken(unittest.TestCase):
- '''Unit tests for keystone/models.py:Token class.'''
-
- def test_token(self):
- token = Token()
- self.assertEquals(str(token.__class__),
- "<class 'keystone.models.Token'>",
- "token should be of instance "
- "class keystone.models.Token but instead "
- "was '%s'" % str(token.__class__))
- self.assertIsInstance(token, dict, "")
-
- def test_token_static_properties(self):
- token = Token(id=1, name="the token", enabled=True, blank=None)
- self.assertEquals(token.id, 1)
- self.assertEquals(token.name, "the token")
- self.assertTrue(token.enabled)
- self.assertRaises(AttributeError, getattr, token,
- 'some_bad_property')
-
- def test_token_properties(self):
- token = Token(id=1, name="the token", blank=None)
- token["dynamic"] = "test"
- self.assertEquals(token["dynamic"], "test")
-
- def test_token_json_serialization(self):
- token = Token(id=1, name="the token", blank=None)
- token["dynamic"] = "test"
- json_str = token.to_json()
- d1 = json.loads(json_str)
- d2 = json.loads('{"token": {"name": "the token", \
- "id": 1, "dynamic": "test"}}')
- self.assertDictEqual(d1, d2)
-
- def test_token_xml_serialization(self):
- token = Token(id=1, name="the token", blank=None)
- xml_str = token.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<token id="1" name="the token"/>'))
-
- def test_token_json_deserialization(self):
- token = Token.from_json('{"name": "the token", "id": 1}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(token, Token)
- self.assertEquals(token.id, 1)
- self.assertEquals(token.name, "the token")
-
- def test_token_xml_deserialization(self):
- token = Token(id=1, name="the token", blank=None)
- self.assertIsInstance(token, Token)
-
- def test_token_inspection(self):
- token = Token(id=1, name="the token", blank=None)
- self.assertFalse(token.inspect())
-
- def test_token_validation(self):
- token = Token(id=1, name="the token", blank=None)
- self.assertTrue(token.validate())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_models_user.py b/keystone/test/unit/test_models_user.py
deleted file mode 100644
index 1a3f7c4f..00000000
--- a/keystone/test/unit/test_models_user.py
+++ /dev/null
@@ -1,69 +0,0 @@
-import json
-from lxml import etree
-import unittest2 as unittest
-
-from keystone.models import User
-from keystone.test import utils as testutils
-
-
-class TestModelsUser(unittest.TestCase):
- '''Unit tests for keystone/models.py:User class.'''
-
- def test_user(self):
- user = User()
- self.assertEquals(str(user.__class__),
- "<class 'keystone.models.User'>",
- "user should be of instance "
- "class keystone.models.User but instead "
- "was '%s'" % str(user.__class__))
- self.assertIsInstance(user, dict, "")
-
- def test_user_static_properties(self):
- user = User(id=1, name="the user", blank=None)
- self.assertEquals(user.id, 1)
- self.assertEquals(user.name, "the user")
- self.assertRaises(AttributeError, getattr, user,
- 'some_bad_property')
-
- def test_user_properties(self):
- user = User(id=1, name="the user", blank=None)
- user["dynamic"] = "test"
- self.assertEquals(user["dynamic"], "test")
-
- def test_user_json_serialization(self):
- user = User(id=1, name="the user", blank=None)
- user["dynamic"] = "test"
- json_str = user.to_json()
- d1 = json.loads(json_str)
- d2 = json.loads('{"user": {"name": "the user", \
- "id": 1, "dynamic": "test"}}')
- self.assertDictEqual(d1, d2)
-
- def test_user_xml_serialization(self):
- user = User(id=1, name="the user", blank=None)
- xml_str = user.to_xml()
- self.assertTrue(testutils.XMLTools.xmlEqual(xml_str,
- '<user name="the user" id="1"/>'))
-
- def test_user_json_deserialization(self):
- user = User.from_json('{"name": "the user", "id": 1}',
- hints={"contract_attributes": ['id', 'name']})
- self.assertIsInstance(user, User)
- self.assertEquals(user.id, 1)
- self.assertEquals(user.name, "the user")
-
- def test_user_xml_deserialization(self):
- user = User(id=1, name="the user", blank=None)
- self.assertIsInstance(user, User)
-
- def test_user_inspection(self):
- user = User(id=1, name="the user", blank=None)
- self.assertFalse(user.inspect())
-
- def test_user_validation(self):
- user = User(id=1, name="the user", blank=None)
- self.assertTrue(user.validate())
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_normalizingfilter.py b/keystone/test/unit/test_normalizingfilter.py
deleted file mode 100644
index 95b7ea93..00000000
--- a/keystone/test/unit/test_normalizingfilter.py
+++ /dev/null
@@ -1,94 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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 unittest2 as unittest
-from keystone.frontends.normalizer import NormalizingFilter
-
-
-class MockWsgiApp(object):
-
- def __init__(self):
- pass
-
- def __call__(self, env, start_response):
- pass
-
-
-def _start_response():
- pass
-
-
-class NormalizingFilterTest(unittest.TestCase):
-
- def setUp(self):
- self.filter = NormalizingFilter(MockWsgiApp(), {})
-
- def test_trailing_slash(self):
- env = {'PATH_INFO': '/v2.0/'}
- self.filter(env, _start_response)
- self.assertEqual('/', env['PATH_INFO'])
-
- def test_remove_trailing_slash_from_empty_path(self):
- """Empty paths should still equate to a slash"""
- env = {'PATH_INFO': '/'}
- self.filter(env, _start_response)
- self.assertEqual('/', env['PATH_INFO'])
-
- def test_no_extension(self):
- env = {'PATH_INFO': '/v2.0/someresource'}
- self.filter(env, _start_response)
- self.assertEqual('/someresource', env['PATH_INFO'])
- self.assertEqual('application/json', env['HTTP_ACCEPT'])
-
- def test_xml_extension(self):
- env = {'PATH_INFO': '/v2.0/someresource.xml'}
- self.filter(env, _start_response)
- self.assertEqual('/someresource', env['PATH_INFO'])
- self.assertEqual('application/xml', env['HTTP_ACCEPT'])
-
- def test_atom_extension(self):
- env = {'PATH_INFO': '/v2.0/someresource.atom'}
- self.filter(env, _start_response)
- self.assertEqual('/someresource', env['PATH_INFO'])
- self.assertEqual('application/atom+xml', env['HTTP_ACCEPT'])
-
- def test_json_extension(self):
- env = {'PATH_INFO': '/v2.0/someresource.json'}
- self.filter(env, _start_response)
- self.assertEqual('/someresource', env['PATH_INFO'])
- self.assertEqual('application/json', env['HTTP_ACCEPT'])
-
- def test_version_header(self):
- env = {'PATH_INFO': '/someresource',
- 'HTTP_ACCEPT':
- 'application/vnd.openstack.identity+xml;version=2.0'}
- self.filter(env, _start_response)
- self.assertEqual('/someresource', env['PATH_INFO'])
- self.assertEqual('application/xml', env['HTTP_ACCEPT'])
- self.assertEqual('2.0', env['KEYSTONE_API_VERSION'])
-
- def test_extension_overrides_header(self):
- env = {
- 'PATH_INFO': '/v2.0/someresource.json',
- 'HTTP_ACCEPT': 'application/xml'}
- self.filter(env, _start_response)
- self.assertEqual('/someresource', env['PATH_INFO'])
- self.assertEqual('application/json', env['HTTP_ACCEPT'])
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_server.py b/keystone/test/unit/test_server.py
deleted file mode 100644
index 5ecd46f7..00000000
--- a/keystone/test/unit/test_server.py
+++ /dev/null
@@ -1,88 +0,0 @@
-import unittest2 as unittest
-from StringIO import StringIO
-import datetime
-import webob
-from lxml import etree
-import json
-
-from keystone import utils
-from keystone.logic.types import auth
-import keystone.logic.types.fault as fault
-
-
-class TestServer(unittest.TestCase):
- '''Unit tests for server.py.'''
-
- request = None
- auth_data = None
-
- def setUp(self):
- environ = {'wsgi.url_scheme': 'http'}
- self.request = webob.Request(environ)
- self.auth_data = auth.ValidateData(auth.Token(datetime.date.today(),
- "2231312"), auth.User("id", "username", "12345", "aTenant"))
-
- #def tearDown(self):
-
- def test_is_xml_response(self):
- self.assertFalse(utils.is_xml_response(self.request))
- self.request.headers["Accept"] = "application/xml"
- self.request.content_type = "application/json"
- self.assertTrue(utils.is_xml_response(self.request))
-
- def test_send_result_xml(self):
- self.request.headers["Accept"] = "application/xml"
- response = utils.send_result(200, self.request, self.auth_data)
-
- self.assertTrue(response.headers['content-type'] ==
- "application/xml; charset=UTF-8")
- xml = etree.fromstring(response.unicode_body)
-
- user = xml.find("{http://docs.openstack.org/identity/api/v2.0}user")
- token = xml.find("{http://docs.openstack.org/identity/api/v2.0}token")
-
- self.assertTrue(user.get("name"), "username")
- self.assertTrue(user.get("id"), "id")
- self.assertTrue(user.get("tenantId"), '12345')
- self.assertTrue(token.get("id"), '2231312')
- self.assertTrue(token.get("expires"), datetime.date.today())
-
- def test_send_result_json(self):
- self.request.headers["Accept"] = "application/json"
- response = utils.send_result(200, self.request, self.auth_data)
- self.assertTrue(response.headers['content-type'] ==
- "application/json; charset=UTF-8")
- dict = json.loads(response.unicode_body)
- self.assertTrue(dict['access']['user']['id'], 'id')
- self.assertTrue(dict['access']['user']['name'], 'username')
- self.assertTrue(dict['access']['user']['tenantId'], '12345')
- self.assertTrue(dict['access']['token']['id'], '2231312')
- self.assertTrue(dict['access']['token']['expires'],
- datetime.date.today())
-
- def test_get_auth_token(self):
- self.request.headers["X-Auth-Token"] = "Test token"
- self.assertTrue(utils.get_auth_token(self.request), "Test Token")
-
- def test_get_normalized_request_content_exception(self):
- self.assertRaises(fault.IdentityFault,
- utils.get_normalized_request_content, None, self.request)
-
- def test_get_normalized_request_content_xml(self):
- self.request.environ["CONTENT_TYPE"] = "application/xml"
- auth.AuthWithPasswordCredentials("username", "password", "1")
- body = '<?xml version="1.0" encoding="UTF-8"?> \
- <auth xmlns="http://docs.openstack.org/identity/api/v2.0">\
- <passwordCredentials \
- xmlns="http://docs.openstack.org/identity/api/v2.0" \
- password="secret" username="disabled" \
- /></auth>'
- str = StringIO()
- str.write(body)
- self.request.environ["wsgi.input"] = str
- self.request.environ["CONTENT_LENGTH"] = str.len
- #TODO: I THINK THIS belongs in a test for auth.py.
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_service_logic.py b/keystone/test/unit/test_service_logic.py
deleted file mode 100644
index d73d0e90..00000000
--- a/keystone/test/unit/test_service_logic.py
+++ /dev/null
@@ -1,65 +0,0 @@
-import datetime as dt
-import unittest2 as unittest
-
-import keystone.logic.service as service
-from keystone.test.unit.base import ServiceAPITest, AdminAPITest
-from keystone.logic.types.fault import ItemNotFoundFault, UnauthorizedFault
-from keystone.logic.types.auth import ValidateData
-
-
-class TestServiceLogic(AdminAPITest):
- """Unit tests for logic/service.py."""
- def __init__(self, *args, **kwargs):
- super(TestServiceLogic, self).__init__(*args, **kwargs)
- self.api_class = service.IdentityService
-
- def setUp(self):
- super(TestServiceLogic, self).setUp()
- user_attrs = {'id': 'test_user',
- 'password': 'test_pass',
- 'email': 'test_user@example.com',
- 'enabled': True,
- 'tenant_id': 'tenant1'}
- self.test_user = self.fixture_create_user(**user_attrs)
-
- def test_get_user(self):
- user_id = self.test_user["id"]
- user = self.api.get_user(self.admin_token_id, user_id)
- # The returned user object is a different type:
- # keystone.logic.types.user.User_Update
- self.assertEqual(self.test_user["email"], user.email)
- self.assertEqual(self.test_user["enabled"], user.enabled)
- self.assertEqual(self.test_user["id"], user.id)
- self.assertEqual(self.test_user["tenant_id"], user.tenant_id)
-
- def test_require_admin(self):
- user_id = self.test_user["id"]
- self.assertRaises(UnauthorizedFault, self.api.get_user,
- self.auth_token_id, user_id)
-
- def test_require_service_admin(self):
- self.assertRaises(UnauthorizedFault, self.api.validate_token,
- self.auth_token_id, "any_id")
-
- def test_has_admin_role(self):
- self.assertTrue(self.api.has_admin_role(self.admin_token_id))
- self.assertFalse(self.api.has_admin_role(self.auth_token_id))
-
- def test_validate_token(self):
- data = self.api.validate_token(self.admin_token_id, self.auth_token_id)
- self.assertTrue(isinstance(data, ValidateData))
-
- def test_remove_role_from_user(self):
- auth_userid = self.auth_user["id"]
- regular_role_id = self.role_fixtures[0]["id"]
- admin_role_id = self.role_fixtures[1]["id"]
- # Attempting to remove the admin role should raise an error.
- self.assertRaises(ItemNotFoundFault, self.api.remove_role_from_user,
- self.admin_token_id, auth_userid, admin_role_id)
- # This should run without error
- self.api.remove_role_from_user(self.admin_token_id,
- auth_userid, regular_role_id)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_utils.py b/keystone/test/unit/test_utils.py
deleted file mode 100644
index 338a12c7..00000000
--- a/keystone/test/unit/test_utils.py
+++ /dev/null
@@ -1,89 +0,0 @@
-import json
-import unittest2 as unittest
-
-from keystone import utils
-
-
-class TestStringEmpty(unittest.TestCase):
- """Unit tests for string functions of utils.py."""
-
- def test_is_empty_for_a_valid_string(self):
- self.assertFalse(utils.is_empty_string('asdfgf'))
-
- def test_is_empty_for_a_blank_string(self):
- self.assertTrue(utils.is_empty_string(''))
-
- def test_is_empty_for_none(self):
- self.assertTrue(utils.is_empty_string(None))
-
- def test_is_empty_for_a_number(self):
- self.assertFalse(utils.is_empty_string(0))
-
-
-class TestCredentialDetection(unittest.TestCase):
- """Unit tests for credential type detection"""
-
- def test_detects_passwordCredentials(self):
- self.content_type = "application/xml"
- self.body = '<auth '\
- 'xmlns="http://docs.openstack.org/identity/api/v2.0">'\
- '<passwordCredentials/></auth>'
- self.assertEquals(utils.detect_credential_type(self),
- "passwordCredentials")
-
- def test_detects_passwordCredentials_unwrapped(self):
- self.content_type = "application/xml"
- self.body = '<passwordCredentials '\
- 'xmlns="http://docs.openstack.org/identity/api/v2.0"/>'
- self.assertEquals(utils.detect_credential_type(self),
- "passwordCredentials")
-
- def test_detects_no_creds(self):
- self.content_type = "application/xml"
- self.body = '<auth '\
- 'xmlns="http://docs.openstack.org/identity/api/v2.0"/>'
- self.assertRaises(Exception, utils.detect_credential_type, self)
-
- def test_detects_blank_creds(self):
- self.content_type = "application/xml"
- self.body = ''
- self.assertRaises(Exception, utils.detect_credential_type, self)
-
- def test_detects_anyCredentials(self):
- self.content_type = "application/xml"
- self.body = '<auth '\
- 'xmlns="http://docs.openstack.org/identity/api/v2.0">'\
- '<anyCredentials/></auth>'
- self.assertEquals(utils.detect_credential_type(self),
- "anyCredentials")
-
- def test_detects_anyCredentials_json(self):
- self.content_type = "application/json"
- self.body = json.dumps({'auth': {'anyCredentials': {}}})
- self.assertEquals(utils.detect_credential_type(self),
- "anyCredentials")
-
- def test_detects_anyUnwrappedCredentials_json(self):
- self.content_type = "application/json"
- self.body = json.dumps({'anyCredentials': {}})
- self.assertEquals(utils.detect_credential_type(self),
- "anyCredentials")
-
- def test_detects_anyCredentials_with_tenant_json(self):
- self.content_type = "application/json"
- self.body = json.dumps({'auth': {'tenantId': '1000',
- 'anyCredentials': {}}})
- self.assertEquals(utils.detect_credential_type(self),
- "anyCredentials")
-
- def test_detects_skips_tenant_json(self):
- self.content_type = "application/json"
- self.body = json.dumps({'auth': {'tenantId': '1000'}})
- self.assertRaises(Exception, utils.detect_credential_type, self)
-
- self.body = json.dumps({'auth': {'tenantName': '1000'}})
- self.assertRaises(Exception, utils.detect_credential_type, self)
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/unit/test_wsgi.py b/keystone/test/unit/test_wsgi.py
deleted file mode 100644
index 48fe028f..00000000
--- a/keystone/test/unit/test_wsgi.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# Copyright 2010 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-
-"""
-Test WSGI basics and provide some helper functions for other WSGI tests.
-"""
-
-import unittest2 as unittest
-import routes
-import webob
-
-from keystone.common import wsgi
-from keystone.test.functional import common
-
-
-class TestWsgi(unittest.TestCase):
-
- def test_debug(self):
-
- class Application(common.BlankApp):
- """Dummy application to test debug."""
-
- def __call__(self, environ, start_response):
- start_response("200", [("X-Test", "checking")])
- return ['Test result']
-
- application = wsgi.Debug(Application())
- result = webob.Request.blank('/').get_response(application)
- self.assertEqual(result.body, "Test result")
-
- def test_router(self):
-
- class Application(common.BlankApp):
- """Test application to call from router."""
-
- def __call__(self, environ, start_response):
- start_response("200", [])
- return ['Router result']
-
- class Router(wsgi.Router):
- """Test router."""
-
- def __init__(self):
- mapper = routes.Mapper()
- mapper.connect("/test", controller=Application())
- super(Router, self).__init__(mapper)
-
- result = webob.Request.blank('/test').get_response(Router())
- self.assertEqual(result.body, "Router result")
- result = webob.Request.blank('/bad').get_response(Router())
- self.assertNotEqual(result.body, "Router result")
-
-
-if __name__ == '__main__':
- unittest.main()
diff --git a/keystone/test/utils.py b/keystone/test/utils.py
deleted file mode 100644
index 40883e24..00000000
--- a/keystone/test/utils.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# pylint: disable=C0103
-import re
-import socket
-from lxml import etree
-
-
-# pylint: disable=W0232
-class XMLTools():
- @staticmethod
- def xmlEqual(xmlStr1, xmlStr2):
- et1 = etree.XML(xmlStr1)
- et2 = etree.XML(xmlStr2)
-
- let1 = [x for x in et1.iter()]
- let2 = [x for x in et2.iter()]
-
- if len(let1) != len(let2):
- return False
-
- while let1:
- el = let1.pop(0)
- foundEl = XMLTools.findMatchingElem(el, let2)
- if foundEl is None:
- return False
- let2.remove(foundEl)
- return True
-
- @staticmethod
- def findMatchingElem(el, eList):
- for elem in eList:
- if XMLTools.elemsEqual(el, elem):
- return elem
- return None
-
- @staticmethod
- def elemsEqual(el1, el2):
- if el1.tag != el2.tag or el1.attrib != el2.attrib:
- return False
- # no requirement for text checking for now
- #if el1.text != el2.text or el1.tail != el2.tail:
- #return False
- path1 = el1.getroottree().getpath(el1)
- path2 = el2.getroottree().getpath(el2)
- idxRE = re.compile(r"(\[\d*\])")
- path1 = idxRE.sub("", path1)
- path2 = idxRE.sub("", path2)
- if path1 != path2:
- return False
-
- return True
-
-
-def get_unused_port():
- """
- Returns an unused port on localhost.
- """
- s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
- s.bind(('localhost', 0))
- addr, port = s.getsockname() # pylint: disable=W0612
- s.close()
- return port
diff --git a/keystone/token/__init__.py b/keystone/token/__init__.py
new file mode 100644
index 00000000..bf971a5a
--- /dev/null
+++ b/keystone/token/__init__.py
@@ -0,0 +1 @@
+from keystone.token.core import *
diff --git a/keystone/contrib/extensions/service/raxgrp/__init__.py b/keystone/token/backends/__init__.py
index e69de29b..e69de29b 100644
--- a/keystone/contrib/extensions/service/raxgrp/__init__.py
+++ b/keystone/token/backends/__init__.py
diff --git a/keystone/token/backends/kvs.py b/keystone/token/backends/kvs.py
new file mode 100644
index 00000000..990e107b
--- /dev/null
+++ b/keystone/token/backends/kvs.py
@@ -0,0 +1,32 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import copy
+import datetime
+
+from keystone.common import kvs
+from keystone import exception
+from keystone import token
+
+
+class Token(kvs.Base, token.Driver):
+ # Public interface
+ def get_token(self, token_id):
+ token = self.db.get('token-%s' % token_id)
+ if (token and (token['expires'] is None
+ or token['expires'] > datetime.datetime.now())):
+ return token
+ else:
+ raise exception.TokenNotFound(token_id=token_id)
+
+ def create_token(self, token_id, data):
+ data_copy = copy.deepcopy(data)
+ if 'expires' not in data:
+ data_copy['expires'] = self._get_default_expire_time()
+ self.db.set('token-%s' % token_id, data_copy)
+ return copy.deepcopy(data_copy)
+
+ def delete_token(self, token_id):
+ try:
+ return self.db.delete('token-%s' % token_id)
+ except KeyError:
+ raise exception.TokenNotFound(token_id=token_id)
diff --git a/keystone/token/backends/memcache.py b/keystone/token/backends/memcache.py
new file mode 100644
index 00000000..b9c2cbe1
--- /dev/null
+++ b/keystone/token/backends/memcache.py
@@ -0,0 +1,58 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+from __future__ import absolute_import
+import copy
+
+import memcache
+
+from keystone import config
+from keystone import exception
+from keystone import token
+from keystone.common import utils
+
+
+CONF = config.CONF
+config.register_str('servers', group='memcache', default='localhost:11211')
+
+
+class Token(token.Driver):
+ def __init__(self, client=None):
+ self._memcache_client = client
+
+ @property
+ def client(self):
+ return self._memcache_client or self._get_memcache_client()
+
+ def _get_memcache_client(self):
+ memcache_servers = CONF.memcache.servers.split(',')
+ self._memcache_client = memcache.Client(memcache_servers, debug=0)
+ return self._memcache_client
+
+ def _prefix_token_id(self, token_id):
+ return 'token-%s' % token_id.encode('utf-8')
+
+ def get_token(self, token_id):
+ ptk = self._prefix_token_id(token_id)
+ token = self.client.get(ptk)
+ if token is None:
+ raise exception.TokenNotFound(token_id=token_id)
+
+ return token
+
+ def create_token(self, token_id, data):
+ data_copy = copy.deepcopy(data)
+ ptk = self._prefix_token_id(token_id)
+ if 'expires' not in data_copy:
+ data_copy['expires'] = self._get_default_expire_time()
+ kwargs = {}
+ if data_copy['expires'] is not None:
+ expires_ts = utils.unixtime(data_copy['expires'])
+ kwargs['time'] = expires_ts
+ self.client.set(ptk, data_copy, **kwargs)
+ return copy.deepcopy(data_copy)
+
+ def delete_token(self, token_id):
+ # Test for existence
+ self.get_token(token_id)
+ ptk = self._prefix_token_id(token_id)
+ return self.client.delete(ptk)
diff --git a/keystone/token/backends/sql.py b/keystone/token/backends/sql.py
new file mode 100644
index 00000000..b57f32a8
--- /dev/null
+++ b/keystone/token/backends/sql.py
@@ -0,0 +1,69 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+import copy
+import datetime
+
+from keystone.common import sql
+from keystone import exception
+from keystone import token
+
+
+class TokenModel(sql.ModelBase, sql.DictBase):
+ __tablename__ = 'token'
+ id = sql.Column(sql.String(64), primary_key=True)
+ expires = sql.Column(sql.DateTime(), default=None)
+ extra = sql.Column(sql.JsonBlob())
+
+ @classmethod
+ def from_dict(cls, token_dict):
+ # shove any non-indexed properties into extra
+ extra = copy.deepcopy(token_dict)
+ data = {}
+ for k in ('id', 'expires'):
+ data[k] = extra.pop(k, None)
+ data['extra'] = extra
+ return cls(**data)
+
+ def to_dict(self):
+ out = copy.deepcopy(self.extra)
+ out['id'] = self.id
+ out['expires'] = self.expires
+ return out
+
+
+class Token(sql.Base, token.Driver):
+ # Public interface
+ def get_token(self, token_id):
+ session = self.get_session()
+ token_ref = session.query(TokenModel).filter_by(id=token_id).first()
+ now = datetime.datetime.now()
+ if token_ref and (not token_ref.expires or now < token_ref.expires):
+ return token_ref.to_dict()
+ else:
+ raise exception.TokenNotFound(token_id=token_id)
+
+ def create_token(self, token_id, data):
+ data_copy = copy.deepcopy(data)
+ if 'expires' not in data_copy:
+ data_copy['expires'] = self._get_default_expire_time()
+
+ token_ref = TokenModel.from_dict(data_copy)
+ token_ref.id = token_id
+
+ session = self.get_session()
+ with session.begin():
+ session.add(token_ref)
+ session.flush()
+ return token_ref.to_dict()
+
+ def delete_token(self, token_id):
+ session = self.get_session()
+ token_ref = session.query(TokenModel)\
+ .filter_by(id=token_id)\
+ .first()
+ if not token_ref:
+ raise exception.TokenNotFound(token_id=token_id)
+
+ with session.begin():
+ session.delete(token_ref)
+ session.flush()
diff --git a/keystone/token/core.py b/keystone/token/core.py
new file mode 100644
index 00000000..8c816efe
--- /dev/null
+++ b/keystone/token/core.py
@@ -0,0 +1,82 @@
+# vim: tabstop=4 shiftwidth=4 softtabstop=4
+
+"""Main entry point into the Token service."""
+
+import datetime
+
+from keystone import config
+from keystone.common import manager
+
+
+CONF = config.CONF
+config.register_int('expiration', group='token', default=86400)
+
+
+class Manager(manager.Manager):
+ """Default pivot point for the Token backend.
+
+ See :mod:`keystone.common.manager.Manager` for more details on how this
+ dynamically calls the backend.
+
+ """
+
+ def __init__(self):
+ super(Manager, self).__init__(CONF.token.driver)
+
+
+class Driver(object):
+ """Interface description for a Token driver."""
+
+ def get_token(self, token_id):
+ """Get a token by id.
+
+ :param token_id: identity of the token
+ :type token_id: string
+ :returns: token_ref
+ :raises: keystone.exception.TokenNotFound
+
+ """
+ raise NotImplementedError()
+
+ def create_token(self, token_id, data):
+ """Create a token by id and data.
+
+ :param token_id: identity of the token
+ :type token_id: string
+ :param data: dictionary with additional reference information
+
+ ::
+
+ {
+ expires=''
+ id=token_id,
+ user=user_ref,
+ tenant=tenant_ref,
+ metadata=metadata_ref
+ }
+
+ :type data: dict
+ :returns: token_ref or None.
+
+ """
+ raise NotImplementedError()
+
+ def delete_token(self, token_id):
+ """Deletes a token by id.
+
+ :param token_id: identity of the token
+ :type token_id: string
+ :returns: None.
+ :raises: keystone.exception.TokenNotFound
+
+ """
+ raise NotImplementedError()
+
+ def _get_default_expire_time(self):
+ """Determine when a token should expire based on the config.
+
+ :returns: datetime.datetime object
+
+ """
+ expire_delta = datetime.timedelta(seconds=CONF.token.expiration)
+ return datetime.datetime.now() + expire_delta
diff --git a/keystone/tools/__init__.py b/keystone/tools/__init__.py
deleted file mode 100644
index 2baa83b1..00000000
--- a/keystone/tools/__init__.py
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
diff --git a/keystone/tools/buffout.py b/keystone/tools/buffout.py
deleted file mode 100644
index 84f313eb..00000000
--- a/keystone/tools/buffout.py
+++ /dev/null
@@ -1,89 +0,0 @@
-import sys
-import StringIO
-
-
-class OutputBuffer():
- """Replaces stdout with a StringIO buffer"""
-
- def __init__(self):
- """Initialize output buffering"""
- # True if the OutputBuffer is started
- self.buffering = False
-
- # a reference to the current StringIO buffer
- self._buffer = None
-
- # stale if buffering is True; access buffer contents using .read()
- self._contents = None
-
- def __enter__(self):
- self.start()
- return self
-
- def __exit__(self, exc_type, exc_value, traceback):
- if exc_type is None:
- self.stop()
-
- def __unicode__(self):
- return self._contents
-
- def __str__(self):
- return str(self._contents)
-
- def start(self):
- """Replace stdout with a fresh buffer"""
- assert not self.buffering
-
- self.buffering = True
- self.old_stdout = sys.stdout
-
- self.clear()
-
- def read(self):
- """Read the current buffer"""
- if self.buffering:
- self._contents = self._buffer.getvalue()
-
- return self._contents
-
- def read_lines(self):
- """Returns the current buffer as a list
-
- Excludes the last line, which is empty.
-
- """
- return self.read().split("\n")[:-1]
-
- def clear(self):
- """Resets the current buffer"""
- assert self.buffering
-
- # dispose of the previous buffer, if any
- if self._buffer is not None:
- self._buffer.close()
-
- self._contents = ''
- self._buffer = StringIO.StringIO()
- sys.stdout = self._buffer
-
- def flush(self):
- """Flushes and clears the current buffer contents"""
- assert self.buffering
-
- self.old_stdout.write(self._contents)
- self._contents = ''
- self._buffer = StringIO.StringIO()
-
- def stop(self):
- """Stop buffering and pass the output along"""
- assert self.buffering
-
- # preserve the contents prior to closing the StringIO
- self.read()
- self._buffer.close()
-
- sys.stdout = self.old_stdout
- print self.__unicode__()
- self.buffering = False
-
- return unicode(self)
diff --git a/keystone/tools/tracer.py b/keystone/tools/tracer.py
deleted file mode 100644
index 6345e2ae..00000000
--- a/keystone/tools/tracer.py
+++ /dev/null
@@ -1,159 +0,0 @@
-#!/usr/bin/env python
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-
-# Copyright 2010 United States Government as represented by the
-# Administrator of the National Aeronautics and Space Administration.
-# Copyright 2011 OpenStack LLC.
-# All Rights Reserved.
-#
-# 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.
-#
-# Author: Ziad Sawalha (http://launchpad.net/~ziad-sawalha)
-# Original maintained at: https://github.com/ziadsawalha/Python-tracer
-#
-
-"""
-OpenStack Call Tracing Tool
-
-To use this:
-1. include the tools directory in your project (__init__.py and tracer.py)
-2. import tools.tracer as early as possible into your module
-3. add --trace-calls or -t to any argument parsers if you want the argument
-to be shown in the usage page
-
-Usage:
-Add this as early as possible in the first module called in your service::
-
- import tools.tracer # @UnusedImport # module runs on import
-
-If a '-t' or '--trace-calls' parameter is found, it will trace calls to stdout
-and space them to show the call graph. Exceptions (errors) will be displayed in
-red.
-
-"""
-
-import linecache
-import os
-import sys
-
-
-if '--trace-calls' in sys.argv or '-t' in sys.argv:
- # Pop the trace arguments
- for i in range(len(sys.argv)):
- if sys.argv[i] in ['-t', '--trace-calls']:
- sys.argv.pop(i)
-
- STACK_DEPTH = 0
-
- # Calculate root project path
- POSSIBLE_TOPDIR = os.path.normpath(os.path.join(
- os.path.abspath(sys.argv[0]),
- os.pardir,
- os.pardir))
-
- class ConsoleColors():
- HEADER = '\033[95m'
- OKBLUE = '\033[94m'
- OKGREEN = '\033[92m'
- WARNING = '\033[93m'
- FAIL = '\033[91m'
- ENDC = '\033[0m'
-
- def localtrace(frame, event, arg):
- if event == "return":
- global STACK_DEPTH # pylint: disable=W0603
- STACK_DEPTH = STACK_DEPTH - 1
- elif event == "exception":
- output_exception(frame, arg)
- return None
-
- def selectivetrace(frame, event, arg): # pylint: disable=R0911
- global STACK_DEPTH # pylint: disable=W0603
- if event == "exception":
- output_exception(frame, arg)
- if event == 'call':
- co = frame.f_code
- func_name = co.co_name
- if func_name == 'write':
- # Ignore write() calls from print statements
- return
- func_filename = co.co_filename
- if func_filename == "<string>":
- return
- if func_filename.startswith(("/System", "/Library",
- "/usr/lib/py")):
- return
- if 'python' in func_filename:
- return
- if 'macosx' in func_filename:
- return
- output_call(frame, arg)
- global STACK_DEPTH # pylint: disable=W0603
- STACK_DEPTH = STACK_DEPTH + 1
- return localtrace
- return
-
- def output_exception(frame, arg):
- exc_type, exc_value, exc_traceback = arg # pylint: disable=W0612
- if exc_type is StopIteration:
- return
- global STACK_DEPTH # pylint: disable=W0603
- global POSSIBLE_TOPDIR # pylint: disable=W0603
- co = frame.f_code
- local_vars = frame.f_locals
- func_name = co.co_name
- line_no = frame.f_lineno
- func_filename = co.co_filename
- func_filename = func_filename.replace(POSSIBLE_TOPDIR, '')
- sys.stdout.write('%s%sERROR: %s %s in %s of %s:%s%s\n'
- % (ConsoleColors.FAIL, ' ' * STACK_DEPTH,
- exc_type.__name__, exc_value, func_name,
- func_filename, line_no, ConsoleColors.ENDC))
- filename = co.co_filename
- if filename == "<stdin>":
- filename = "%s.py" % __file__
- if (filename.endswith(".pyc") or
- filename.endswith(".pyo")):
- filename = filename[:-1]
- line = linecache.getline(filename, line_no)
- name = frame.f_globals["__name__"]
- sys.stdout.write('%s%s %s:%s: %s%s\n' %
- (ConsoleColors.HEADER, ' ' * STACK_DEPTH, name,
- line_no, line.rstrip(), ConsoleColors.ENDC))
-
- sys.stdout.write('%s locals: %s\n'
- % (' ' * STACK_DEPTH,
- local_vars))
-
- def output_call(frame, arg):
- caller = frame.f_back
-
- if caller:
- global STACK_DEPTH # pylint: disable=W0603
- global POSSIBLE_TOPDIR # pylint: disable=W0603
- co = frame.f_code
- func_name = co.co_name
- func_line_no = frame.f_lineno
- func_filename = co.co_filename
- func_filename = func_filename.replace(POSSIBLE_TOPDIR, '')
- caller_line_no = caller.f_lineno
- caller_filename = caller.f_code.co_filename.replace(
- POSSIBLE_TOPDIR, '')
- if caller_filename == func_filename:
- caller_filename = 'line'
- sys.stdout.write('%s%s::%s:%s (from %s:%s)\n' %
- (' ' * STACK_DEPTH, func_filename, func_name, func_line_no,
- caller_filename, caller_line_no))
-
- sys.stdout.write('Starting OpenStack call tracer\n')
- sys.settrace(selectivetrace)
diff --git a/keystone/utils.py b/keystone/utils.py
deleted file mode 100755
index 7f32d323..00000000
--- a/keystone/utils.py
+++ /dev/null
@@ -1,312 +0,0 @@
-# vim: tabstop=4 shiftwidth=4 softtabstop=4
-# Copyright (c) 2010-2011 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.
-
-# pylint: disable=W1201
-
-import functools
-import json
-import logging
-from lxml import etree
-import os
-import sys
-import tempfile
-from webob import Response
-
-from keystone import config
-import keystone.logic.types.fault as fault
-
-logger = logging.getLogger(__name__) # pylint: disable=C0103
-
-CONF = config.CONF
-
-
-def is_xml_response(req):
- """Returns True when the request wants an XML response, False otherwise"""
- return "Accept" in req.headers and "application/xml" in req.accept
-
-
-def is_json_response(req):
- """Returns True when the request wants a JSON response, False otherwise"""
- return "Accept" in req.headers and "application/json" in req.accept
-
-
-def is_atom_response(req):
- """Returns True when the request wants an ATOM response, False otherwise"""
- return "Accept" in req.headers and "application/atom+xml" in req.accept
-
-
-def get_app_root():
- return os.path.abspath(os.path.dirname(__file__))
-
-
-def get_auth_token(req):
- """Returns the auth token from request headers"""
- return req.headers.get("X-Auth-Token")
-
-
-def get_auth_user(req):
- """Returns the auth user from request headers"""
- return req.headers.get("X-Auth-User")
-
-
-def get_auth_key(req):
- """Returns the auth key from request headers"""
- return req.headers.get("X-Auth-Key")
-
-
-def wrap_error(func):
-
- # pylint: disable=W0703
- @functools.wraps(func)
- def check_error(*args, **kwargs):
- try:
- return func(*args, **kwargs)
- except Exception as err:
- if isinstance(err, fault.IdentityFault):
- return send_error(err.code, kwargs['req'], err)
- elif isinstance(err, fault.ItemNotFoundFault):
- return send_error(err.code, kwargs['req'], err)
- else:
- logging.exception(err)
- return send_error(500, kwargs['req'],
- fault.IdentityFault("Unhandled error",
- str(err)))
- return check_error
-
-
-def get_normalized_request_content(model, req):
- """Initialize a model from json/xml contents of request body"""
-
- if req.content_type == "application/xml":
- return model.from_xml(req.body)
- elif req.content_type == "application/json":
- return model.from_json(req.body)
- else:
- logging.debug("Unsupported content-type passed: %s" % req.content_type)
- raise fault.IdentityFault("I don't understand the content type",
- code=415)
-
-
-# pylint: disable=R0912
-def detect_credential_type(req):
- """Return the credential type name by detecting them in json/xml body"""
-
- if req.content_type == "application/xml":
- dom = etree.Element("root")
- dom.append(etree.fromstring(req.body))
- root = dom.find("{http://docs.openstack.org/identity/api/v2.0}"
- "auth")
- if root is None:
- # Try legacy without wrapper
- creds = dom.find("*")
- if creds:
- logger.warning("Received old syntax credentials not wrapped in"
- "'auth'")
- else:
- creds = root.find("*")
-
- if creds is None:
- raise fault.BadRequestFault("Request is missing credentials")
-
- name = creds.tag
- if "}" in name:
- #trim away namespace if it is there
- name = name[name.rfind("}") + 1:]
-
- return name
- elif req.content_type == "application/json":
- obj = json.loads(req.body)
- if len(obj) == 0:
- raise fault.BadRequestFault("Expecting 'auth'")
- tag = obj.keys()[0]
- if tag == "auth":
- if len(obj[tag]) == 0:
- raise fault.BadRequestFault("Expecting Credentials")
- for key, value in obj[tag].iteritems(): # pylint: disable=W0612
- if key not in ['tenantId', 'tenantName']:
- return key
- raise fault.BadRequestFault("Credentials missing from request")
- else:
- credentials_type = tag
- return credentials_type
- else:
- logging.debug("Unsupported content-type passed: %s" % req.content_type)
- raise fault.IdentityFault("I don't understand the content type",
- code=415)
-
-
-def send_error(code, req, result):
- content = None
-
- resp = Response()
- resp.headers['content-type'] = None
- resp.headers['Vary'] = 'X-Auth-Token'
- resp.status = code
-
- if result:
- if is_xml_response(req):
- content = result.to_xml()
- resp.headers['content-type'] = "application/xml"
- else:
- content = result.to_json()
- resp.headers['content-type'] = "application/json"
-
- resp.content_type_params = {'charset': 'UTF-8'}
- resp.unicode_body = content.decode('UTF-8')
-
- return resp
-
-
-def send_result(code, req, result=None):
- content = None
-
- resp = Response()
- resp.headers['content-type'] = None
- resp.headers['Vary'] = 'X-Auth-Token'
- resp.status = code
- if code > 399:
- return resp
-
- if result:
- if is_xml_response(req):
- content = result.to_xml()
- resp.headers['content-type'] = "application/xml"
- else:
- content = result.to_json()
- resp.headers['content-type'] = "application/json"
- resp.content_type_params = {'charset': 'UTF-8'}
- resp.unicode_body = content.decode('UTF-8')
-
- return resp
-
-
-def send_legacy_result(code, headers):
- resp = Response()
- if 'content-type' not in headers:
- headers['content-type'] = "text/plain"
- resp.headers['Vary'] = 'X-Auth-Token'
-
- headers['Vary'] = 'X-Auth-Token'
-
- resp.headers = headers
- resp.status = code
- if code > 399:
- return resp
-
- resp.content_type_params = {'charset': 'UTF-8'}
-
- return resp
-
-
-def import_module(module_name, class_name=None):
- '''Import a class given a full module.class name or seperate
- module and options. If no class_name is given, it is assumed to
- be the last part of the module_name string.'''
- if class_name is None:
- try:
- if module_name not in sys.modules:
- __import__(module_name)
- return sys.modules[module_name]
- except ImportError as exc:
- logging.exception(exc)
- module_name, _separator, class_name = module_name.rpartition('.')
- if not exc.args[0].startswith('No module named %s' % class_name):
- raise
- try:
- if module_name not in sys.modules:
- __import__(module_name)
- return getattr(sys.modules[module_name], class_name)
- except (ImportError, ValueError, AttributeError), exception:
- logging.exception(exception)
- raise ImportError(_('Class %s.%s cannot be found (%s)') %
- (module_name, class_name, exception))
-
-
-def check_empty_string(value, message):
- """
- Checks whether a string is empty and raises
- fault for empty string.
- """
- if is_empty_string(value):
- raise fault.BadRequestFault(message)
-
-
-def is_empty_string(value):
- """
- Checks whether string is empty.
- """
- if value is None:
- return True
- if not isinstance(value, basestring):
- return False
- if len(value.strip()) == 0:
- return True
- return False
-
-
-def write_temp_file(txt):
- """
- Writes the supplied text to a temporary file and returns the file path.
-
- When the file is no longer needed, it is up to the calling program to
- delete it.
- """
- fd, tmpname = tempfile.mkstemp()
- os.close(fd)
- with file(tmpname, "w") as fconf:
- fconf.write(txt)
- return tmpname
-
-
-def opt_to_conf(options, create_temp=False):
- """
- Takes a dict of options and either returns a string that represents the
- equivalent CONF configuration file (when create_temp is False), or writes
- the temp file and returns the name of that temp file. NOTE: it is up to
- the calling program to delete the temp file when it is no longer needed.
- """
- def parse_opt(options, section=None):
- out = []
- subsections = []
- if section is None:
- section = "DEFAULT"
- # Create the section header
- out.append("[%s]" % section)
- for key, val in options.iteritems():
- if isinstance(val, dict):
- # This is a subsection; parse recursively.
- subsections.append(parse_opt(val, section=key))
- else:
- out.append("%s = %s" % (key.replace("-", "_"), val))
-
- # Add the subsections
- for subsection in subsections:
- out.append("")
- out.append(subsection)
- return "\n".join(out)
-
- txt = parse_opt(options)
- if create_temp:
- return write_temp_file(txt)
- else:
- return txt
-
-
-def set_configuration(options):
- """ Given a dict of options, populates the config.CONF module to match."""
- _config_file = opt_to_conf(options, create_temp=True)
- CONF(config_files=[_config_file])
- os.remove(_config_file)
diff --git a/keystone/version.py b/keystone/version.py
deleted file mode 100644
index 0529b279..00000000
--- a/keystone/version.py
+++ /dev/null
@@ -1,31 +0,0 @@
-# Copyright (C) 2011 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.
-
-API_VERSION = "2.0"
-API_VERSION_STATUS = "beta"
-API_VERSION_DATE = "2011-11-19T00:00:00Z"
-
-RELEASE_VERSION = "2012.1"
-RELEASE_VERSION_FINAL = False # becomes true at Release Candidate time
-
-
-def canonical_version():
- return RELEASE_VERSION
-
-
-def version():
- if RELEASE_VERSION_FINAL:
- return RELEASE_VERSION
- else:
- return '%s-dev' % (RELEASE_VERSION)